From feb5d90ec016c99712f19c5485cf7633cd38f111 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 23 Mar 2007 14:26:04 +0000
Subject: [PATCH] Merge admin framework from config-prototype-branch onto trunk.
---
opends/resource/admin/example-plugin/ExamplePluginConfiguration.xml | 32
opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java | 129
opends/src/server/org/opends/server/admin/AdminException.java | 81
opends/resource/admin/serverMO.xsl | 423
opends/src/server/org/opends/server/admin/IllegalPropertyValueException.java | 84
opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml | 65
opends/resource/admin/example-plugin/ExamplePlugin.java | 148
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java | 6
opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java | 11
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java | 14
opends/src/admin/defn/org/opends/server/admin/std/PlainSASLMechanismHandlerConfiguration.xml | 41
opends/src/admin/defn/org/opends/server/admin/std/GSSAPISASLMechanismHandlerConfiguration.xml | 158
opends/src/server/org/opends/server/admin/SizePropertyDefinition.java | 395
opends/src/server/org/opends/server/admin/DefaultBehaviorProviderVisitor.java | 116
opends/resource/admin/property-types/dn.xsl | 48
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagementContext.java | 101
opends/src/server/org/opends/server/admin/client/ExampleClient.java | 193
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java | 6
opends/src/server/org/opends/server/admin/ClassPropertyDefinition.java | 370
opends/src/server/org/opends/server/admin/DurationPropertyDefinition.java | 579
opends/src/admin/defn/org/opends/server/admin/std/LengthBasedPasswordValidatorConfiguration.xml | 74
opends/resource/admin/property-types/string.xsl | 38
opends/src/server/org/opends/server/admin/IPAddressMaskPropertyDefinition.java | 153
opends/src/server/org/opends/server/admin/client/ManagedObject.java | 475
opends/src/server/org/opends/server/admin/DefinedDefaultBehaviorProvider.java | 93
opends/src/server/org/opends/server/plugins/LastModPlugin.java | 9
opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java | 354
opends/resource/admin/xml.xsd | 146
opends/src/admin/defn/org/opends/server/admin/std/ConnectionHandlerConfiguration.xml | 118
opends/src/server/org/opends/server/admin/ManagedObjectPathSerializer.java | 78
opends/src/server/org/opends/server/admin/InheritedDefaultValueException.java | 97
opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java | 102
opends/src/admin/defn/org/opends/server/admin/std/ExactMatchIdentityMapperConfiguration.xml | 70
opends/src/server/org/opends/server/admin/server/AbstractOptionalConfigurationManager.java | 724
opends/resource/admin/clientMO.xsl | 352
opends/resource/admin/property-types/attribute-type.xsl | 42
opends/src/server/org/opends/server/admin/IllegalPropertyValueStringException.java | 85
opends/src/server/org/opends/server/admin/client/ManagementContext.java | 64
opends/src/server/org/opends/server/admin/server/ConfigurationChangeListener.java | 75
opends/src/server/org/opends/server/admin/server/package-info.java | 39
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/LDAPProfileTest.java | 52
opends/src/server/org/opends/server/admin/OperationsException.java | 89
opends/src/server/org/opends/server/admin/PropertyException.java | 81
opends/src/server/org/opends/server/admin/PropertyIsReadOnlyException.java | 65
opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java | 10
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java | 22
opends/resource/admin/text-utilities.xsl | 187
opends/src/server/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java | 99
opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java | 209
opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java | 3
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/PropertySetTest.java | 497
opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java | 145
opends/src/server/org/opends/server/admin/AdminRuntimeException.java | 82
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AttributeTypePropertyDefinitionTest.java | 149
opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java | 13
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java | 14
opends/src/server/org/opends/server/admin/DecodingException.java | 52
opends/resource/admin/abbreviations.xsl | 52
opends/src/admin/defn/org/opends/server/admin/std/ExternalSASLMechanismHandlerConfiguration.xml | 111
opends/src/server/org/opends/server/api/PasswordValidator.java | 19
opends/src/server/org/opends/server/admin/StringPropertyDefinition.java | 191
opends/src/server/org/opends/server/backends/task/RecurringTask.java | 3
opends/src/server/org/opends/server/core/PasswordValidatorConfigManager.java | 1029
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java | 6
opends/src/server/org/opends/server/admin/ClassLoaderProvider.java | 637
opends/src/server/org/opends/server/admin/PropertyIsMandatoryException.java | 65
opends/src/server/org/opends/server/core/PasswordGeneratorConfigManager.java | 13
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java | 418
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java | 349
opends/resource/admin/example-plugin/README | 48
opends/src/server/org/opends/server/plugins/profiler/ProfilerPlugin.java | 720
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java | 14
opends/src/server/org/opends/server/admin/server/ServerManagementContext.java | 83
opends/src/server/org/opends/server/admin/IPAddressPropertyDefinition.java | 152
opends/src/server/org/opends/server/api/IdentityMapper.java | 17
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java | 30
opends/src/server/org/opends/server/api/KeyManagerProvider.java | 27
opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java | 350
opends/src/server/org/opends/server/core/PasswordPolicyState.java | 3
opends/src/server/org/opends/server/admin/client/ExampleIntrospection.java | 344
opends/src/server/org/opends/server/core/AddOperation.java | 2
opends/src/server/org/opends/server/admin/client/package-info.java | 41
opends/src/server/org/opends/server/admin/AdminClassLoaderProvider.java | 560
opends/resource/admin/example-plugin/package-info.java | 35
opends/resource/admin/preprocessor.xsl | 902 +
opends/src/server/org/opends/server/admin/client/Property.java | 137
opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java | 17
opends/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java | 712
opends/src/server/org/opends/server/admin/ManagedObjectDefinition.java | 105
opends/src/admin/defn/org/opends/server/admin/std/Package.xml | 245
opends/src/server/org/opends/server/core/MonitorConfigManager.java | 12
opends/src/admin/defn/org/opends/server/admin/std/SubjectDNToUserAttributeCertificateMapperConfiguration.xml | 65
opends/src/server/org/opends/server/core/LoggerConfigManager.java | 18
opends/src/server/org/opends/server/admin/ManagedObjectPath.java | 484
opends/src/admin/defn/org/opends/server/admin/std/KeyManagerConfiguration.xml | 55
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/IntegerPropertyDefinitionTest.java | 336
opends/resource/admin/property-types.xsl | 335
opends/src/admin/defn/org/opends/server/admin/std/DigestMD5SASLMechanismHandlerConfiguration.xml | 70
opends/src/server/org/opends/server/core/BackendConfigManager.java | 20
opends/resource/admin/example-plugin/build.xml | 237
opends/resource/admin/java-utilities.xsl | 236
opends/resource/admin/property-types/enumeration.xsl | 86
opends/src/server/org/opends/server/admin/InheritedDefaultValueProvider.java | 71
opends/src/server/org/opends/server/backends/task/TaskScheduler.java | 3
opends/src/admin/defn/org/opends/server/admin/std/PKCS11KeyManagerConfiguration.xml | 34
opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java | 89
opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java | 2
opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java | 4327 ----
opends/src/server/org/opends/server/plugins/LDAPADListPlugin.java | 13
opends/src/server/org/opends/server/admin/AttributeTypePropertyDefinition.java | 193
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/EnumPropertyDefinitionTest.java | 152
opends/src/server/org/opends/server/admin/DNPropertyDefinition.java | 227
opends/src/server/org/opends/server/admin/LDAPProfile.java | 200
opends/src/server/org/opends/server/admin/AbstractPropertyDefinition.java | 357
opends/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandler.java | 487
opends/src/server/org/opends/server/core/PasswordStorageSchemeConfigManager.java | 12
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullKeyManagerProviderTestCase.java | 12
opends/src/server/org/opends/server/admin/PropertyNotFoundException.java | 73
opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java | 16
opends/src/server/org/opends/server/core/SynchronizationProviderConfigManager.java | 9
opends/src/server/org/opends/server/admin/RelationDefinition.java | 181
opends/src/server/org/opends/server/admin/UnknownPropertyDefinitionException.java | 82
opends/src/server/org/opends/server/admin/client/InitialManagedObject.java | 352
opends/src/server/org/opends/server/admin/StringPropertyProvider.java | 88
opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java | 568
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java | 90
opends/resource/admin/property-types/boolean.xsl | 41
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java | 5
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java | 6
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationPropertyDefinitionTest.java | 450
opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java | 492
opends/src/server/org/opends/server/core/EntryCacheConfigManager.java | 3
opends/resource/admin/example-plugin/99-example-plugin.ldif | 38
opends/src/server/org/opends/server/messages/MessageHandler.java | 10
opends/src/admin/defn/org/opends/server/admin/std/PasswordValidatorConfiguration.xml | 55
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/FingerprintCertificateMapperTestCase.java | 14
opends/src/admin/defn/org/opends/server/admin/std/SubjectAttributeToUserAttributeCertificateMapperConfiguration.xml | 72
opends/src/server/org/opends/server/admin/client/ldap/package-info.java | 35
opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java | 413
opends/resource/admin/admin-ldap.xsd | 99
opends/src/admin/defn/org/opends/server/admin/std/ProfilerPluginConfiguration.xml | 130
opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java | 1282 -
opends/src/server/org/opends/server/core/ConnectionHandlerConfigManager.java | 1459 -
opends/src/server/org/opends/server/core/ExtendedOperationConfigManager.java | 12
opends/resource/admin/package-info.xsl | 94
opends/src/server/org/opends/server/admin/AliasDefaultBehaviorProvider.java | 61
opends/src/server/org/opends/server/api/CertificateMapper.java | 18
opends/resource/admin/property-types/ip-address.xsl | 41
opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml | 460
opends/resource/admin/manifestMO.xsl | 52
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapperTestCase.java | 14
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java | 102
opends/src/server/org/opends/server/admin/ManagedObjectAlreadyExistsException.java | 75
opends/resource/admin/example-plugin/Package.xml | 6
opends/resource/admin/metaMO.xsl | 1695 +
opends/src/server/org/opends/server/admin/ManagedObjectNotFoundException.java | 66
opends/src/server/org/opends/server/admin/SizeUnit.java | 277
opends/src/server/org/opends/server/messages/ProtocolMessages.java | 4
opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java | 352
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UpdatePreOpPlugin.java | 6
opends/src/server/org/opends/server/admin/Configuration.java | 70
opends/src/server/org/opends/server/admin/PropertyOption.java | 64
opends/src/server/org/opends/server/extensions/FileBasedKeyManagerProvider.java | 156
opends/src/server/org/opends/server/extensions/SubjectEqualsDNCertificateMapper.java | 23
opends/src/server/org/opends/server/admin/IntegerPropertyDefinition.java | 338
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java | 78
opends/src/server/org/opends/server/core/IdentityMapperConfigManager.java | 1041
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationUnitTest.java | 105
opends/src/server/org/opends/server/admin/server/DNBuilder.java | 170
opends/src/admin/defn/org/opends/server/admin/std/IdentityMapperConfiguration.xml | 55
opends/src/server/org/opends/server/admin/client/PropertySet.java | 791
opends/resource/admin/property-types/oid.xsl | 38
opends/src/server/org/opends/server/admin/PropertyDefinition.java | 252
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AdminTestCase.java | 38
opends/resource/admin/admin-preprocessor.xsd | 111
opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java | 212
opends/src/server/org/opends/server/admin/server/ServerManagedObjectDecodingException.java | 120
opends/src/server/org/opends/server/admin/DefinitionResolver.java | 72
opends/src/server/org/opends/server/admin/AggregationRelationDefinition.java | 190
opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java | 206
opends/src/server/org/opends/server/admin/server/ConfigurationDeleteListener.java | 74
opends/src/server/org/opends/server/core/GroupManager.java | 12
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java | 31
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/BooleanPropertyDefinitionTest.java | 127
opends/src/server/org/opends/server/admin/EnumPropertyDefinition.java | 216
opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java | 25
opends/src/server/org/opends/server/extensions/NullKeyManagerProvider.java | 13
opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java | 10
opends/src/admin/defn/org/opends/server/admin/std/FileBasedKeyManagerConfiguration.xml | 84
opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java | 13
opends/resource/admin/property-types/size.xsl | 58
opends/resource/admin/property-types/java-class.xsl | 52
opends/resource/admin/ldapMOProfile.xsl | 62
opends/build.xml | 264
opends/resource/admin/property-types/duration.xsl | 68
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DNPropertyDefinitionTest.java | 219
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ClassPropertyDefinitionTest.java | 185
opends/src/server/org/opends/server/admin/BooleanPropertyDefinition.java | 177
opends/src/server/org/opends/server/core/AccountStatusNotificationHandlerConfigManager.java | 13
opends/src/server/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java | 59
opends/src/server/org/opends/server/core/SASLConfigManager.java | 1054
opends/src/server/org/opends/server/core/KeyManagerProviderConfigManager.java | 16
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapperTestCase.java | 14
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java | 303
opends/src/server/org/opends/server/core/SchemaConfigManager.java | 6
opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java | 906
opends/src/server/org/opends/server/admin/client/ldap/OperationsExceptionFactory.java | 72
opends/src/server/org/opends/server/admin/client/ManagedObjectDecodingException.java | 119
opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java | 90
opends/src/server/org/opends/server/api/ConnectionHandler.java | 99
opends/src/server/org/opends/server/core/PluginConfigManager.java | 1271
opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java | 572
opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml | 41
opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java | 211
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResourceTest.java | 66
opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java | 107
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AdminTestCaseUtils.java | 86
opends/resource/admin/property-types/password.xsl | 38
opends/src/server/org/opends/server/messages/AdminMessages.java | 292
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java | 48
opends/src/server/org/opends/server/admin/DurationUnit.java | 218
opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java | 687
opends/src/server/org/opends/server/admin/ManagedObjectDefinitionResource.java | 145
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/NullPlugin.java | 6
opends/src/server/org/opends/server/admin/PropertyIsSingleValuedException.java | 66
opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java | 42
opends/src/server/org/opends/server/admin/DefaultBehaviorPropertyValueException.java | 93
opends/resource/admin/admin.xsd | 1490 +
opends/src/admin/defn/org/opends/server/admin/std/SASLMechanismHandlerConfiguration.xml | 55
opends/src/server/org/opends/server/core/AccessControlConfigManager.java | 2
opends/resource/admin/example-plugin/example-plugin.ldif | 10
opends/src/server/org/opends/server/admin/package-info.java | 35
opends/src/server/org/opends/server/core/PasswordPolicy.java | 24
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java | 807
opends/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java | 123
opends/src/admin/defn/org/opends/server/admin/std/CertificateMapperConfiguration.xml | 55
opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml | 309
opends/src/server/org/opends/server/admin/ConfigurationClient.java | 69
opends/src/server/org/opends/server/admin/server/ServerManagedObject.java | 994 +
opends/src/server/org/opends/server/core/CertificateMapperConfigManager.java | 1022
opends/src/admin/defn/org/opends/server/admin/std/FingerprintCertificateMapperConfiguration.xml | 95
opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml | 24
opends/src/server/org/opends/server/admin/DefaultBehaviorProvider.java | 73
opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java | 4
opends/resource/admin/property-types/ip-address-mask.xsl | 41
opends/src/server/org/opends/server/admin/PropertyProvider.java | 89
opends/src/server/org/opends/server/admin/DefinitionDecodingException.java | 125
opends/src/server/org/opends/server/api/SASLMechanismHandler.java | 18
opends/src/server/org/opends/server/core/DirectoryServer.java | 340
opends/resource/admin/property-types/integer.xsl | 58
opends/src/server/org/opends/server/admin/AbstractPropertyDefinitionVisitor.java | 172
opends/src/server/org/opends/server/admin/client/ldap/LDAPNameBuilder.java | 177
opends/src/server/org/opends/server/extensions/PKCS11KeyManagerProvider.java | 118
opends/src/server/org/opends/server/admin/server/ConfigurationAddListener.java | 74
opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java | 87
opends/src/server/org/opends/server/admin/client/ldap/LDAPChangeBuilder.java | 183
opends/src/admin/defn/org/opends/server/admin/std/CramMD5SASLMechanismHandlerConfiguration.xml | 40
257 files changed, 36,950 insertions(+), 15,248 deletions(-)
diff --git a/opends/build.xml b/opends/build.xml
index ce9d877..e5669a3 100644
--- a/opends/build.xml
+++ b/opends/build.xml
@@ -128,6 +128,11 @@
<property file="PRODUCT" />
+ <!-- Properties for administration framework code generation. -->
+ <property name="admin.defn.dir" location="src/admin/defn" />
+ <property name="admin.src.dir" location="src/admin/generated" />
+ <property name="admin.rules.dir" location="resource/admin" />
+
<!-- Create a package bundle containing the DSML library. -->
<target name="dsml" depends="predsml,package"
description="Build a Directory Server package bundle with DSML.">
@@ -167,13 +172,14 @@
<!-- Remove all dynamically-generated build files. -->
- <target name="clean"
+ <target name="clean" depends="cleanadmin"
description="Clean up any files generated during the build process">
<delete dir="${build.dir}" />
- <delete file="${dynconstants.file}" /> <fileset dir="${lib.dir}">
- <include name="*.jar" />
- </fileset>
+ <delete file="${dynconstants.file}" />
+ <fileset dir="${lib.dir}">
+ <include name="*.jar" />
+ </fileset>
</target>
@@ -282,8 +288,10 @@
</taskdef>
<checkcopyrightdates>
- <fileset dir="${basedir}" includes="**/*.java" excludes="build/**/*" />
+ <fileset dir="${basedir}" includes="**/*.java" excludes="build/**/*,src/admin/generated/**/*" />
<fileset dir="${basedir}" includes="**/*.xml" excludes="build/**/*" />
+ <fileset dir="${basedir}" includes="**/*.xsd" excludes="build/**/*" />
+ <fileset dir="${basedir}" includes="**/*.xsl" excludes="build/**/*" />
<fileset dir="${basedir}" includes="**/*.html" excludes="build/**/*" />
<fileset dir="${basedir}" includes="**/*.sh" excludes="build/**/*" />
<fileset dir="${basedir}" includes="**/*.bat" excludes="build/**/* " />
@@ -299,7 +307,6 @@
-
<!-- Check added files to see if any svn:eol-style updates are needed. -->
<target name="eolstyle" depends="buildtools"
description="Ensure added files have the correct svn:eol-style" >
@@ -316,8 +323,10 @@
</taskdef>
<checkeolstyle>
- <fileset dir="${basedir}" includes="**/*.java" excludes="build/**/*" />
+ <fileset dir="${basedir}" includes="**/*.java" excludes="build/**/*,src/admin/generated/**/*" />
<fileset dir="${basedir}" includes="**/*.xml" excludes="build/**/*" />
+ <fileset dir="${basedir}" includes="**/*.xsd" excludes="build/**/*" />
+ <fileset dir="${basedir}" includes="**/*.xsl" excludes="build/**/*" />
<fileset dir="${basedir}" includes="**/*.html" excludes="build/**/*" />
<fileset dir="${basedir}" includes="**/*.sh" excludes="build/**/*" />
<fileset dir="${basedir}" includes="**/*.bat" excludes="build/**/* " />
@@ -392,12 +401,12 @@
<!-- Compile the Directory Server source files. -->
<target name="compile"
- depends="init,dynamicconstants"
+ depends="init,dynamicconstants,compileadmin"
description="Compile the Directory Server source files.">
<mkdir dir="${classes.dir}" />
- <javac srcdir="${src.dir}" destdir="${classes.dir}" optimize="true"
+ <javac srcdir="${src.dir}:${admin.src.dir}" destdir="${classes.dir}" optimize="true"
excludes="**/package-info.java"
debug="on" debuglevel="lines,vars,source" source="1.5" target="1.5"
deprecation="true" fork="true" memoryInitialSize="${MEM}"
@@ -444,16 +453,16 @@
description="Compile the Quick Setup source files.">
<mkdir dir="${quicksetup.classes.dir}" />
- <javac srcdir="${src.dir}" destdir="${quicksetup.classes.dir}"
- optimize="true" debug="on" debuglevel="lines,source" source="1.5"
- target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}"
- memoryMaximumSize="${MEM}">
- <include name="**/org/opends/server/util/SetupUtils.java"/>
- <include name="**/org/opends/server/util/DynamicConstants.java"/>
- <include name="**/org/opends/server/types/OperatingSystem.java"/>
- <compilerarg value="-Xlint:all" />
- </javac>
- <javac srcdir="${quicksetup.src.dir}" destdir="${quicksetup.classes.dir}"
+ <javac srcdir="${src.dir}" destdir="${quicksetup.classes.dir}"
+ optimize="true" debug="on" debuglevel="lines,source" source="1.5"
+ target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}"
+ memoryMaximumSize="${MEM}">
+ <include name="**/org/opends/server/util/SetupUtils.java"/>
+ <include name="**/org/opends/server/util/DynamicConstants.java"/>
+ <include name="**/org/opends/server/types/OperatingSystem.java"/>
+ <compilerarg value="-Xlint:all" />
+ </javac>
+ <javac srcdir="${quicksetup.src.dir}" destdir="${quicksetup.classes.dir}"
optimize="true" debug="on" debuglevel="lines,source" source="1.5"
target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}"
memoryMaximumSize="${MEM}">
@@ -524,9 +533,12 @@
<delete file="${package.dir}/lib/quicksetup.jar" />
<delete file="${package.dir}/lib/statuspanel.jar" />
+ <!-- Regenerate configuration files if necessary -->
+ <antcall target="compileadmin" />
+
<!-- Recreate the classes directory and recompile into it. -->
<mkdir dir="${classes.dir}" />
- <javac srcdir="${src.dir}" destdir="${classes.dir}" optimize="true"
+ <javac srcdir="${src.dir}:${admin.src.dir}" destdir="${classes.dir}" optimize="true"
debug="on" debuglevel="lines,source" source="1.5" target="1.5"
deprecation="true" fork="true" memoryInitialSize="${MEM}"
memoryMaximumSize="${MEM}">
@@ -545,32 +557,32 @@
<!-- Recreate the quicksetup classes directory and recompile into it. -->
<mkdir dir="${quicksetup.classes.dir}" />
- <javac srcdir="${src.dir}" destdir="${quicksetup.classes.dir}"
- optimize="true" debug="on" debuglevel="lines,source" source="1.5"
- target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}"
- memoryMaximumSize="${MEM}">
- <include name="**/org/opends/server/util/SetupUtils.java"/>
- <include name="**/org/opends/server/util/DynamicConstants.java"/>
- <include name="**/org/opends/server/types/OperatingSystem.java"/>
- <compilerarg value="-Xlint:all" />
- </javac>
+ <javac srcdir="${src.dir}" destdir="${quicksetup.classes.dir}"
+ optimize="true" debug="on" debuglevel="lines,source" source="1.5"
+ target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}"
+ memoryMaximumSize="${MEM}">
+ <include name="**/org/opends/server/util/SetupUtils.java"/>
+ <include name="**/org/opends/server/util/DynamicConstants.java"/>
+ <include name="**/org/opends/server/types/OperatingSystem.java"/>
+ <compilerarg value="-Xlint:all" />
+ </javac>
<javac srcdir="${quicksetup.src.dir}" destdir="${quicksetup.classes.dir}" optimize="true"
debug="on" debuglevel="lines,source" source="1.5" target="1.5"
deprecation="true" fork="true" memoryInitialSize="${MEM}"
memoryMaximumSize="${MEM}">
- <compilerarg value="-Xlint:all" />
- <classpath>
- <fileset dir="${build.dir}/build-tools">
- <include name="build-tools.jar" />
- </fileset>
- <fileset dir="${pdir}/lib">
- <include name="OpenDS.jar" />
- </fileset>
- </classpath>
+ <compilerarg value="-Xlint:all" />
+ <classpath>
+ <fileset dir="${build.dir}/build-tools">
+ <include name="build-tools.jar" />
+ </fileset>
+ <fileset dir="${pdir}/lib">
+ <include name="OpenDS.jar" />
+ </fileset>
+ </classpath>
</javac>
<copy todir="${quicksetup.classes.dir}">
- <fileset dir="${quicksetup.src.dir}"
+ <fileset dir="${quicksetup.src.dir}"
includes="**/*.properties, **/*.gif, **/*.png"/>
</copy>
@@ -584,22 +596,25 @@
debug="on" debuglevel="lines,source" source="1.5" target="1.5"
deprecation="true" fork="true" memoryInitialSize="${MEM}"
memoryMaximumSize="${MEM}">
- <compilerarg value="-Xlint:all" />
- <classpath>
- <fileset dir="${pdir}/lib">
- <include name="OpenDS.jar" />
- </fileset>
- </classpath>
+ <compilerarg value="-Xlint:all" />
+ <classpath>
+ <fileset dir="${pdir}/lib">
+ <include name="OpenDS.jar" />
+ </fileset>
+ </classpath>
</javac>
<copy todir="${statuspanel.classes.dir}">
- <fileset dir="${statuspanel.src.dir}"
+ <fileset dir="${statuspanel.src.dir}"
includes="**/*.properties, **/*.gif, **/*.png"/>
</copy>
- <!-- Generate the statuspanel.jar file -->
- <jar jarfile="${pdir}/lib/statuspanel.jar"
+ <!-- Generate the statuspanel.jar file -->
+ <jar jarfile="${pdir}/lib/statuspanel.jar"
basedir="${statuspanel.classes.dir}" compress="true" index="true" />
+
+ <!-- Regenerate example plugin. -->
+ <antcall target="example-plugin" />
</target>
@@ -617,7 +632,7 @@
<mkdir dir="${pdir}" />
<mkdir dir="${pdir}/bak" />
<mkdir dir="${pdir}/bat" />
- <mkdir dir="${pdir}/bin" />
+ <mkdir dir="${pdir}/bin" />
<mkdir dir="${pdir}/classes" />
<mkdir dir="${pdir}/config" />
<mkdir dir="${pdir}/config/upgrade" />
@@ -629,6 +644,7 @@
<mkdir dir="${pdir}/ldif" />
<mkdir dir="${pdir}/legal-notices" />
<mkdir dir="${pdir}/lib" />
+ <mkdir dir="${pdir}/lib/extensions" />
<mkdir dir="${pdir}/locks" />
<mkdir dir="${pdir}/logs" />
@@ -644,18 +660,18 @@
<copy todir="${pdir}/lib">
<fileset file="${lib.dir}/*.jar" />
</copy>
-
- <copy todir="${pdir}/lib">
- <fileset file="${lib.dir}/*.exe" />
- </copy>
- <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bin" excludes="*.bat"
- eol="lf" />
- <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bin" includes="*.bat,README_WINDOWS.txt"
- eol="crlf" />
+ <copy todir="${pdir}/lib">
+ <fileset file="${lib.dir}/*.exe" />
+ </copy>
+
+ <antcall target="example-plugin" />
+
+ <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bin" excludes="*.bat" eol="lf" />
+ <fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bin" includes="*.bat,README_WINDOWS.txt" eol="crlf" />
<fixcrlf srcDir="${scripts.dir}" destDir="${pdir}/bat" includes="*.bat"
eol="crlf" />
-
+
<copy todir="${pdir}/config">
<fileset file="${config.dir}/*" />
</copy>
@@ -808,7 +824,7 @@
<!-- Generate JavaDoc documentation from the source files -->
- <target name="javadoc" depends="dsml"
+ <target name="javadoc" depends="dsml,compileadmin"
description="Generate JavaDoc documentation.">
<mkdir dir="${javadoc.dir}" />
@@ -830,6 +846,7 @@
</classpath>
<packageset dir="${src.dir}" />
+ <packageset dir="${admin.src.dir}" />
<packageset dir="${dsml.src.dir}" />
</javadoc>
</target>
@@ -946,14 +963,14 @@
<antcall target="testinit.checkFailedTestsOnly"/>
</target>
- <!-- If we were asked to run only the tests that failed,
+ <!-- If we were asked to run only the tests that failed,
then we overwrite the testng.xml that we just generated
with testng-failed.xml, which TestNG generated. -->
<target name="testinit.checkFailedTestsOnly" if="test.failures">
<!-- Ensure that some of the tests failed last time. -->
- <available property="testng-failed.xml.exists"
+ <available property="testng-failed.xml.exists"
file="${unittest.report.dir}/testng-failed.xml"/>
- <fail message="No unit tests failed in the previous run."
+ <fail message="No unit tests failed in the previous run."
unless="testng-failed.xml.exists"/>
<!-- We replace the 'Failed suite [OpenDS]' with 'OpenDS' so we
@@ -968,7 +985,7 @@
<copy file="${unittest.report.dir}/testng-failed.xml"
tofile="${unittest.resource.dir}/testng.xml"
overwrite="true"/>
-
+
<echo message="Will run the failed unit tests only"/>
</target>
@@ -1110,7 +1127,7 @@
<antcall target="testhelp"/>
<mkdir dir="${unittest.report.dir}" />
-
+
<taskdef resource="testngtasks">
<classpath>
<fileset dir="${testng.lib.dir}">
@@ -1149,7 +1166,7 @@
<fileset dir="${unittest.report.dir}" includes="*"/>
</delete>
- <!-- Our testng listener will remove this file if all of the
+ <!-- Our testng listener will remove this file if all of the
tests passed. This allows us to generate the coverage
report even if the tests failed and still fail the build. -->
<touch file="${unittest.report.dir}/.tests-failed-marker"/>
@@ -1190,7 +1207,7 @@
<!-- Our testng listener will create this file if any of the
tests failed. This allows us to generate the coverage
report even if the tests failed. -->
- <available property="testng.tests.failed"
+ <available property="testng.tests.failed"
file="${unittest.report.dir}/.tests-failed-marker"/>
<!-- Delete all of the report suite sub-directories since we only
@@ -1200,8 +1217,8 @@
<emma enabled="${coverage.enabled}" >
<report sourcepath="${src.dir}" >
<fileset dir="${coverage.data.dir}" >
- <include name="unit.emma" />
- <include name="metadata.emma" />
+ <include name="unit.emma" />
+ <include name="metadata.emma" />
</fileset>
<txt outfile="${coverage.report.dir}/coverage.txt" />
@@ -1279,13 +1296,13 @@
</target>
- <target name="integration-tests"
+ <target name="integration-tests"
description="Builds the integration tests"
>
- <ant dir="${functest.testng.dir}" inheritall="false"/>
- </target>
+ <ant dir="${functest.testng.dir}" inheritall="false"/>
+ </target>
-
+
<target name="buildtools"
description="Builds the build tools">
@@ -1324,5 +1341,106 @@
<jar jarfile="${build.dir}/build-tools/build-tools.jar"
basedir="${buildtools.classes.dir}" compress="true" index="true" />
</target>
-
+
+ <!-- Code generation for core administration components. -->
+ <target name="compileadmin" depends="validateadmin" description="Code generation for configuration Object.">
+ <!-- Generate introspection API for core administration components. -->
+ <xslt basedir="${admin.defn.dir}" destdir="${admin.src.dir}" includes="**/*Configuration.xml" style="${admin.rules.dir}/metaMO.xsl">
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/meta/\2CfgDefn.java" />
+ <param name="base-dir" expression="${admin.defn.dir}" />
+ </xslt>
+
+ <xslt basedir="${admin.defn.dir}" destdir="${admin.src.dir}" includes="**/Package.xml" style="${admin.rules.dir}/package-info.xsl">
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)\.xml$$" to="\1/meta/package-info.java" />
+ <param name="type" expression="meta" />
+ </xslt>
+
+ <!-- Generate client API for core administration components. -->
+ <xslt basedir="${admin.defn.dir}" destdir="${admin.src.dir}" includes="**/*Configuration.xml" style="${admin.rules.dir}/clientMO.xsl">
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/client/\2CfgClient.java" />
+ <param name="base-dir" expression="${admin.defn.dir}" />
+ </xslt>
+
+ <xslt basedir="${admin.defn.dir}" destdir="${admin.src.dir}" includes="**/Package.xml" style="${admin.rules.dir}/package-info.xsl">
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)\.xml$$" to="\1/client/package-info.java" />
+ <param name="type" expression="client" />
+ </xslt>
+
+ <!-- Generate server API for core administration components. -->
+ <xslt basedir="${admin.defn.dir}" destdir="${admin.src.dir}" includes="**/*Configuration.xml" style="${admin.rules.dir}/serverMO.xsl">
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/server/\2Cfg.java" />
+ <param name="base-dir" expression="${admin.defn.dir}" />
+ </xslt>
+
+ <xslt basedir="${admin.defn.dir}" destdir="${admin.src.dir}" includes="**/Package.xml" style="${admin.rules.dir}/package-info.xsl">
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)\.xml$$" to="\1/server/package-info.java" />
+ <param name="type" expression="server" />
+ </xslt>
+
+ <!-- Generate LDAP profile for core administration components. -->
+ <mkdir dir="${classes.dir}" />
+ <xslt basedir="${admin.defn.dir}" destdir="${classes.dir}/admin/profiles/ldap" includes="**/*Configuration.xml" style="${admin.rules.dir}/ldapMOProfile.xsl">
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/meta/\2CfgDefn.properties" />
+ <param name="base-dir" expression="${admin.defn.dir}" />
+ </xslt>
+
+ <!-- Generate manifest file for core administration components. -->
+ <tempfile property="admin.temp.dir" destDir="${build.dir}" prefix="tmp" />
+ <mkdir dir="${admin.temp.dir}" />
+ <xslt basedir="${admin.defn.dir}" destdir="${admin.temp.dir}" extension=".manifest" includes="**/*Configuration.xml" style="${admin.rules.dir}/manifestMO.xsl"/>
+ <concat destfile="${classes.dir}/admin/core.manifest">
+ <fileset dir="${admin.temp.dir}" includes="**/*.manifest" />
+ </concat>
+ <delete dir="${admin.temp.dir}" />
+ </target>
+
+ <!-- Remove all dynamically-generated build files. -->
+ <target name="cleanadmin" description="Clean up any generated source files for admin">
+ <delete includeemptydirs="true">
+ <fileset dir="${admin.src.dir}" includes="**/*" />
+ </delete>
+ </target>
+
+ <!-- Validate core administration component XML definition files. -->
+ <target name="validateadmin" description="Validate core administration component XML definition files.">
+ <schemavalidate>
+ <fileset dir="${admin.defn.dir}" includes="**/*.xml" />
+ <schema namespace="http://www.opends.org/admin" file="${admin.rules.dir}/admin.xsd"/>
+ <schema namespace="http://www.opends.org/admin-ldap" file="${admin.rules.dir}/admin-ldap.xsd"/>
+ </schemavalidate>
+ </target>
+
+ <!-- Generate example plugin package. -->
+ <target name="example-plugin" if="pdir">
+ <!-- Create folder hierarchy in temporary directory. -->
+ <tempfile property="plugin.temp.dir" destDir="${build.dir}" prefix="tmp"/>
+ <mkdir dir="${plugin.temp.dir}/example-plugin" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/src" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/src-generated" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/lib" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/ext" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/resource" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/resource/admin" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/resource/config" />
+ <mkdir dir="${plugin.temp.dir}/example-plugin/resource/schema" />
+ <copy todir="${plugin.temp.dir}/example-plugin/src">
+ <fileset dir="${admin.defn.dir}" includes="**/*.xml" />
+ </copy>
+ <copy todir="${plugin.temp.dir}/example-plugin/resource/admin">
+ <fileset dir="${admin.rules.dir}" excludes="example-plugin/**" />
+ </copy>
+ <copy todir="${plugin.temp.dir}/example-plugin" file="${admin.rules.dir}/example-plugin/build.xml" />
+ <copy todir="${plugin.temp.dir}/example-plugin" file="${admin.rules.dir}/example-plugin/README" />
+ <copy todir="${plugin.temp.dir}/example-plugin/resource/schema" file="${admin.rules.dir}/example-plugin/99-example-plugin.ldif" />
+ <copy todir="${plugin.temp.dir}/example-plugin/resource/config" file="${admin.rules.dir}/example-plugin/example-plugin.ldif" />
+ <copy todir="${plugin.temp.dir}/example-plugin/src/com/example/opends">
+ <fileset dir="${admin.rules.dir}/example-plugin" includes="*.java,*.xml" excludes="build.xml" />
+ </copy>
+
+ <!-- Package up the plugin in the OpenDS package folder. -->
+ <zip destfile="${pdir}/example-plugin.zip">
+ <zipfileset dir="${plugin.temp.dir}" filemode="644" dirmode="755" />
+ </zip>
+ <delete dir="${plugin.temp.dir}" />
+ </target>
</project>
diff --git a/opends/resource/admin/abbreviations.xsl b/opends/resource/admin/abbreviations.xsl
new file mode 100644
index 0000000..90d72f0
--- /dev/null
+++ b/opends/resource/admin/abbreviations.xsl
@@ -0,0 +1,52 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ This XSLT file contains a list of acronyms and abbreviations which should
+ be converted to upper-case when used in applications (e.g. as Java names).
+ -->
+ <!--
+ Determines whether or not the provided word is a known abbreviation or
+ acronym.
+
+ @param value The word.
+
+ @return Returns the string "true" if the word is an abbreviation.
+ -->
+ <xsl:template name="is-abbreviation">
+ <xsl:param name="value" select="/.." />
+ <xsl:value-of
+ select="$value = 'aci' or $value = 'ip' or $value = 'ssl'
+ or $value = 'dn' or $value = 'rdn' or $value = 'jmx'
+ or $value = 'smtp' or $value = 'http' or $value = 'https'
+ or $value = 'ldap' or $value = 'ldaps' or $value = 'ldif'
+ or $value = 'jdbc' or $value = 'tcp' or $value = 'tls'
+ or $value = 'pkcs11' or $value = 'sasl' or $value = 'gssapi'
+ or $value = 'md5' " />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/admin-ldap.xsd b/opends/resource/admin/admin-ldap.xsd
new file mode 100644
index 0000000..c16bf54
--- /dev/null
+++ b/opends/resource/admin/admin-ldap.xsd
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema targetNamespace="http://www.opends.org/admin-ldap"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ xmlns:tns="http://www.opends.org/admin-ldap">
+ <xsd:annotation>
+ <xsd:documentation>
+ This schema defines the elements and attributes of the "ldap"
+ profile. This profile specifies the relationship between managed
+ objects and their representation in LDAP. For example, each
+ managed object is associated with an LDAP object class and each
+ property is associated with an LDAP attribute. Using this profile
+ it should also be possible to generate the LDAP configuration
+ schema.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleType name="oid-type">
+ <xsd:annotation>
+ <xsd:documentation>A numeric OID.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:token">
+ <xsd:pattern value="([0-9]+(\.[0-9]+)*)|([a-zA-Z][a-zA-Z0-9\-_]*-oid)" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="name-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A LDAP attribute type or object class name.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:token">
+ <xsd:pattern value="[a-zA-Z][a-zA-Z0-9\-_]*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:element name="object-class">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines which LDAP object class a managed object should be
+ mapped to.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="oid" type="tns:oid-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ The numeric OID of the LDAP object class.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="name" type="tns:name-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the LDAP object class.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="superior" type="tns:name-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the parent LDAP object class.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="attribute">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines which LDAP attribute a managed object property should be
+ mapped to.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="oid" type="tns:oid-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ The numeric OID of the LDAP attribute.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="name" type="tns:name-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the LDAP attribute.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="rdn-sequence" type="xsd:token">
+ <xsd:annotation>
+ <xsd:documentation>A sequence of RDNs.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+</xsd:schema>
\ No newline at end of file
diff --git a/opends/resource/admin/admin-preprocessor.xsd b/opends/resource/admin/admin-preprocessor.xsd
new file mode 100644
index 0000000..0714a1e
--- /dev/null
+++ b/opends/resource/admin/admin-preprocessor.xsd
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema targetNamespace="http://www.opends.org/admin-preprocessor"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:admin="http://www.opends.org/admin"
+ elementFormDefault="qualified"
+ xmlns:tns="http://www.opends.org/admin-preprocessor">
+ <xsd:import namespace="http://www.opends.org/admin"
+ schemaLocation="admin.xsd" />
+ <xsd:annotation>
+ <xsd:documentation>
+ This schema defines the elements and attributes which are added to
+ managed object definitions and property definitions in the
+ "preprocessor" profile.
+ </xsd:documentation>
+ <xsd:documentation>
+ Managed object definitions are annotated by listing the parent
+ managed objects which the definition inherits from. This can be
+ used to enforce a simple managed object naming scheme where
+ sub-definitions use the uppermost definition's name as a suffix.
+ For example, "ldap-connection-handler" is derived from
+ "connection-handler", and therefore has the suffix
+ "-connection-handler". Applications can take advantage of this
+ naming schema to shorten sub-definition names where appropriate.
+ For example, a CLI which supports creation of connection handlers,
+ can use remove the suffix from "ldap-connection-handler" in order
+ to derive a "type", in this case "ldap".
+ </xsd:documentation>
+ <xsd:documentation>
+ Each property definition is annotated as follows: firstly a
+ "managed-object" element is added defining the name and package of
+ the managed object which defines the property (i.e. this will be a
+ parent managed object for inherited properties). Secondly, if the
+ property is referenced from a Property.xml file, an additional
+ "package" element is appended identifying the referenced package.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:element name="managed-object">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies the name and package of the managed object definition
+ which defines a property definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="name" type="admin:name-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="package" type="admin:package-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the package containing the managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="package">
+ <xsd:annotation>
+ <xsd:documentation>
+ This optional element specifies, for referenced property
+ definitions (i.e. those defined in a Package.xml file), the name
+ of the package defining the definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="name" type="admin:package-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the package.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="parent-managed-object">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies the name and package of a parent managed object
+ definition. Elements are order such that the immediate parent is
+ the first node in document order and the last element represents
+ the uppermost definition in the inheritance hierarchy.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="name" type="admin:name-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the parent managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="package" type="admin:package-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the package containing the parent managed
+ object.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+</xsd:schema>
\ No newline at end of file
diff --git a/opends/resource/admin/admin.xsd b/opends/resource/admin/admin.xsd
new file mode 100644
index 0000000..aa2bed0
--- /dev/null
+++ b/opends/resource/admin/admin.xsd
@@ -0,0 +1,1490 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema targetNamespace="http://www.opends.org/admin"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ xmlns:tns="http://www.opends.org/admin">
+ <xsd:import namespace="http://www.opends.org/admin-ldap"
+ schemaLocation="admin-ldap.xsd" />
+ <xsd:import namespace="http://www.opends.org/admin-preprocessor"
+ schemaLocation="admin-preprocessor.xsd" />
+ <xsd:annotation>
+ <xsd:documentation>
+ This schema defines the XML schema elements and attributes which
+ should be used to specify the server's configuration model.
+ Broadly speaking, there are three main components to this schema:
+ managed objects, properties, and relations. Using these components
+ it is possible to model the server's configuration based on its
+ configurable components (managed objects), their configurable
+ attributes (properties), and their relationships with other
+ configurable components (relations).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType name="managed-object-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the structure of a configurable component within the
+ configuration. A managed object comprises of zero or more
+ properties, and zero or more relations with other managed
+ objects. A managed object can be abstract, indicating that it
+ cannot be instantiated directly, and that it is intended as a
+ base definition from which other child managed objects inherit
+ their behavior. Conversely, a managed object can be derived from
+ a parent managed object definition. In this case, the managed
+ object will inherit the properties and relations defined by the
+ parent. Multiple levels of inheritance are supported, but
+ multiple inheritance is not.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element name="TODO" minOccurs="0" type="xsd:string"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation specifying remaining work or unsolved problems
+ relating to this managed object definition. Its use is
+ primarily for development purposes and should not be
+ processed by applications.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="synopsis" type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A brief description of this managed object. The description
+ should describe, preferably in one sentence, the purpose of
+ this managed object. The synopsis should be suitable for use
+ in applications such as tool-tips, CLI help, and the summary
+ description in Javadoc. It is possible to embed rich content
+ including XHTML markup (this will only be used where
+ supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="description" minOccurs="0"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A detailed description of this managed object. The
+ description should describe in detail the purpose of this
+ managed object. The description should be suitable for use
+ in applications such as manual pages or detailed help. It
+ does not need to repeat anything described in the synopsis
+ as applications should normally display the two together. It
+ is possible to embed rich content including XHTML markup
+ (this will only be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="profile" type="tns:profile-type" minOccurs="0"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation relating to this managed object. Annotations
+ can define additional information which cannot be directly
+ represented using this XML schema. The additional
+ information can relate to specific applications such as LDAP
+ (e.g. LDAP object classes), CLIs (e.g. sub-command name),
+ GUIs (e.g. how properties should be arranged and grouped in
+ a window).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="relation" maxOccurs="unbounded" minOccurs="0"
+ type="tns:relation-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies a composition relationship between this managed
+ object and other "child" managed objects. The relationship
+ can be a singleton relationship (i.e. one to one), an
+ optional relationship (i.e. one to zero or one), or a one to
+ many relationship.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="property" type="tns:property-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a configurable property of this managed object. A
+ property's value or values affects the behavior of this
+ managed object. Various different types of properties are
+ supported, for example, strings, integers, etc. A property
+ definition must not override a property defined elsewhere
+ in this managed object or property inherited from a parent
+ definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="property-reference"
+ type="tns:property-reference-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A reference to a common property definition defined in a
+ package, which should be part of this managed object's
+ definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="rich-description-type" mixed="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ An internationalized description string which can contain XHTML
+ markup.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:any namespace="http://www.w3.org/1999/xhtml"
+ processContents="lax" />
+ <xsd:element name="product-name">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the product associated with this definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="user-friendly-name">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the managed object associated with this
+ definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="user-friendly-plural-name">
+ <xsd:annotation>
+ <xsd:documentation>
+ The plural name of the managed object associated with this
+ definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ <xsd:complexType name="description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ An internationalized description string which cannot contain
+ XHTML markup.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:token" />
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="property-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a configurable property of a managed object. A
+ property's value or values affects the behavior of the
+ associated managed object. Various different types of properties
+ are supported, for example, strings, integers, etc. A property
+ definition must not override a property defined elsewhere in the
+ managed object or property inherited from a parent managed
+ object.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element name="TODO" minOccurs="0" type="xsd:string"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation specifying remaining work or unsolved problems
+ relating to this property definition. Its use is primarily
+ for development purposes and should not be processed by
+ applications.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="synopsis" type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A brief description of this property. The description should
+ describe, preferably in one sentence, the purpose of this
+ property. It does not need to provide details regarding
+ default behavior, syntax, nor how changes take effect (e.g.
+ immediately, post-restart, etc). The synopsis should be
+ suitable for use in applications such as tool-tips, CLI
+ help, and the summary description in Javadoc. It is possible
+ to embed rich content including XHTML markup (this will only
+ be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="description" minOccurs="0"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A detailed description of this property. The description
+ should describe in detail the purpose of this property. The
+ description should be suitable for use in applications such
+ as manual pages or detailed help. It does not need to repeat
+ anything described in the synopsis as applications should
+ normally display the two together. In addition, it does not
+ need to provide details regarding default behavior, syntax,
+ nor how changes take effect (e.g. immediately, post-restart,
+ etc). It is possible to embed rich content including XHTML
+ markup (this will only be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="requires-admin-action"
+ type="tns:admin-action-type" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines an optional action which administators must perform
+ after they have modified this property. By default
+ modifications to properties are assumed to take effect
+ immediately and require no additional administrative action.
+ Developers should be aware that, where feasible, they should
+ implement components such that property modifications
+ require no additional administrative action. This is
+ required in order to minimize server downtime during
+ administration and provide a more user-friendly experience.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="default-behavior" type="tns:default-type"
+ minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a default behavior for the property when it has no
+ values specified. All properties must have a default
+ behavior defined unless they are mandatory.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="syntax" type="tns:syntax-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the syntax of this property. This includes the data
+ type used for the property and additional constraints (e.g.
+ upper/lower bounds).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="profile" type="tns:profile-type" minOccurs="0"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation relating to this property. Annotations can
+ define additional information which cannot be directly
+ represented using this XML schema. The additional
+ information can relate to specific applications such as LDAP
+ (e.g. LDAP attributes), CLIs (e.g. operand name), GUIs (e.g.
+ how properties should be arranged and grouped in a window).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="tns:name-type" use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of this property. The name should describe as
+ concisely as possible the purpose of this property and should
+ be suitable for use in Java method names (e.g. getters and
+ setters). The property name should be a string comprising of
+ short lower-case words joined with hyphens "-". For example,
+ "use-ssl".
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="multi-valued" type="xsd:boolean" use="optional"
+ default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this property is multi-valued. By
+ default, properties are single-valued.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="read-only" type="xsd:boolean" use="optional"
+ default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this property is read-only. By
+ default, properties are modifiable. Read-only monitoring
+ information is a good use-case for read-only properties.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="mandatory" type="xsd:boolean" use="optional"
+ default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this property is mandatory. Mandatory
+ properties are those properties which have no sensible default
+ behavior and must, therefore, be specified by administrators.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="hidden" type="xsd:boolean" use="optional"
+ default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this property should be hidden from
+ client applications. Hidden properties should rarely be used
+ but are sometimes required in order to provide functionality
+ that needs to be exposed in management APIs but not in
+ front-ends such as CLIs.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ <xsd:complexType name="property-reference-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A reference to a common property definition defined in a
+ package, which should be part of a managed object's definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element name="requires-admin-action"
+ type="tns:admin-action-type" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Optionally override the administrative action defined in the
+ referenced property definition. An administrative action
+ defines an optional action which administators must perform
+ after they have modified this property. By default
+ modifications to properties are assumed to take effect
+ immediately and require no additional administrative action.
+ Developers should be aware that, where feasible, they should
+ implement components such that property modifications
+ require no additional administrative action. This is
+ required in order to minimize server downtime during
+ administration and provide a more user-friendly experience.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="default-behavior" type="tns:default-type"
+ minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Optionally override the default behavior defined in the
+ referenced property definition. The default behavior is
+ applicable when the property has no values specified. All
+ properties must have a default behavior defined unless they
+ are mandatory.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="tns:name-type" use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the referenced property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="package" type="tns:package-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ The package containing the referenced property. By default,
+ the package in which this managed object is defined will be
+ used.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ <xsd:complexType name="relation-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies a relationship between a managed object and other
+ managed objects. The relationship can be a singleton
+ relationship (i.e. one to one), an optional relationship (i.e.
+ one to zero or one), or a one to many relationship. Both
+ compositions (the default) and aggregations are supported.
+ Aggregations are defined by specifying the path to the
+ referenced managed objects in the aggregation attribute.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element name="TODO" minOccurs="0" type="xsd:string"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation specifying remaining work or unsolved problems
+ relating to this relation definition. Its use is primarily
+ for development purposes and should not be processed by
+ applications.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="synopsis" type="tns:rich-description-type"
+ minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ An optional brief description of this relation. The
+ description should describe, preferably in one sentence, the
+ purpose of this relation. If a synopsis is not defined this
+ relation will inherit the synopsis of the referenced managed
+ object. If present, the synopsis should be suitable for use
+ in applications such as tool-tips, CLI help, and the summary
+ description in Javadoc. It is possible to embed rich content
+ including XHTML markup (this will only be used where
+ supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="description" minOccurs="0"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ An optional detailed description of this relation. The
+ description should describe in detail the purpose of this
+ relation. The description should be suitable for use in
+ applications such as manual pages or detailed help. It does
+ not need to repeat anything described in the synopsis as
+ applications should normally display the two together. If a
+ description is not defined this relation will inherit the
+ description of the referenced managed object. It is possible
+ to embed rich content including XHTML markup (this will only
+ be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:choice>
+ <xsd:element name="one-to-one">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies a one to one (singleton) relationship with
+ another type of managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="one-to-zero-or-one">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies a one to zero or one (optional) relationship
+ with another type of managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="one-to-many">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies a one to many (instantiable) relationship with
+ another type of managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="plural-name" type="tns:name-type"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies the plural name of this relation if
+ different from the plural name of the referenced
+ managed object type.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ <xsd:sequence>
+ <xsd:element name="profile" type="tns:profile-type"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation relating to this relation. Annotations can
+ define additional information which cannot be directly
+ represented using this XML schema. The additional
+ information can relate to specific applications such as
+ LDAP (e.g. an LDAP RDN representing the entry beneath
+ which managed objects should be located).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="tns:name-type" use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of this relation. The name should describe as
+ concisely as possible the purpose of this relation and should
+ be suitable for use in Java method names (e.g. getters and
+ setters). The property name should be a string comprising of
+ short lower-case words joined with hyphens "-". For example,
+ "key-manager-provider". Usually the name will correspond to
+ the name of the referenced type of managed object. If it this
+ is not the case, then the type of referenced managed object
+ should be specified using the "managed-object-name" attribute.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="aggregation" type="tns:path-type"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ For aggregation relations, the path locating the relation
+ beneath which the referenced (aggregated) managed objects can
+ be found. If this attribute is not specified, the relation is
+ a composition by default.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="managed-object-name" type="tns:name-type"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ The type of managed object referenced by this relation if
+ different from this relation's name.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="managed-object-package" type="tns:package-type"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ The package containing the referenced managed object
+ definition if it is not the same as this managed object's
+ package.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ <xsd:complexType name="admin-action-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines an optional action which administators must perform
+ after they have modified a property. By default modifications to
+ properties are assumed to take effect immediately and require no
+ additional administrative action. Developers should be aware
+ that, where feasible, they should implement components such that
+ property modifications require no additional administrative
+ action. This is required in order to minimize server downtime
+ during administration and provide a more user-friendly
+ experience.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:choice>
+ <xsd:element name="none">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when no administrator action is required after
+ modifications to a property.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="server-restart">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when modifications to a property require a server
+ restart in order to take effect.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="component-restart">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when modifications to a property require a component
+ restart in order to take effect (usually by disabling and
+ re-enabling the component).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="other">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when modifications to a property require an additional
+ administrative action in order to take effect. This should
+ be used when neither a server restart nor a component
+ restart are applicable.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="synopsis"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A brief description of this required administrative
+ action. The description should describe, preferably in
+ one sentence, what additional administrator action is
+ required when this property is modified. If present,
+ the synopsis should be suitable for use in
+ applications such as tool-tips, CLI help, and the
+ summary description in Javadoc. It is possible to
+ embed rich content including XHTML markup (this will
+ only be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="profile" type="tns:profile-type"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation relating to this administrative action.
+ Annotations can define additional information which
+ cannot be directly represented using this XML schema.
+ The additional information can relate to specific
+ applications.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ <xsd:complexType name="default-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a default behavior for a property when it has no values
+ specified. All properties must have a default behavior defined
+ unless they are mandatory.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:choice>
+ <xsd:element name="undefined">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when a property has no tangible default behavior - its
+ default behavior is undefined.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="alias">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when a property defaults to some special behavior that
+ cannot be represented using property values.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="synopsis"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A brief description of this default behavior. The
+ description should describe, preferably in one
+ sentence, the default behavior. If present, the
+ synopsis should be suitable for use in applications
+ such as tool-tips, CLI help, and the summary
+ description in Javadoc. It is possible to embed rich
+ content including XHTML markup (this will only be used
+ where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="profile" type="tns:profile-type"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation relating to this default behavior.
+ Annotations can define additional information which
+ cannot be directly represented using this XML schema.
+ The additional information can relate to specific
+ applications.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="defined">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when a property defaults to one or more real values of
+ the property.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" minOccurs="1"
+ maxOccurs="unbounded" type="xsd:string">
+ <xsd:annotation>
+ <xsd:documentation>
+ The string representation of a value of this property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="inherited">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when a property defaults one or more values taken from
+ a property in another managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:choice>
+ <xsd:element name="relative">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when the managed object providing the default
+ values is located relative to this managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="offset" use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The relative location of the managed object (where
+ 0 is this managed object, 1 is the parent, and 2
+ is the grand-parent).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="0" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="property-name" type="tns:name-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the property containing the default
+ values.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="absolute">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used when the managed object providing the default
+ values is in a known absolute location.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="path">
+ <xsd:annotation>
+ <xsd:documentation>
+ TODO: not sure what form this will take.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="property-name" type="tns:name-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the property containing the default
+ values.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ <xsd:complexType name="syntax-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the syntax of a property. This includes the data type
+ used for the property and additional constraints on the values
+ it contains (e.g. upper/lower bounds).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:choice>
+ <xsd:element name="attribute-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain LDAP attribute type names.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="boolean">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which are best represented using boolean
+ on/off type values.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="dn">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain LDAP distinguished names.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="base" minOccurs="0" type="xsd:string">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates that values of this property must be
+ immediately subordinate to the specified base DN.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="oid">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain LDAP object identifiers
+ (e.g. attribute names, object classes, controls, etc).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="java-class">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which reference a Java class. These are
+ typically used in plugins where the java class property
+ identifies a class implementing the plugin's functionality.
+ It is possible to restrict the values of this property using
+ the instance-of attribute. Note that it is only possible to
+ validate values on the server, since client applications
+ don't necessarily have the same classes on their class-path.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="instance-of" minOccurs="0"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates that values of this property must implement
+ the specified Java interface. Note that it is only
+ possible to perform validation on the server, since
+ client applications don't necessarily have the same
+ classes on their class-path.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:whiteSpace value="collapse" />
+ <xsd:pattern
+ value="([A-Za-z][A-Za-z0-9_]*\.)*[A-Za-z][A-Za-z0-9_]*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="integer">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain integer values. Where
+ appropriate it is possible to provide a description of the
+ units for values of this property (e.g. "number of
+ threads").
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="unit-synopsis" minOccurs="0"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ An optional description of the units for this value of
+ this property (e.g. "number of threads"). The
+ description should describe the unit, preferably in
+ one sentence. If present, the description should be
+ suitable for use in applications such as tool-tips,
+ CLI help, and the summary description in Javadoc. It
+ is possible to embed rich content including XHTML
+ markup (this will only be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="allow-unlimited" type="xsd:boolean"
+ use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this property supports a
+ special value representing infinity. This is useful
+ where properties are used to constrain some behavior and
+ the administrator wishes to remove the constraint (e.g.
+ number of simultaneous client connections).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="lower-limit" type="xsd:integer"
+ use="optional" default="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates a lower limit for this integer property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="upper-limit" type="xsd:integer"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates an upper limit for this integer property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="ip-address">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain IP addresses. IPv4 and
+ IPv6 address forms are supported. In addition name
+ resolution is performed when non-numeric addresses are
+ specified.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="ip-address-mask">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain IP address masks. IPv4 and
+ IPv6 address mask forms are supported.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="size">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which represent a computer storage size.
+ Sizes can be specified using both decimal and binary units.
+ For example, "1kb" represents 1000 bytes, and "1kib"
+ represents 1024 bytes. Values must always specify the unit
+ and can included a fractionaly part (e.g. 1.5mb). Both short
+ and long unit names are supported (e.g. "kb" and
+ "kilobytes").
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="allow-unlimited" type="xsd:boolean"
+ use="optional" default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this property supports a
+ special value representing infinity. This is useful
+ where properties are used to constrain some behavior and
+ the administrator wishes to remove the constraint (e.g.
+ maximum log size).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="lower-limit" type="xsd:string"
+ use="optional" default="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates a lower limit for this size property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="upper-limit" type="xsd:string"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates an upper limit for this size property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="duration">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain a time duration.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="base-unit" use="optional" default="s">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies the minimum granularity which can be used to
+ specify duration property values. For example, if the
+ base unit is in seconds then values represented in
+ milliseconds will not be permitted. The default base
+ unit is seconds.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="ms" />
+ <xsd:enumeration value="s" />
+ <xsd:enumeration value="m" />
+ <xsd:enumeration value="h" />
+ <xsd:enumeration value="d" />
+ <xsd:enumeration value="w" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="maximum-unit" use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies the biggest duration unit which can be used to
+ specify duration property values. Values presented in
+ units greater than this unit will not be permitted.
+ There is no default maximum unit.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="ms" />
+ <xsd:enumeration value="s" />
+ <xsd:enumeration value="m" />
+ <xsd:enumeration value="h" />
+ <xsd:enumeration value="d" />
+ <xsd:enumeration value="w" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="allow-unlimited" type="xsd:boolean"
+ use="optional" default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this property supports a
+ special value representing infinity. This is useful
+ where properties are used to constrain some behavior and
+ the administrator wishes to remove the constraint (e.g.
+ connection time-out).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="lower-limit" type="xsd:string"
+ use="optional" default="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates a lower limit for this duration property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="upper-limit" type="xsd:string"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates an upper limit for this duration property.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="password">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain passwords. Values will be
+ represented using strings which are then encrypted.
+ Typically password properties are write-only and should
+ never be displayed in client applications (even during
+ creation).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType />
+ </xsd:element>
+ <xsd:element name="enumeration">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain values taken from a finite
+ set of values. There must be at least one possible value
+ defined.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" minOccurs="1"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines one of the possible values that this property
+ can contain.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="synopsis"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A description of this enumeration value. The
+ description should describe the behavior
+ indicated by the value preferably in one
+ sentence. The description should be suitable for
+ use in applications such as tool-tips, CLI help,
+ and the summary description in Javadoc. It is
+ possible to embed rich content including XHTML
+ markup (this will only be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required"
+ type="tns:name-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of this enumeration value. The name
+ should describe as concisely as possible the
+ behavior indicated by this value and should be
+ suitable for use in Java source code (e.g.
+ enumerations). The enumeration value name should
+ be a string comprising of short lower-case words
+ joined with hyphens "-". For example, "optional".
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="string">
+ <xsd:annotation>
+ <xsd:documentation>
+ Used for properties which contain string values. It is
+ possible to contrain the permitted set of values using a
+ regular expression.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="pattern" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Constrains the permitted set of values using a regular
+ expression. All values of this property must match the
+ provided regular expression.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="regex" type="xsd:string">
+ <xsd:annotation>
+ <xsd:documentation>
+ The regular expression conforming to the syntax
+ supported by the Java "java.util.regex.Pattern"
+ class.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="synopsis"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ An description of the regular expression (e.g.
+ "email address"). The description should
+ describe the type of string represented by the
+ regular expression, preferably in one sentence.
+ If present, the description should be suitable
+ for use in applications such as tool-tips, CLI
+ help, and the summary description in Javadoc. It
+ is possible to embed rich content including
+ XHTML markup (this will only be used where
+ supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ <xsd:simpleType name="name-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ An identifier name comprising of a 1 or more sequences of lower
+ case letters or digits separated by a single hyphen '-'. The
+ first sequence must begin with a letter.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:token">
+ <xsd:pattern value="[a-z][a-z0-9]*(-[a-z0-9]+)*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="package-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ An identifier name comprising of a 1 or more sequences of lower
+ case letters or digits separated by a single dot '.'. The first
+ sequence must begin with a letter.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:token">
+ <xsd:pattern value="[a-z][a-z0-9]*(\.[a-z0-9]+)*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="path-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A managed object path which can be used to specify the location
+ of refererenced managed objects. A managed object path has a
+ similar syntax to unix file system paths, and comprises of zero
+ or more path elements separated by a forward slash "/". The root
+ configuration is referenced using the path "/". Subsequent path
+ elements name either a relation or its subordinate named managed
+ object (for one-to-many relations). For example, the path
+ "/connection-handlers/LDAP connection handler" references the
+ LDAP connection handler managed object referenced by the root
+ configuration's connection-handlers relation.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="/([^/]+(/[^/]+)*)?"></xsd:pattern>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:complexType name="profile-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation relating to the associated element. Annotations
+ can define additional information which cannot be directly
+ represented using this XML schema. The additional information
+ can relate to specific applications such as CLIs, GUIs, etc.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:any processContents="strict" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="tns:name-type" use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of this profile e.g. "ldap".
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ <xsd:element name="root-managed-object">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the root managed object and its relationships with
+ top-level managed objects. The root managed object serves as a
+ single point of access to the rest of the configuration. It is
+ essentially a virtual managed object and has no properties of
+ its own, just relationships. There can only be a single root
+ managed object defined per configuration model.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="tns:managed-object-type">
+ <xsd:sequence>
+ <xsd:element name="product-name">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the product associated with this
+ configuration model.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:whiteSpace value="collapse" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="tns:name-type"
+ fixed="root">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of this root managed object, which is always
+ "root".
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="package" type="tns:package-type"
+ fixed="org.opends.server.admin.std">
+ <xsd:annotation>
+ <xsd:documentation>
+ The package containing this root managed object, which
+ is always "org.opends.server.admin.std".
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="managed-object">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the structure of a configurable component within the
+ configuration. A managed object comprises of zero or more
+ properties, and zero or more relations with other managed
+ objects. A managed object can be abstract, indicating that it
+ cannot be instantiated directly, and that it is intended as a
+ base definition from which other child managed objects inherit
+ their behavior. Conversely, a managed object can be derived from
+ a parent managed object definition. In this case, the managed
+ object will inherit the properties and relations defined by the
+ parent. Multiple levels of inheritance are supported, but
+ multiple inheritance is not.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="tns:managed-object-type">
+ <xsd:attribute name="name" type="tns:name-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of this managed object. The name should
+ describe as concisely as possible the role of this
+ managed object and should be suitable for use in Java
+ method names (e.g. class names). The managed object name
+ should be a string comprising of short lower-case words
+ joined with hyphens "-". For example,
+ "ldap-connection-handler". NOTE: a managed object name
+ must end in the name of the definition's uppermost
+ super-type. For example, "ldap-connection-handler" is a
+ sub-type of "connection-handler" and therefore ends in
+ "-connection-handler".
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="plural-name" type="tns:name-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The plural name of this managed object. The plural name
+ should correspond to the singular name defined in the
+ "name" attribute and it should be suitable for use in
+ Java method names (e.g. getters). The managed object
+ plural name should be a string comprising of short
+ lower-case words joined with hyphens "-". For example,
+ "ldap-connection-handlers".
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="package" type="tns:package-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The package containing this managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="abstract" type="xsd:boolean"
+ use="optional" default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this managed object is
+ abstract. Abstract managed objects cannot be
+ instantiated directly and are intended for use as base
+ definitions for inheritance.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="extends" type="tns:name-type"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates whether or not this managed object is inherits
+ from a parent managed object and, if so, the name of the
+ parent. If specified, this managed object will inherit
+ all of the properties and relations defined in the
+ parent managed object.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ <xsd:attribute name="parent-package" type="tns:package-type"
+ use="optional">
+ <xsd:annotation>
+ <xsd:documentation>
+ The package containing the parent managed object. By
+ default, the package in which this managed object is
+ defined will be used.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="package">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a common information associated with all managed objects
+ defined in the containing package. A package definition
+ comprises of a description of the package together with common
+ property definitions which can be referenced from within managed
+ objects using "property-reference" elements. Sharing property
+ definitions in this way makes maintenance easier in situations
+ where the property definition needs modifying, since all
+ referencing managed objects will automatically inherit the
+ changes.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="TODO" minOccurs="0" type="xsd:string"
+ maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ An annotation specifying remaining work or unsolved
+ problems relating to this package definition. Its use is
+ primarily for development purposes and should not be
+ processed by applications.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="synopsis" type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A brief description of this package. The description
+ should describe, preferably in one sentence, the purpose
+ of this package, for example, the type of managed objects
+ it defines. The synopsis should be suitable for use in
+ applications such as tool-tips, CLI help, and the summary
+ description in Javadoc. It is possible to embed rich
+ content including XHTML markup (this will only be used
+ where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="description" minOccurs="0"
+ type="tns:rich-description-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ A detailed description of this package. The description
+ should describe in detail the purpose of this package. The
+ description should be suitable for use in applications
+ such as manual pages or detailed help. It does not need to
+ repeat anything described in the synopsis as applications
+ should normally display the two together. It is possible
+ to embed rich content including XHTML markup (this will
+ only be used where supported).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="property" minOccurs="0" maxOccurs="unbounded"
+ type="tns:property-type">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a common configurable property for this package.
+ Managed objects can inherit this property definition by
+ referencing it using a "property-reference" element.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="tns:package-type"
+ use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+ The package containing this package definition.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+ </xsd:complexType>
+ </xsd:element>
+</xsd:schema>
\ No newline at end of file
diff --git a/opends/resource/admin/clientMO.xsl b/opends/resource/admin/clientMO.xsl
new file mode 100644
index 0000000..bfaf653
--- /dev/null
+++ b/opends/resource/admin/clientMO.xsl
@@ -0,0 +1,352 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:admpp="http://www.opends.org/admin-preprocessor"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:import href="java-utilities.xsl" />
+ <xsl:import href="preprocessor.xsl" />
+ <xsl:import href="property-types.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Template for generating the interface declaration.
+ -->
+ <xsl:template name="generate-interface-declaration">
+ <xsl:value-of select="'/**
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content"
+ select="concat('A client-side interface for reading and modifying ',
+ $this-ufn, ' settings.')" />
+ </xsl:call-template>
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="$this/adm:synopsis" />
+ </xsl:call-template>
+ <xsl:value-of select="' */
'" />
+ <xsl:value-of
+ select="concat('public interface ',
+ $this-java-class,
+ 'CfgClient extends ')" />
+ <xsl:choose>
+ <xsl:when test="boolean($this/@extends)">
+ <xsl:value-of select="concat($parent-java-class,'CfgClient ')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'ConfigurationClient '" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>{
</xsl:text>
+ </xsl:template>
+ <!--
+ Template for generating the configuration definition getter.
+ -->
+ <xsl:template name="generate-configuration-definition-getter">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Get the configuration definition associated with this ', $this-ufn, '.
',
+ ' *
',
+ ' * @return Returns the configuration definition associated with this ', $this-ufn, '.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ManagedObjectDefinition<? extends ', $this-java-class,'CfgClient, ? extends ', $this-java-class,'Cfg> definition();
')" />
+ </xsl:template>
+ <!--
+ Template for generating the relation getter declarations.
+ -->
+ <xsl:template name="generate-relation-declarations">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="ufn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-relation-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-class-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="adm:one-to-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Gets the ', $ufn,'.
',
+ ' *
',
+ ' * @return Returns the ', $ufn,'.
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufn,' could not be read due to some
',
+ ' * underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ', $java-class-name, 'CfgClient get',
+ $java-relation-name, '() throws OperationsException;
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-zero-or-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Determines whether or not the ', $ufn,' exists.
',
+ ' *
',
+ ' * @return Returns <true> if the ', $ufn,' exists.
',
+ ' * @throws OperationsException
',
+ ' * If the determination could not be made
',
+ ' * due to some underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' boolean has',
+ $java-relation-name, '() throws OperationsException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Gets the ', $ufn,' if it is present.
',
+ ' *
',
+ ' * @return Returns the ', $ufn,' if it is present.
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufn,' does not exist or could not be read
',
+ ' * due to some underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ', $java-class-name, 'CfgClient get',
+ $java-relation-name, '() throws OperationsException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Creates the ', $ufn,' if it does not exist yet.
',
+ ' *
',
+ ' * @param <C>
',
+ ' * The type of the ', $ufn,' being added.
',
+ ' * @param d
',
+ ' * The definition of the ', $ufn,' to be created.
',
+ ' * @param p
',
+ ' * A property provider which can be used to initialize
',
+ ' * the property values of the new ', $ufn,'.
',
+ ' * @return Returns the ', $ufn,' instance representing the
',
+ ' * ', $ufn,' that was created.
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufn,' already exists or could not be created
',
+ ' * due to some underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' <C extends ', $java-class-name,'CfgClient> C create', $java-relation-name, '(
',
+ ' ManagedObjectDefinition<C, ?> d, PropertyProvider p) throws OperationsException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Removes the ', $ufn,' if it exists.
',
+ ' *
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufn,' does not exist or could not be removed
',
+ ' * due to some underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void remove',
+ $java-relation-name, '() throws OperationsException;
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-many">
+ <xsl:variable name="plural-name"
+ select="adm:one-to-many/@plural-name" />
+ <xsl:variable name="ufpn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$plural-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-relation-plural-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$plural-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Lists the ', $ufpn,'.
',
+ ' *
',
+ ' * @return Returns an array containing the names of the
',
+ ' * ', $ufpn,'.
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufpn,' could not be listed due to some
',
+ ' * underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' String[] list',
+ $java-relation-plural-name, '() throws OperationsException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Gets the named ', $ufn,'.
',
+ ' *
',
+ ' * @param name
',
+ ' * The name of the ', $ufn,' to retrieve.
',
+ ' * @return Returns the named ', $ufn,'.
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufn,' does not exist or could not be read
',
+ ' * due to some underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ', $java-class-name, 'CfgClient get',
+ $java-relation-name, '(String name) throws OperationsException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Creates a new ', $ufn,'.
',
+ ' *
',
+ ' * @param <C>
',
+ ' * The type of the ', $ufn,' being added.
',
+ ' * @param d
',
+ ' * The definition of the ', $ufn,' to be created.
',
+ ' * @param name
',
+ ' * The name of the new ', $ufn,'.
',
+ ' * @param p
',
+ ' * A property provider which can be used to initialize
',
+ ' * the property values of the new ', $ufn,'.
',
+ ' * @return Returns a new ', $ufn,' instance representing the
',
+ ' * ', $ufn,' that was created.
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufn,' already exists or could not be created
',
+ ' * due to some underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' <C extends ', $java-class-name,'CfgClient> C create', $java-relation-name, '(
',
+ ' ManagedObjectDefinition<C, ?> d, String name, PropertyProvider p) throws OperationsException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Removes the named ', $ufn,'.
',
+ ' *
',
+ ' * @param name
',
+ ' * The name of the ', $ufn,' to remove.
',
+ ' * @throws OperationsException
',
+ ' * If the ', $ufn,' does not exist or could not be removed
',
+ ' * due to some underlying communication problem.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void remove',
+ $java-relation-name, '(String name) throws OperationsException;
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unknown relation type "', local-name(*), '" in relation "', $name, '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Main document parsing template.
+ -->
+ <xsl:template match="/">
+ <xsl:call-template name="copyright-notice" />
+ <xsl:value-of
+ select="concat('package ', $this-package, '.client;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-import-statements">
+ <xsl:with-param name="imports">
+ <xsl:for-each select="$this-local-properties">
+ <xsl:call-template name="get-property-java-imports" />
+ </xsl:for-each>
+ <xsl:if test="$this-local-properties[@multi-valued='true']">
+ <import>java.util.Collection</import>
+ <import>java.util.SortedSet</import>
+ </xsl:if>
+ <xsl:if test="$this-local-properties[not(@read-only='true')]">
+ <import>
+ org.opends.server.admin.IllegalPropertyValueException
+ </import>
+ </xsl:if>
+ <xsl:if test="$this-local-relations">
+ <import>org.opends.server.admin.OperationsException</import>
+ </xsl:if>
+ <xsl:if
+ test="$this-local-relations/adm:one-to-zero-or-one|$this-local-relations/adm:one-to-many">
+ <import>org.opends.server.admin.PropertyProvider</import>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="$this/@extends">
+ <xsl:if test="$parent-package != $this-package">
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($parent-package, '.client.', $parent-java-class, 'CfgClient')" />
+ </xsl:element>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <import>org.opends.server.admin.ConfigurationClient</import>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($this-package, '.server.', $this-java-class, 'Cfg')" />
+ </xsl:element>
+ <import>org.opends.server.admin.ManagedObjectDefinition</import>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-interface-declaration" />
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-configuration-definition-getter" />
+ <xsl:for-each select="$this-local-properties">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-getter-declaration">
+ <xsl:with-param name="interface" select="'client'" />
+ </xsl:call-template>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-setter-declaration" />
+ </xsl:for-each>
+ <xsl:for-each select="$this-local-relations">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-relation-declarations" />
+ </xsl:for-each>
+ <xsl:text>
</xsl:text>
+ <xsl:text>}
</xsl:text>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/example-plugin/99-example-plugin.ldif b/opends/resource/admin/example-plugin/99-example-plugin.ldif
new file mode 100644
index 0000000..4a70e97
--- /dev/null
+++ b/opends/resource/admin/example-plugin/99-example-plugin.ldif
@@ -0,0 +1,38 @@
+# 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.
+#
+#
+# This file contains the attribute type and objectclass definitions for use
+# with the Directory Server configuration.
+dn: cn=schema
+objectClass: top
+objectClass: ldapSubentry
+objectClass: subschema
+attributeTypes: ( ds-cfg-example-plugin-message-oid NAME 'ds-cfg-example-plugin-message'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
+ X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( ds-cfg-example-plugin-oid NAME 'ds-cfg-example-plugin'
+ SUP ds-cfg-plugin STRUCTURAL MAY ( ds-cfg-example-plugin-message )
+ X-ORIGIN 'OpenDS Directory Server' )
diff --git a/opends/resource/admin/example-plugin/ExamplePlugin.java b/opends/resource/admin/example-plugin/ExamplePlugin.java
new file mode 100644
index 0000000..adf80cc
--- /dev/null
+++ b/opends/resource/admin/example-plugin/ExamplePlugin.java
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+package com.example.opends;
+
+
+
+import static org.opends.server.loggers.Error.logError;
+
+import java.util.List;
+import java.util.Set;
+
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.api.plugin.DirectoryServerPlugin;
+import org.opends.server.api.plugin.PluginType;
+import org.opends.server.api.plugin.StartupPluginResult;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.ResultCode;
+
+import com.example.opends.server.ExamplePluginCfg;
+
+
+
+/**
+ * The example plugin implementation class. This plugin will output
+ * the configured message to the error log during server start up.
+ */
+public class ExamplePlugin extends
+ DirectoryServerPlugin<ExamplePluginCfg> implements
+ ConfigurationChangeListener<ExamplePluginCfg> {
+
+ // The current configuration.
+ private ExamplePluginCfg config;
+
+
+
+ /**
+ * Default constructor.
+ */
+ public ExamplePlugin() {
+ super();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public void initializePlugin(Set<PluginType> pluginTypes,
+ ExamplePluginCfg configuration)
+ throws ConfigException {
+ // This plugin may only be used as a server startup plugin.
+ for (PluginType t : pluginTypes) {
+ switch (t) {
+ case STARTUP:
+ // This is fine.
+ break;
+ default:
+ throw new ConfigException(-1, "Invalid plugin type " + t
+ + " for the example plugin.");
+ }
+ }
+
+ // Register change listeners. These are not really necessary for
+ // this plugin since it is only used during server start-up.
+ configuration.addExampleChangeListener(this);
+
+ // Save the configuration.
+ this.config = configuration;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public StartupPluginResult doStartup() {
+ // Log the provided message.
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.NOTICE,
+ "Example plugin message '" + config.getMessage() + "'.", 9999);
+ return StartupPluginResult.SUCCESS;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ ExamplePluginCfg config) {
+ // The new configuration has already been validated.
+
+ // Log a message to say that the configuration has changed. This
+ // isn't necessary, but we'll do it just to show that the change
+ // has taken effect.
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.NOTICE,
+ "Example plugin message has been changed from '"
+ + this.config.getMessage() + "' to '"
+ + config.getMessage() + "'.", 9999);
+
+ // Update the configuration.
+ this.config = config;
+
+ // Update was successfull, no restart required.
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ ExamplePluginCfg config, List<String> messages) {
+ // The only thing that can be validated here is the plugin's
+ // message. However, it is always going to be valid, so let's
+ // always return true.
+ return true;
+ }
+}
diff --git a/opends/resource/admin/example-plugin/ExamplePluginConfiguration.xml b/opends/resource/admin/example-plugin/ExamplePluginConfiguration.xml
new file mode 100644
index 0000000..79db512
--- /dev/null
+++ b/opends/resource/admin/example-plugin/ExamplePluginConfiguration.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="example-plugin" plural-name="example-plugins"
+ package="com.example.opends" extends="plugin"
+ parent-package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>An example "Hello World" plugin.</adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>ds-cfg-example-plugin-oid</ldap:oid>
+ <ldap:name>ds-cfg-example-plugin</ldap:name>
+ <ldap:superior>ds-cfg-plugin</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="message">
+ <adm:synopsis>The message to be logged.</adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>Hello World</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>ds-cfg-example-plugin-message-oid</ldap:oid>
+ <ldap:name>ds-cfg-example-plugin-message</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opends/resource/admin/example-plugin/Package.xml b/opends/resource/admin/example-plugin/Package.xml
new file mode 100644
index 0000000..2fdb8df
--- /dev/null
+++ b/opends/resource/admin/example-plugin/Package.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:package name="com.example.opends"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>Example OpenDS Hello World plugin.</adm:synopsis>
+</adm:package>
diff --git a/opends/resource/admin/example-plugin/README b/opends/resource/admin/example-plugin/README
new file mode 100644
index 0000000..8e7b7bc
--- /dev/null
+++ b/opends/resource/admin/example-plugin/README
@@ -0,0 +1,48 @@
+This folder contains source code for an example "Hello World" style
+plugin. It features a plugin which has a configurable message (the
+default being "Hello World") which is displayed as a notice message
+when an OpenDS instance is started.
+
+In order to build and use this example plugin, perform the following
+steps (presumably you are already at step 4):
+
+ 1. In the top-level source folder for OpenDS, first build and
+ package OpenDS:
+
+ ./build.sh
+
+ 2. Next go into the packages folder:
+
+ cd build/package/OpenDS-0.1
+
+ 3. Then unzip the example-plugin.zip (in place):
+
+ unzip example-plugin.zip
+
+ 4. Go into the example-plugin source folder:
+
+ cd example-plugin
+
+ 5. And build the plugin (this requires Ant in your path):
+
+ ant install
+
+ 6. This will copy the following files into the parent OpenDS
+ installation:
+
+ lib/extensions/example-plugin.jar
+ config/example-plugin.ldif
+ config/schema/99-example-plugin.ldif
+
+ 7. Add the plugin's config to the server configuration. The
+ following instruction assumes usage of the Unix 'cat'
+ command, but obviously ldapadd can be used:
+
+ cd ../config
+ cat example-plugin.ldif >> config.ldif
+
+ 8. Start the server and look for the "hello world" notice in the start
+ up log:
+
+ cd ..
+ ./bin/start-ds
diff --git a/opends/resource/admin/example-plugin/build.xml b/opends/resource/admin/example-plugin/build.xml
new file mode 100644
index 0000000..9a67112
--- /dev/null
+++ b/opends/resource/admin/example-plugin/build.xml
@@ -0,0 +1,237 @@
+<!--
+ ! 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.
+ ! -->
+
+<project name="Directory Server Extension" basedir="." default="package">
+ <description>
+ This is the build script for an OpenDS Directory Server extension.
+ </description>
+
+ <!-- CONFIGURE: The name of the extension's Jar file. -->
+ <property name="pkg.name" value="example-plugin" />
+
+ <!-- CONFIGURE: The description of this extension - used in the Javadoc title. -->
+ <property name="pkg.description" value="Example Plugin" />
+
+ <!-- CONFIGURE: The path of the OpenDS installation. -->
+ <property name="opends.install.dir" location=".." />
+
+ <!-- General properties - should not need changing. -->
+ <property name="build.dir" location="build" />
+ <property name="src.dir" location="src" />
+ <property name="src.gen.dir" location="src-generated" />
+ <property name="lib.dir" location="lib" />
+ <property name="ext.dir" location="ext" />
+ <property name="resource.dir" location="resource" />
+ <property name="admin.dir" location="${resource.dir}/admin" />
+ <property name="config.dir" location="${resource.dir}/config" />
+ <property name="schema.dir" location="${resource.dir}/schema" />
+ <property name="classes.dir" location="${build.dir}/classes" />
+ <property name="javadoc.dir" location="${build.dir}/javadoc" />
+ <property name="package.dir" location="${build.dir}/package" />
+ <property name="jar.file" value="${pkg.name}.jar" />
+
+ <!-- Location of OpenDS components - should not need changing. -->
+ <property name="opends.lib.dir" location="${opends.install.dir}/lib" />
+ <property name="opends.config.dir" location="${opends.install.dir}/config" />
+ <property name="opends.schema.dir" location="${opends.config.dir}/schema" />
+ <property name="opends.extensions.dir" location="${opends.lib.dir}/extensions" />
+
+ <!-- Display help information. -->
+ <target name="help">
+ <echo message="Ant options to control the build:" />
+ <echo message="" />
+ <echo message=" -Dopends.install.dir=path" />
+ <echo message=" The path of the OpenDS installation [default: ${opends.install.dir}]." />
+ <echo message="" />
+ <echo message=" -Dpkg.name=name" />
+ <echo message=" The name of the extension's Jar file [default: ${pkg.name}]." />
+ <echo message="" />
+ <echo message=" -Dpkg.description=description" />
+ <echo message=" The description of this extension - used in the Javadoc title [default: ${pkg.description}]." />
+ <echo message="" />
+ </target>
+
+ <!-- Clean up any files generated during the build process. -->
+ <target name="clean" description="Clean up any files generated during the build process.">
+ <delete dir="${build.dir}" />
+ <delete includeemptydirs="true">
+ <fileset dir="${src.gen.dir}" includes="**/*" />
+ </delete>
+ </target>
+
+ <!-- Compile the Directory Server extension source files. -->
+ <target name="compile" depends="init,compileadmin" description="Compile the Directory Server extension source files.">
+ <mkdir dir="${classes.dir}" />
+ <javac srcdir="${src.dir}:${src.gen.dir}" destdir="${classes.dir}" optimize="true" excludes="**/package-info.java" debug="on" debuglevel="lines,source" source="1.5" target="1.5" deprecation="true" fork="true" memoryInitialSize="${MEM}" memoryMaximumSize="${MEM}">
+ <compilerarg value="-Xlint:all" />
+ <classpath>
+ <fileset dir="${lib.dir}">
+ <include name="*.jar" />
+ </fileset>
+ <fileset dir="${opends.lib.dir}">
+ <include name="*.jar" />
+ </fileset>
+ </classpath>
+ </javac>
+ </target>
+
+ <!-- Generate JavaDoc documentation from the source files. -->
+ <target name="javadoc" depends="init,compile" description="Generate JavaDoc documentation.">
+ <mkdir dir="${javadoc.dir}" />
+ <javadoc destdir="${javadoc.dir}" source="1.5" additionalparam="-quiet" linksource="yes" windowtitle="${pkg.description} API Documentation" maxmemory="${MEM}">
+ <classpath>
+ <fileset dir="${lib.dir}">
+ <include name="*.jar" />
+ </fileset>
+ <fileset dir="${opends.lib.dir}">
+ <include name="*.jar" />
+ </fileset>
+ <dirset dir="${classes.dir}" />
+ </classpath>
+ <packageset dir="${src.dir}" />
+ <packageset dir="${src.gen.dir}" />
+ </javadoc>
+ </target>
+
+ <!-- Package the Directory Server extension for distribution. -->
+ <target name="package" depends="clean,compile" description="Package the Directory Server extension for distribution.">
+ <mkdir dir="${package.dir}" />
+ <jar jarfile="${package.dir}/${jar.file}" basedir="${classes.dir}" compress="true" index="true" />
+ </target>
+
+ <!-- Install the Directory Server extension in an existing OpenDS installation. -->
+ <target name="install" depends="package" description="Install the Directory Server extension in an existing OpenDS installation.">
+ <mkdir dir="${opends.lib.dir}" />
+ <copy todir="${opends.lib.dir}">
+ <fileset file="${lib.dir}/*.jar" />
+ </copy>
+ <mkdir dir="${opends.extensions.dir}" />
+ <copy todir="${opends.extensions.dir}">
+ <fileset file="${package.dir}/*.jar" />
+ </copy>
+ <copy todir="${opends.config.dir}">
+ <fileset file="${config.dir}/*.ldif" />
+ </copy>
+ <copy todir="${opends.schema.dir}">
+ <fileset file="${schema.dir}/*.ldif" />
+ </copy>
+ </target>
+
+ <!-- Perform common initialization common to several targets. -->
+ <target name="init">
+ <tstamp>
+ <format property="timestamp" pattern="yyyyMMddHHmmss" />
+ </tstamp>
+ <condition property="DEBUG_BUILD" value="false">
+ <not>
+ <isset property="DEBUG_BUILD" />
+ </not>
+ </condition>
+ <condition property="MEM" value="128M">
+ <not>
+ <isset property="MEM" />
+ </not>
+ </condition>
+ </target>
+
+ <!-- Compile the Directory Server extension configuration definition files. -->
+ <target name="compileadmin" depends="validateadmin" description="Compile the Directory Server extension configuration definition files.">
+ <!-- Compile the Directory Server extension configuration meta classes. -->
+ <xslt basedir="${src.dir}" destdir="${src.gen.dir}" style="${admin.dir}/metaMO.xsl">
+ <include name="**/*Configuration.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/meta/\2CfgDefn.java" />
+ <param name="base-dir" expression="${src.dir}" />
+ </xslt>
+
+ <xslt basedir="${src.dir}" destdir="${src.gen.dir}" style="${admin.dir}/package-info.xsl">
+ <include name="**/Package.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)\.xml$$" to="\1/meta/package-info.java" />
+ <param name="type" expression="meta" />
+ </xslt>
+
+ <!-- Compile the Directory Server extension configuration client classes. -->
+ <xslt basedir="${src.dir}" destdir="${src.gen.dir}" style="${admin.dir}/clientMO.xsl">
+ <include name="**/*Configuration.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/client/\2CfgClient.java" />
+ <param name="base-dir" expression="${src.dir}" />
+ </xslt>
+
+ <xslt basedir="${src.dir}" destdir="${src.gen.dir}" style="${admin.dir}/package-info.xsl">
+ <include name="**/Package.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)\.xml$$" to="\1/client/package-info.java" />
+ <param name="type" expression="client" />
+ </xslt>
+
+ <!-- Compile the Directory Server extension configuration server classes. -->
+ <xslt basedir="${src.dir}" destdir="${src.gen.dir}" style="${admin.dir}/serverMO.xsl">
+ <include name="**/*Configuration.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/server/\2Cfg.java" />
+ <param name="base-dir" expression="${src.dir}" />
+ </xslt>
+
+ <xslt basedir="${src.dir}" destdir="${src.gen.dir}" style="${admin.dir}/package-info.xsl">
+ <include name="**/Package.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)\.xml$$" to="\1/server/package-info.java" />
+ <param name="type" expression="server" />
+ </xslt>
+
+ <!-- Compile the Directory Server extension configuration ldap profile property files. -->
+ <xslt basedir="${src.dir}" destdir="${classes.dir}/admin/profiles/ldap" style="${admin.dir}/ldapMOProfile.xsl">
+ <include name="**/*Configuration.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ <regexpmapper handledirsep="true" from="^(.*)/([^/]+)Configuration\.xml$$" to="\1/meta/\2CfgDefn.properties" />
+ <param name="base-dir" expression="${src.dir}" />
+ </xslt>
+
+ <!-- Compile the Directory Server extension configuration manifest file. -->
+ <tempfile property="admin.temp.dir" destDir="${classes.dir}" />
+ <mkdir dir="${admin.temp.dir}" />
+ <xslt basedir="${src.dir}" destdir="${admin.temp.dir}" extension=".manifest" style="${admin.dir}/manifestMO.xsl">
+ <include name="**/*Configuration.xml" />
+ <exclude name="org/opends/server/admin/std/*.xml" />
+ </xslt>
+ <concat destfile="${classes.dir}/admin/extension.manifest">
+ <fileset dir="${admin.temp.dir}" includes="**/*.manifest" />
+ </concat>
+ <delete dir="${admin.temp.dir}" />
+ </target>
+
+ <!-- Validate the Directory Server extension configuration definitions. -->
+ <target name="validateadmin" description="Validate the Directory Server extension configuration definitions.">
+ <schemavalidate>
+ <fileset dir="${src.dir}" includes="**/*.xml" />
+ <schema namespace="http://www.opends.org/admin" file="${admin.dir}/admin.xsd" />
+ <schema namespace="http://www.opends.org/admin-ldap" file="${admin.dir}/admin-ldap.xsd" />
+ </schemavalidate>
+ </target>
+</project>
diff --git a/opends/resource/admin/example-plugin/example-plugin.ldif b/opends/resource/admin/example-plugin/example-plugin.ldif
new file mode 100644
index 0000000..b682749
--- /dev/null
+++ b/opends/resource/admin/example-plugin/example-plugin.ldif
@@ -0,0 +1,10 @@
+dn: cn=Example Plugin,cn=Plugins,cn=config
+objectClass: top
+objectClass: ds-cfg-plugin
+objectClass: ds-cfg-example-plugin
+cn: Example Plugin
+ds-cfg-plugin-enabled: true
+ds-cfg-plugin-class: com.example.opends.ExamplePlugin
+ds-cfg-plugin-type: startup
+ds-cfg-example-plugin-message: Hello World
+
diff --git a/opends/resource/admin/example-plugin/package-info.java b/opends/resource/admin/example-plugin/package-info.java
new file mode 100644
index 0000000..9190201
--- /dev/null
+++ b/opends/resource/admin/example-plugin/package-info.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/**
+ * Example OpenDS Hello World plugin implementation clases.
+ * <p>
+ * This package contains the classes which implement the example
+ * plugin.
+ */
+package com.example.opends;
+
diff --git a/opends/resource/admin/java-utilities.xsl b/opends/resource/admin/java-utilities.xsl
new file mode 100644
index 0000000..370b30d
--- /dev/null
+++ b/opends/resource/admin/java-utilities.xsl
@@ -0,0 +1,236 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common">
+ <!--
+ This XSLT file contains utility templates which can be used for any
+ generating Java code.
+ -->
+ <xsl:import href="text-utilities.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Add a copyright notice to the top of a Java source file.
+
+ TODO: it would be nice to generate the copyright year automatically.
+ -->
+ <xsl:template name="copyright-notice">
+ <xsl:value-of
+ select="concat('/*
',
+ ' * 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.
',
+ ' */
')" />
+ </xsl:template>
+ <!--
+ Convert an entity or property ID to a Java mixed-cased name.
+ For example, the string "my-string-value" will be converted to
+ the string "myStringValue".
+
+ @param value
+ The ID string to be converted to a Java name.
+ -->
+ <xsl:template name="name-to-java">
+ <xsl:param name="value" />
+ <xsl:if test="string-length($value)">
+ <xsl:choose>
+ <xsl:when test="contains($value, '-')">
+ <xsl:variable name="head"
+ select="substring-before($value, '-')" />
+ <xsl:variable name="tail"
+ select="substring-after($value, '-')" />
+ <xsl:call-template name="to-title-case">
+ <xsl:with-param name="value" select="$head" />
+ </xsl:call-template>
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$tail" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="to-title-case">
+ <xsl:with-param name="value" select="$value" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+ <!--
+ Convert an entity or property ID to a Java constant name.
+ For example, the string "my-string-value" will be converted to
+ the string "MY_STRING_VALUE".
+
+ @param value
+ The ID string to be converted to a Java constant.
+ -->
+ <xsl:template name="name-to-java-constant">
+ <xsl:param name="value" />
+ <xsl:value-of
+ select="translate($value,
+ 'abcdefghijklmnopqrstuvwxyz-',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')" />
+ </xsl:template>
+ <!--
+ Add a Java comment. This template handles two levels of
+ indentation: the indentation string for the first line, and a
+ second indentation string used for subsequent lines. The template
+ will output the content wrapping at the nearest word boundary to
+ column 70.
+
+ @param indent-text
+ The indentation text used for the first line.
+
+ @param indent-text2
+ The indentation text used for all lines except
+ the first - defaults to the value of indent-text.
+
+ @param content
+ The content to be output in the comment.
+ -->
+ <xsl:template name="add-java-comment">
+ <xsl:param name="indent-text" />
+ <xsl:param name="indent-text2" select="$indent-text" />
+ <xsl:param name="content" />
+ <xsl:call-template name="format-text">
+ <xsl:with-param name="indent-text" select="$indent-text" />
+ <xsl:with-param name="indent-text2" select="$indent-text2" />
+ <xsl:with-param name="wrap-column" select="'70'" />
+ <xsl:with-param name="content" select="$content" />
+ </xsl:call-template>
+ </xsl:template>
+ <!--
+ Utility template for removing duplicate values from a node-set.
+
+ This template is based on the version published on the XSLT site.
+ It is not capable of normalizing nodes - so they must be
+ pre-normalized before this template is called.
+
+ @param nodes A node-set containing the duplicate nodes.
+ -->
+ <xsl:template name="set-distinct">
+ <xsl:param name="nodes" select="/.." />
+ <xsl:call-template name="_set-distinct">
+ <xsl:with-param name="nodes" select="$nodes" />
+ </xsl:call-template>
+ </xsl:template>
+ <!-- set-distinct helper template -->
+ <xsl:template name="_set-distinct">
+ <xsl:param name="nodes" select="/.." />
+ <xsl:param name="distinct" select="/.." />
+ <xsl:choose>
+ <xsl:when test="$nodes">
+ <xsl:variable name="value" select="$nodes[1]" />
+ <xsl:choose>
+ <xsl:when test="$distinct[. = $value]">
+ <xsl:call-template name="_set-distinct">
+ <xsl:with-param name="distinct" select="$distinct" />
+ <xsl:with-param name="nodes" select="$nodes[position() > 1]" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="_set-distinct">
+ <xsl:with-param name="distinct" select="$distinct | $nodes[1]" />
+ <xsl:with-param name="nodes" select="$nodes[position() > 1]" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="$distinct" mode="set-distinct" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!-- set-distinct helper template -->
+ <xsl:template match="node()|@*" mode="set-distinct">
+ <xsl:copy-of select="." />
+ </xsl:template>
+ <!--
+ Generate a set of import statements.
+
+ This template takes a result tree fragment as a parameter
+ containing elements of the form:
+
+ <import>java.net.InetAddress</import>
+ <import>...</import>
+
+ This template will normalize each element and remove duplicates
+ before generating the output.
+
+ @param imports The result tree fragment containing the import elements.
+ -->
+ <xsl:template name="generate-import-statements">
+ <xsl:param name="imports" select="/.." />
+ <!--
+ Normalize the import elements since the set-distinct
+ template cannot handle additional whitespace
+ -->
+ <xsl:variable name="normalized-imports">
+ <xsl:for-each select="exsl:node-set($imports)/import">
+ <xsl:element name="import">
+ <xsl:value-of select="normalize-space()" />
+ </xsl:element>
+ </xsl:for-each>
+ </xsl:variable>
+ <!--
+ Now remove the duplicates
+ -->
+ <xsl:variable name="unique">
+ <xsl:call-template name="set-distinct">
+ <xsl:with-param name="nodes"
+ select="exsl:node-set($normalized-imports)/import" />
+ </xsl:call-template>
+ </xsl:variable>
+ <!--
+ Now output the import statements
+ -->
+ <xsl:for-each select="exsl:node-set($unique)/import">
+ <xsl:sort select="normalize-space()" />
+ <xsl:value-of
+ select="concat('import ', normalize-space(),';
')" />
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/ldapMOProfile.xsl b/opends/resource/admin/ldapMOProfile.xsl
new file mode 100644
index 0000000..7027ec1
--- /dev/null
+++ b/opends/resource/admin/ldapMOProfile.xsl
@@ -0,0 +1,62 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <xsl:import href="java-utilities.xsl" />
+ <xsl:import href="preprocessor.xsl" />
+ <xsl:import href="property-types.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Document parsing.
+ -->
+ <xsl:template match="/">
+ <xsl:value-of
+ select="concat('objectclass=',
+ normalize-space($this/adm:profile[@name='ldap']/ldap:object-class/ldap:name),
+ '
')" />
+ <xsl:for-each select="$this-all-properties">
+ <xsl:sort select="@name" />
+ <xsl:value-of
+ select="concat('attribute.',
+ normalize-space(@name),
+ '=',
+ normalize-space(adm:profile[@name='ldap']/ldap:attribute/ldap:name),
+ '
')" />
+ </xsl:for-each>
+ <xsl:for-each select="$this-all-relations">
+ <xsl:sort select="@name" />
+ <xsl:value-of
+ select="concat('rdn.',
+ normalize-space(@name),
+ '=',
+ normalize-space(adm:profile[@name='ldap']/ldap:rdn-sequence),
+ '
')" />
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/manifestMO.xsl b/opends/resource/admin/manifestMO.xsl
new file mode 100644
index 0000000..e80d73d
--- /dev/null
+++ b/opends/resource/admin/manifestMO.xsl
@@ -0,0 +1,52 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:import href="java-utilities.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Main document parsing template.
+ -->
+ <xsl:template match="/">
+ <xsl:choose>
+ <xsl:when test="adm:root-managed-object">
+ <xsl:value-of
+ select="'org.opends.server.admin.std.meta.RootCfgDefn
'" />
+ </xsl:when>
+ <xsl:when test="adm:managed-object">
+ <xsl:value-of
+ select="normalize-space(adm:managed-object/@package)" />
+ <xsl:value-of select="'.meta.'" />
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value"
+ select="normalize-space(adm:managed-object/@name)" />
+ </xsl:call-template>
+ <xsl:value-of select="'CfgDefn
'" />
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/metaMO.xsl b/opends/resource/admin/metaMO.xsl
new file mode 100644
index 0000000..1074ab0
--- /dev/null
+++ b/opends/resource/admin/metaMO.xsl
@@ -0,0 +1,1695 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:admpp="http://www.opends.org/admin-preprocessor"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common">
+ <xsl:import href="java-utilities.xsl" />
+ <xsl:import href="preprocessor.xsl" />
+ <xsl:import href="property-types.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Template for generating the class declaration.
+ -->
+ <xsl:template name="generate-meta-class-declaration">
+ <xsl:value-of select="'/**
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content"
+ select="concat('An interface for querying the ', $this-ufn,
+ ' managed object definition meta information.')" />
+ </xsl:call-template>
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="$this/adm:synopsis" />
+ </xsl:call-template>
+ <xsl:value-of select="' */
'" />
+ <xsl:value-of
+ select="concat('public final class ',
+ $this-java-class,
+ 'CfgDefn extends ')" />
+ <xsl:choose>
+ <xsl:when test="$this-is-abstract">
+ <xsl:value-of
+ select="concat('AbstractManagedObjectDefinition<',
+ $this-java-class, 'CfgClient, ',
+ $this-java-class, 'Cfg> {
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat('ManagedObjectDefinition<',
+ $this-java-class, 'CfgClient, ',
+ $this-java-class, 'Cfg> {
')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Template for generating the meta class body.
+ -->
+ <xsl:template name="generate-meta-class-body">
+ <!--
+ Singleton configuration definition instance.
+ -->
+ <xsl:value-of
+ select="concat(' // The singleton configuration definition instance.
',
+ ' private static final ',
+ $this-java-class ,
+ 'CfgDefn INSTANCE = new ', $this-java-class, 'CfgDefn();
')" />
+ <!--
+ Generate enumerations defined by this managed object..
+ -->
+ <xsl:for-each
+ select="$this-local-properties[adm:syntax/adm:enumeration]">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-enumeration" />
+ </xsl:for-each>
+ <!--
+ Generate declarations for properties defined or
+ overridden by this managed object.
+ -->
+ <xsl:for-each select="$this-local-properties">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-declaration" />
+ </xsl:for-each>
+ <!--
+ Generate declarations for relations.
+ -->
+ <xsl:for-each select="$this-local-relations">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-relation-declaration" />
+ </xsl:for-each>
+ <!--
+ Generate constructors for properties defined or
+ overridden by this managed object.
+ -->
+ <xsl:for-each select="$this-local-properties">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-constructor" />
+ </xsl:for-each>
+ <!--
+ Generate constructors for relations.
+ -->
+ <xsl:for-each select="$this-local-relations">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-relation-constructor" />
+ </xsl:for-each>
+ <!--
+ Configuration definition singleton getter.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="' /**
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content"
+ select="concat('Get the ', $this-ufn,' configuration definition singleton.')" />
+ </xsl:call-template>
+ <xsl:value-of select="' *
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="indent-text2" select="' * '" />
+ <xsl:with-param name="content"
+ select="concat('@return Returns the ', $this-ufn,
+ ' configuration definition singleton.')" />
+ </xsl:call-template>
+ <xsl:value-of select="' */
'" />
+ <xsl:value-of
+ select="concat(' public static ',
+ $this-java-class ,
+ 'CfgDefn getInstance() {
',
+ ' return INSTANCE;
',
+ ' }
')" />
+ <!--
+ Private constructor.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Private constructor.
',
+ ' */
',
+ ' private ',
+ $this-java-class ,
+ 'CfgDefn() {
')" />
+ <xsl:choose>
+ <xsl:when test="boolean($this/@extends)">
+ <xsl:value-of
+ select="concat(' super("',
+ $this/@name,
+ '", ',
+ $parent-java-class,
+ 'CfgDefn.getInstance());
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat(' super("',
+ $this/@name,
+ '", null);
')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of select="concat(' }
')" />
+ <!--
+ Create configuration view factory methods for non-abstract definitions
+ -->
+ <xsl:if test="not($this-is-abstract)">
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <!--
+ Generate configuration client factory method.
+ -->
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ',
+ $this-java-class,
+ 'CfgClient createClientConfiguration(
',
+ ' ManagedObject<? extends ',
+ $this-java-class,
+ 'CfgClient> impl) {
',
+ ' return new ',
+ $this-java-class ,
+ 'CfgClientImpl(impl);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <!--
+ Generate configuration server factory method.
+ -->
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ',
+ $this-java-class,
+ 'Cfg createServerConfiguration(
',
+ ' ServerManagedObject<? extends ',$this-java-class,'Cfg> impl) {
',
+ ' return new ',
+ $this-java-class ,
+ 'CfgServerImpl(impl);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <!--
+ Generate configuration server class getter..
+ -->
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public Class<',
+ $this-java-class,
+ 'Cfg> getServerConfigurationClass() {
',
+ ' return ',
+ $this-java-class ,
+ 'Cfg.class;
',
+ ' }
')" />
+ </xsl:if>
+ <!--
+ Generate property definition getters for local properties.
+ -->
+ <xsl:for-each select="$this-all-properties">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-definition-getter" />
+ </xsl:for-each>
+ <!--
+ Generate relation definition getters for local relations.
+ -->
+ <xsl:for-each select="$this-all-relations">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-relation-definition-getter" />
+ </xsl:for-each>
+ <!--
+ Managed object class implementations.
+ -->
+ <xsl:if test="not($this-is-abstract)">
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-client-impl-class" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-server-impl-class" />
+ </xsl:if>
+ </xsl:template>
+ <!--
+ Generate managed object client class implementation.
+ -->
+ <xsl:template name="generate-client-impl-class">
+ <!--
+ Declaration.
+ -->
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Managed object client implementation.
',
+ ' */
',
+ ' private static class ',
+ $this-java-class ,
+ 'CfgClientImpl implements
 ',
+ $this-java-class ,
+ 'CfgClient {
')" />
+ <xsl:text>
</xsl:text>
+ <!--
+ Private instance.
+ -->
+ <xsl:value-of
+ select="concat(' // Private implementation.
',
+ ' private ManagedObject<? extends ',
+ $this-java-class,
+ 'CfgClient> impl;
')" />
+ <!--
+ Private constructor.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' // Private constructor.
',
+ ' private ',
+ $this-java-class,
+ 'CfgClientImpl(
',
+ ' ManagedObject<? extends ',
+ $this-java-class,
+ 'CfgClient> impl) {
',
+ ' this.impl = impl;
',
+ ' };
')" />
+ <!--
+ Getters/Setters for all properties.
+ -->
+ <xsl:for-each select="$this-all-properties">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-getter">
+ <xsl:with-param name="interface" select="'client'" />
+ </xsl:call-template>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-setter" />
+ </xsl:for-each>
+ <!--
+ Relation methods.
+ -->
+ <xsl:for-each select="$this-all-relations">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-client-relation-methods" />
+ </xsl:for-each>
+ <!--
+ Managed object definition getter.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ManagedObjectDefinition<? extends ', $this-java-class,'CfgClient, ? extends ', $this-java-class,'Cfg> definition() {
',
+ ' return INSTANCE;
',
+ ' }
')" />
+ <!--
+ Property provider view.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public PropertyProvider properties() {
',
+ ' return impl;
',
+ ' }
')" />
+ <!--
+ Commit method.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void commit() throws OperationsException {
',
+ ' impl.commit();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="' }
'" />
+ </xsl:template>
+ <!--
+ Generate managed object server class implementation.
+ -->
+ <xsl:template name="generate-server-impl-class">
+ <!--
+ Declaration.
+ -->
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Managed object server implementation.
',
+ ' */
',
+ ' private static class ',
+ $this-java-class ,
+ 'CfgServerImpl implements
 ',
+ $this-java-class ,
+ 'Cfg {
')" />
+ <xsl:text>
</xsl:text>
+ <!--
+ Private instance.
+ -->
+ <xsl:value-of
+ select="concat(' // Private implementation.
',
+ ' private ServerManagedObject<? extends ', $this-java-class, 'Cfg> impl;
')" />
+ <!--
+ Private constructor.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' // Private constructor.
',
+ ' private ',
+ $this-java-class,
+ 'CfgServerImpl(ServerManagedObject<? extends ', $this-java-class, 'Cfg> impl) {
',
+ ' this.impl = impl;
',
+ ' };
')" />
+ <!--
+ Generate all the change listener methods - one for each managed
+ object in the hierarchy.
+ -->
+ <xsl:if test="not($this-is-root)">
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-change-listener" />
+ </xsl:if>
+ <!--
+ Getters/Setters for all properties.
+ -->
+ <xsl:for-each select="$this-all-properties">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-getter">
+ <xsl:with-param name="interface" select="'server'" />
+ </xsl:call-template>
+ </xsl:for-each>
+ <!--
+ Relation methods.
+ -->
+ <xsl:for-each select="$this-all-relations">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-server-relation-methods" />
+ </xsl:for-each>
+ <!--
+ Configuration definition getter.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ManagedObjectDefinition<? extends ', $this-java-class,'CfgClient, ? extends ', $this-java-class,'Cfg> definition() {
',
+ ' return INSTANCE;
',
+ ' }
')" />
+ <!--
+ Property provider view.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public PropertyProvider properties() {
',
+ ' return impl;
',
+ ' }
')" />
+ <!--
+ Configuration entry DN getter.
+ -->
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public DN dn() {
',
+ ' return impl.getDN();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="' }
'" />
+ </xsl:template>
+ <!--
+ Generate a property definition constructor.
+ -->
+ <xsl:template name="generate-property-declaration">
+ <xsl:variable name="java-prop-name">
+ <xsl:call-template name="name-to-java-constant">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="type">
+ <xsl:call-template name="get-property-definition-type" />
+ </xsl:variable>
+ <xsl:variable name="generic-type">
+ <xsl:call-template name="get-property-definition-generic-type" />
+ </xsl:variable>
+ <xsl:variable name="pdtype">
+ <xsl:choose>
+ <xsl:when test="string-length($generic-type) != 0">
+ <xsl:value-of
+ select="concat($type, '<', $generic-type, '>')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$type" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' // The "',
+ @name,
+ '" property definition.
',
+ ' private static final ', $pdtype, ' PD_', $java-prop-name, ';
')" />
+ </xsl:template>
+ <!--
+ Generate a property definition constructor.
+ -->
+ <xsl:template name="generate-property-constructor">
+ <xsl:variable name="java-prop-name">
+ <xsl:call-template name="name-to-java-constant">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="type">
+ <xsl:call-template name="get-property-definition-type" />
+ </xsl:variable>
+ <xsl:variable name="generic-type">
+ <xsl:call-template name="get-property-definition-generic-type" />
+ </xsl:variable>
+ <xsl:variable name="value-type">
+ <xsl:call-template name="get-property-java-type" />
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' // Build the "', @name, '" property definition.
',
+ ' static {
')" />
+ <xsl:choose>
+ <xsl:when test="string-length($generic-type) != 0">
+ <xsl:value-of
+ select="concat(' ', $type, '.Builder<', $generic-type, '> builder = ', $type, '.createBuilder("',@name, '");
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat(' ', $type, '.Builder builder = ', $type, '.createBuilder("',@name, '");
')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:if test="string(@multi-valued) = 'true'">
+ <xsl:value-of
+ select="' builder.setOption(PropertyOption.MULTI_VALUED);
'" />
+ </xsl:if>
+ <xsl:if test="string(@read-only) = 'true'">
+ <xsl:value-of
+ select="' builder.setOption(PropertyOption.READ_ONLY);
'" />
+ </xsl:if>
+ <xsl:if
+ test="adm:requires-admin-action/adm:server-restart|adm:requires-admin-action/adm:component-restart|adm:requires-admin-action/adm:other">
+ <xsl:value-of
+ select="' builder.setOption(PropertyOption.REQUIRES_ADMIN_ACTION);
'" />
+ </xsl:if>
+ <xsl:if test="string(@mandatory) = 'true'">
+ <xsl:value-of
+ select="' builder.setOption(PropertyOption.MANDATORY);
'" />
+ </xsl:if>
+ <xsl:if test="string(@hidden) = 'true'">
+ <xsl:value-of
+ select="' builder.setOption(PropertyOption.HIDDEN);
'" />
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="string(@mandatory) = 'true'">
+ <xsl:value-of
+ select="concat(' builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<', $value-type,'>());
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:if test="not(adm:default-behavior)">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('No default behavior defined for non-mandatory property "', @name,
+ '".')" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="adm:default-behavior/adm:undefined">
+ <xsl:value-of
+ select="concat(' builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<', $value-type,'>());
')" />
+ </xsl:when>
+ <xsl:when test="adm:default-behavior/adm:alias">
+ <xsl:value-of
+ select="concat(' builder.setDefaultBehaviorProvider(new AliasDefaultBehaviorProvider<', $value-type,'>());
')" />
+ </xsl:when>
+ <xsl:when test="adm:default-behavior/adm:defined">
+ <xsl:value-of
+ select="concat(' DefaultBehaviorProvider<', $value-type,'> provider = ',
+ 'new DefinedDefaultBehaviorProvider<', $value-type,'>(')" />
+ <xsl:for-each
+ select="adm:default-behavior/adm:defined/adm:value">
+ <xsl:value-of
+ select="concat('"', normalize-space(), '"')" />
+ <xsl:if test="position() != last()">
+ <xsl:value-of select="', '" />
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:value-of select="');
'" />
+ <xsl:value-of
+ select="' builder.setDefaultBehaviorProvider(provider);
'" />
+ </xsl:when>
+ <xsl:when
+ test="adm:default-behavior/adm:inherited/adm:relative">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Relative inherited property defaults not yet implemented (property "', @name,
+ '").')" />
+ </xsl:message>
+ </xsl:when>
+ <xsl:when
+ test="adm:default-behavior/adm:inherited/adm:absolute">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Absolute inherited property defaults not yet implemented (property "', @name,
+ '").')" />
+ </xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unrecognized default behavior type for property "', @name,
+ '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:call-template name="get-property-definition-ctor" />
+ <xsl:value-of
+ select="concat(' PD_', $java-prop-name, ' = builder.getInstance();
')" />
+ <xsl:value-of
+ select="concat(' INSTANCE.registerPropertyDefinition(PD_', $java-prop-name, ');
')" />
+ <xsl:value-of select="' }
'" />
+ </xsl:template>
+ <!--
+ Generate a relation definition declaration.
+ -->
+ <xsl:template name="generate-relation-declaration">
+ <xsl:variable name="relation-name">
+ <xsl:choose>
+ <xsl:when test="adm:one-to-many">
+ <xsl:value-of select="adm:one-to-many/@plural-name" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="java-relation-name">
+ <xsl:call-template name="name-to-java-constant">
+ <xsl:with-param name="value" select="$relation-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-managed-object-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' // The "',
+ $relation-name,
+ '" relation definition.
',
+ ' private static final ')" />
+ <xsl:choose>
+ <xsl:when test="adm:one-to-one">
+ <xsl:text>SingletonRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:when test="adm:one-to-zero-or-one">
+ <xsl:text>OptionalRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:when test="adm:one-to-many">
+ <xsl:text>InstantiableRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unknown relation type "', local-name(*), '" in relation "', @name, '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of
+ select="concat($java-managed-object-name, 'CfgClient, ', $java-managed-object-name, 'Cfg> RD_', $java-relation-name, ';
')" />
+ </xsl:template>
+ <!--
+ Generate a relation definition constructor.
+ -->
+ <xsl:template name="generate-relation-constructor">
+ <xsl:variable name="relation-name">
+ <xsl:choose>
+ <xsl:when test="adm:one-to-many">
+ <xsl:value-of select="adm:one-to-many/@plural-name" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="java-relation-name">
+ <xsl:call-template name="name-to-java-constant">
+ <xsl:with-param name="value" select="$relation-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-managed-object-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' // Build the "', $relation-name, '" relation definition.
',
+ ' static {
',
+ ' RD_', $java-relation-name, ' = new ')" />
+ <xsl:choose>
+ <xsl:when test="adm:one-to-one">
+ <xsl:text>SingletonRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:when test="adm:one-to-zero-or-one">
+ <xsl:text>OptionalRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:when test="adm:one-to-many">
+ <xsl:text>InstantiableRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unknown relation type "', local-name(*), '" in relation "', @name, '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of
+ select="concat($java-managed-object-name, 'CfgClient, ', $java-managed-object-name, 'Cfg>(
',
+ ' INSTANCE, "', @name, '", ')" />
+ <xsl:if test="adm:one-to-many">
+ <xsl:value-of
+ select="concat('"', adm:one-to-many/@plural-name, '", ')" />
+ </xsl:if>
+ <xsl:value-of
+ select="concat($java-managed-object-name, 'CfgDefn.getInstance());
')" />
+ <xsl:value-of
+ select="concat(' INSTANCE.registerRelationDefinition(RD_', $java-relation-name,');
')" />
+ <xsl:value-of select="' }
'" />
+ </xsl:template>
+ <!--
+ Generate a property definition getter for a locally defined
+ or overriden property.
+ -->
+ <xsl:template name="generate-property-definition-getter">
+ <xsl:variable name="java-prop-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-prop-name-constant">
+ <xsl:call-template name="name-to-java-constant">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="type">
+ <xsl:call-template name="get-property-definition-type" />
+ </xsl:variable>
+ <xsl:variable name="generic-type">
+ <xsl:call-template name="get-property-definition-generic-type" />
+ </xsl:variable>
+ <xsl:variable name="pdtype">
+ <xsl:choose>
+ <xsl:when test="string-length($generic-type) != 0">
+ <xsl:value-of
+ select="concat($type, '<', $generic-type, '>')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$type" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Get the "',
+ @name,
+ '" property definition.
')" />
+ <xsl:if test="adm:synopsis">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:synopsis" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="adm:description">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:description" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when
+ test="adm:profile[@name='preprocessor']/admpp:managed-object[@name=$this-name and @package=$this-package]">
+ <xsl:value-of
+ select="concat(' *
',
+ ' * @return Returns the "',
+ @name,
+ '" property definition.
',
+ ' */
',
+ ' public ',
+ $pdtype,
+ ' get',
+ $java-prop-name,
+ 'PropertyDefinition() {
' ,
+ ' return PD_',
+ $java-prop-name-constant ,
+ ';
' ,
+ ' }
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat(' *
',
+ ' * @return Returns the "',
+ @name,
+ '" property definition.
',
+ ' */
',
+ ' public ',
+ $pdtype,
+ ' get',
+ $java-prop-name,
+ 'PropertyDefinition() {
' ,
+ ' return ',
+ $parent-java-class, 'CfgDefn.getInstance().get',
+ $java-prop-name,
+ 'PropertyDefinition();
',
+ ' }
')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Generate a relation definition getter.
+ -->
+ <xsl:template name="generate-relation-definition-getter">
+ <xsl:variable name="relation-name">
+ <xsl:choose>
+ <xsl:when test="adm:one-to-many">
+ <xsl:value-of select="adm:one-to-many/@plural-name" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="java-relation-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$relation-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-relation-name-constant">
+ <xsl:call-template name="name-to-java-constant">
+ <xsl:with-param name="value" select="$relation-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Get the "',
+ $relation-name,
+ '" relation definition.
',
+ ' *
',
+ ' * @return Returns the "',
+ $relation-name,
+ '" relation definition.
',
+ ' */
',
+ ' public ')" />
+ <xsl:choose>
+ <xsl:when test="adm:one-to-one">
+ <xsl:text>SingletonRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:when test="adm:one-to-zero-or-one">
+ <xsl:text>OptionalRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:when test="adm:one-to-many">
+ <xsl:text>InstantiableRelationDefinition<</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unknown relation type "', local-name(*), '" in relation "', @name, '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:variable name="java-managed-object-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when
+ test="adm:profile[@name='preprocessor']/admpp:managed-object[@name=$this-name and @package=$this-package]">
+ <xsl:value-of
+ select="concat($java-managed-object-name, 'CfgClient,',
+ $java-managed-object-name, 'Cfg> get',
+ $java-relation-name,
+ 'RelationDefinition() {
' ,
+ ' return RD_',
+ $java-relation-name-constant,
+ ';
' ,
+ ' }
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat($java-managed-object-name, 'CfgClient,',
+ $java-managed-object-name, 'Cfg> get',
+ $java-relation-name,
+ 'RelationDefinition() {
' ,
+ ' return ',
+ $parent-java-class, 'CfgDefn.getInstance().get',
+ $java-relation-name,
+ 'RelationDefinition();
',
+ ' }
')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Generate a property value getter.
+ -->
+ <xsl:template name="generate-property-getter">
+ <xsl:param name="interface" select="/.." />
+ <xsl:variable name="java-prop-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ')" />
+ <xsl:choose>
+ <xsl:when test="string(@multi-valued) != 'true'">
+ <xsl:choose>
+ <xsl:when test="adm:default-behavior/adm:defined">
+ <!--
+ The method is guaranteed to return a value since there is a
+ well-defined default value.
+ -->
+ <xsl:call-template name="get-property-java-primitive-type" />
+ </xsl:when>
+ <xsl:when
+ test="$interface = 'server' and @mandatory = 'true'">
+ <!--
+ The method is guaranteed to return a value in the server interface, but
+ not necessarily in the client, since the mandatory property might not
+ have been created yet.
+ -->
+ <xsl:call-template name="get-property-java-primitive-type" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="get-property-java-type" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'SortedSet<'" />
+ <xsl:call-template name="get-property-java-type" />
+ <xsl:value-of select="'>'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="adm:syntax/adm:boolean">
+ <xsl:value-of select="' is'" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="' get'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="string(@multi-valued) != 'true'">
+ <xsl:value-of
+ select="concat($java-prop-name, '() {
',
+ ' return impl.getPropertyValue',
+ '(INSTANCE.get', $java-prop-name ,
+ 'PropertyDefinition());
' ,
+ ' }
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat($java-prop-name, '() {
',
+ ' return impl.getPropertyValues',
+ '(INSTANCE.get', $java-prop-name ,
+ 'PropertyDefinition());
' ,
+ ' }
')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Generate a property value setter.
+ -->
+ <xsl:template name="generate-property-setter">
+ <xsl:if test="string(@read-only) != 'true'">
+ <xsl:variable name="java-prop-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void set',
+ $java-prop-name ,
+ '(')" />
+ <xsl:choose>
+ <xsl:when test="string(@multi-valued) != 'true'">
+ <xsl:choose>
+ <xsl:when test="@mandatory = 'true'">
+ <xsl:call-template
+ name="get-property-java-primitive-type" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="get-property-java-type" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of
+ select="concat(' value) {
' ,
+ ' impl.setPropertyValue(INSTANCE.get',
+ $java-prop-name ,
+ 'PropertyDefinition(), value);
',
+ ' }
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'Collection<'" />
+ <xsl:call-template name="get-property-java-type" />
+ <xsl:value-of
+ select="concat('> values) {
' ,
+ ' impl.setPropertyValues(INSTANCE.get',
+ $java-prop-name ,
+ 'PropertyDefinition(), values);
',
+ ' }
')" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+ <!--
+ Generate client relation methods.
+ -->
+ <xsl:template name="generate-client-relation-methods">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="java-relation-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-class-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="adm:one-to-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ', $java-class-name, 'CfgClient get',
+ $java-relation-name, '() throws OperationsException {
',
+ ' return impl.getChild(INSTANCE.get', $java-relation-name,'RelationDefinition()).getConfiguration();
',
+ ' }
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-zero-or-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public boolean has',
+ $java-relation-name, '() throws OperationsException {
',
+ ' return impl.hasChild(INSTANCE.get', $java-relation-name,'RelationDefinition());
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ', $java-class-name, 'CfgClient get',
+ $java-relation-name, '() throws OperationsException {
',
+ ' return impl.getChild(INSTANCE.get', $java-relation-name,'RelationDefinition()).getConfiguration();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public <M extends ', $java-class-name, 'CfgClient> M create',
+ $java-relation-name, '(ManagedObjectDefinition<M, ?> d, PropertyProvider p) throws OperationsException {
',
+ ' return impl.createChild(INSTANCE.get', $java-relation-name,'RelationDefinition(), d, p).getConfiguration();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void remove',
+ $java-relation-name, '() throws OperationsException {
',
+ ' impl.removeChild(INSTANCE.get', $java-relation-name,'RelationDefinition());
',
+ ' }
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-many">
+ <xsl:variable name="plural-name"
+ select="adm:one-to-many/@plural-name" />
+ <xsl:variable name="java-relation-plural-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$plural-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public String[] list',
+ $java-relation-plural-name, '() throws OperationsException {
',
+ ' return impl.listChildren(INSTANCE.get', $java-relation-plural-name,'RelationDefinition());
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ', $java-class-name, 'CfgClient get',
+ $java-relation-name, '(String name) throws OperationsException {
',
+ ' return impl.getChild(INSTANCE.get', $java-relation-plural-name,'RelationDefinition(), name).getConfiguration();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public <M extends ', $java-class-name, 'CfgClient> M create',
+ $java-relation-name, '(ManagedObjectDefinition<M, ?> d, String name, PropertyProvider p) throws OperationsException {
',
+ ' return impl.createChild(INSTANCE.get', $java-relation-plural-name,'RelationDefinition(), d, name, p).getConfiguration();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void remove',
+ $java-relation-name, '(String name) throws OperationsException {
',
+ ' impl.removeChild(INSTANCE.get', $java-relation-plural-name,'RelationDefinition(), name);
',
+ ' }
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unknown relation type "', local-name(*), '" in relation "', $name, '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Generate server relation methods.
+ -->
+ <xsl:template name="generate-server-relation-methods">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="java-relation-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-class-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="adm:one-to-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ', $java-class-name, 'Cfg get',
+ $java-relation-name, '() throws ConfigException {
',
+ ' return impl.getChild(INSTANCE.get', $java-relation-name, 'RelationDefinition()).getConfiguration();
',
+ ' }
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-zero-or-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public boolean has',
+ $java-relation-name, '() {
',
+ ' return impl.hasChild(INSTANCE.get', $java-relation-name, 'RelationDefinition());
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ', $java-class-name, 'Cfg get',
+ $java-relation-name, '() throws ConfigException {
',
+ ' return impl.getChild(INSTANCE.get', $java-relation-name, 'RelationDefinition()).getConfiguration();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void add', $java-relation-name, 'AddListener(
',
+ ' ConfigurationAddListener<', $java-class-name,'Cfg> listener) throws ConfigException {
',
+ ' impl.registerAddListener(INSTANCE.get', $java-relation-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void remove', $java-relation-name, 'AddListener(
',
+ ' ConfigurationAddListener<', $java-class-name,'Cfg> listener) {
',
+ ' impl.deregisterAddListener(INSTANCE.get', $java-relation-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void add', $java-relation-name, 'DeleteListener(
',
+ ' ConfigurationDeleteListener<', $java-class-name,'Cfg> listener) throws ConfigException {
',
+ ' impl.registerDeleteListener(INSTANCE.get', $java-relation-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void remove', $java-relation-name, 'DeleteListener(
',
+ ' ConfigurationDeleteListener<', $java-class-name,'Cfg> listener) {
',
+ ' impl.deregisterDeleteListener(INSTANCE.get', $java-relation-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-many">
+ <xsl:variable name="plural-name"
+ select="adm:one-to-many/@plural-name" />
+ <xsl:variable name="java-relation-plural-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$plural-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public String[] list',
+ $java-relation-plural-name, '() {
',
+ ' return impl.listChildren(INSTANCE.get', $java-relation-plural-name,'RelationDefinition());
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public ', $java-class-name, 'Cfg get',
+ $java-relation-name, '(String name) throws ConfigException {
',
+ ' return impl.getChild(INSTANCE.get', $java-relation-plural-name, 'RelationDefinition(), name).getConfiguration();
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void add', $java-relation-name, 'AddListener(
',
+ ' ConfigurationAddListener<', $java-class-name,'Cfg> listener) throws ConfigException {
',
+ ' impl.registerAddListener(INSTANCE.get', $java-relation-plural-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void remove', $java-relation-name, 'AddListener(
',
+ ' ConfigurationAddListener<', $java-class-name,'Cfg> listener) {
',
+ ' impl.deregisterAddListener(INSTANCE.get', $java-relation-plural-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void add', $java-relation-name, 'DeleteListener(
',
+ ' ConfigurationDeleteListener<', $java-class-name,'Cfg> listener) throws ConfigException {
',
+ ' impl.registerDeleteListener(INSTANCE.get', $java-relation-plural-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public void remove', $java-relation-name, 'DeleteListener(
',
+ ' ConfigurationDeleteListener<', $java-class-name,'Cfg> listener) {
',
+ ' impl.deregisterDeleteListener(INSTANCE.get', $java-relation-plural-name, 'RelationDefinition(), listener);
',
+ ' }
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unknown relation type "', local-name(*), '" in relation "', $name, '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Generate change listener registration methods.
+ -->
+ <xsl:template name="generate-change-listener">
+ <!--
+ Process this managed object.
+ -->
+ <xsl:variable name="top-name"
+ select="$this/adm:profile[@name='preprocessor']/admpp:parent-managed-object[last()]/@name" />
+ <xsl:call-template name="generate-change-listener-help">
+ <xsl:with-param name="top-name" select="$top-name" />
+ <xsl:with-param name="name" select="$this-name" />
+ </xsl:call-template>
+ <!--
+ Process parent hierarchy.
+ -->
+ <xsl:for-each
+ select="$this/adm:profile[@name='preprocessor']/admpp:parent-managed-object">
+ <xsl:call-template name="generate-change-listener-help">
+ <xsl:with-param name="top-name" select="$top-name" />
+ <xsl:with-param name="name" select="@name" />
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:template>
+ <!--
+ Generate a single set of change listener registration methods.
+ -->
+ <xsl:template name="generate-change-listener-help">
+ <xsl:param name="top-name" select="/.." />
+ <xsl:param name="name" select="/.." />
+ <xsl:variable name="short-name">
+ <xsl:choose>
+ <xsl:when test="not($top-name) or $top-name = $name">
+ <xsl:value-of select="''" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="top-length"
+ select="string-length($top-name)" />
+ <xsl:variable name="length" select="string-length($name)" />
+ <xsl:variable name="diff" select="$length - $top-length" />
+ <xsl:value-of select="substring($name, 1, $diff - 1)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="java-class">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="short-java-class">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$short-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' public void add', $short-java-class, 'ChangeListener(
',
+ ' ConfigurationChangeListener<',$java-class,'Cfg> listener) {
',
+ ' impl.registerChangeListener(listener);
',
+ ' }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * {@inheritDoc}
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' public void remove', $short-java-class, 'ChangeListener(
',
+ ' ConfigurationChangeListener<',$java-class,'Cfg> listener) {
',
+ ' impl.deregisterChangeListener(listener);
',
+ ' }
')" />
+ </xsl:template>
+ <!--
+ Generate import statements for change-listener
+ -->
+ <xsl:template name="generate-change-listener-import-statements">
+ <!--
+ Process this managed object.
+ -->
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($this-package, '.server.', $this-java-class, 'Cfg')" />
+ </xsl:element>
+ <!--
+ Process parent hierarchy.
+ -->
+ <xsl:for-each
+ select="$this/adm:profile[@name='preprocessor']/admpp:parent-managed-object">
+ <xsl:variable name="java-class">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat(@package, '.server.', $java-class, 'Cfg')" />
+ </xsl:element>
+ </xsl:for-each>
+ </xsl:template>
+ <!--
+ Generate an enumeration for a locally defined enumerated property.
+ -->
+ <xsl:template name="generate-enumeration">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Defines the set of permissable values for the "', @name, '" property.
')" />
+ <xsl:if test="adm:synopsis">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:synopsis" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="adm:description">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:description" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:value-of
+ select="concat(' */
',
+ ' public static enum ')" />
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ <xsl:value-of select="' {
'" />
+ <xsl:text>
</xsl:text>
+ <xsl:for-each select="adm:syntax/adm:enumeration/adm:value">
+ <xsl:sort select="@name" />
+ <xsl:value-of select="' /**
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:description" />
+ </xsl:call-template>
+ <xsl:value-of select="' */
'" />
+ <xsl:value-of select="' '" />
+ <xsl:call-template name="name-to-java-constant">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ <xsl:value-of select="concat('("', @name, '")')" />
+ <xsl:choose>
+ <xsl:when test="position() != last()">
+ <xsl:value-of select="',
'" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="';
'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="' // String representation of the value.
'" />
+ <xsl:value-of select="' private final String name;
'" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="' // Private constructor.
'" />
+ <xsl:value-of select="' private '" />
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@name" />
+ </xsl:call-template>
+ <xsl:value-of
+ select="concat('(String name) { this.name = name; }
',
+ '
',
+ '
',
+ '
',
+ ' /**
',
+ ' * {@inheritDoc}
',
+ ' */
',
+ ' public String toString() { return name; }
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="' }
'" />
+ </xsl:template>
+ <!--
+ Main document parsing template.
+ -->
+ <xsl:template match="/">
+ <xsl:call-template name="copyright-notice" />
+ <xsl:value-of
+ select="concat('package ', $this-package, '.meta;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-import-statements">
+ <xsl:with-param name="imports">
+ <xsl:if
+ test="$this-local-properties[@multi-valued='true' or
+ @read-only='true' or
+ @hidden='true' or
+ @mandatory='true']">
+ <import>org.opends.server.admin.PropertyOption</import>
+ </xsl:if>
+ <xsl:if
+ test="$this-local-properties/adm:default-behavior/adm:undefined
+ | $this-local-properties[@mandatory='true']">
+ <import>
+ org.opends.server.admin.UndefinedDefaultBehaviorProvider
+ </import>
+ </xsl:if>
+ <xsl:if
+ test="$this-local-properties/adm:default-behavior/adm:alias">
+ <import>
+ org.opends.server.admin.AliasDefaultBehaviorProvider
+ </import>
+ </xsl:if>
+ <xsl:if
+ test="$this-local-properties/adm:default-behavior/adm:defined">
+ <import>
+ org.opends.server.admin.DefinedDefaultBehaviorProvider
+ </import>
+ <import>
+ org.opends.server.admin.DefaultBehaviorProvider
+ </import>
+ </xsl:if>
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($this-package, '.client.', $this-java-class, 'CfgClient')" />
+ </xsl:element>
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($this-package, '.server.', $this-java-class, 'Cfg')" />
+ </xsl:element>
+ <xsl:for-each select="$this-inherited-properties">
+ <xsl:call-template name="get-property-java-imports" />
+ </xsl:for-each>
+ <xsl:for-each select="$this-all-properties">
+ <xsl:call-template
+ name="get-property-definition-java-imports" />
+ </xsl:for-each>
+ <xsl:for-each select="$this-all-relations">
+ <xsl:variable name="java-class-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value"
+ select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat(@managed-object-package, '.client.', $java-class-name, 'CfgClient')" />
+ </xsl:element>
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat(@managed-object-package, '.server.', $java-class-name, 'Cfg')" />
+ </xsl:element>
+ </xsl:for-each>
+ <xsl:choose>
+ <xsl:when test="$this-is-abstract">
+ <import>
+ org.opends.server.admin.AbstractManagedObjectDefinition
+ </import>
+ </xsl:when>
+ <xsl:otherwise>
+ <import>
+ org.opends.server.admin.ManagedObjectDefinition
+ </import>
+ <import>org.opends.server.admin.PropertyProvider</import>
+ <import>org.opends.server.admin.OperationsException</import>
+ <import>
+ org.opends.server.admin.client.ManagedObject
+ </import>
+ <import>
+ org.opends.server.admin.server.ServerManagedObject
+ </import>
+ <xsl:if test="not($this-is-root)">
+ <import>
+ org.opends.server.admin.server.ConfigurationChangeListener
+ </import>
+ <xsl:call-template
+ name="generate-change-listener-import-statements" />
+ </xsl:if>
+ <import>org.opends.server.types.DN</import>
+ <xsl:if test="$this-all-relations/adm:one-to-many">
+ <import>
+ org.opends.server.admin.InstantiableRelationDefinition
+ </import>
+ <import>
+ org.opends.server.admin.server.ConfigurationAddListener
+ </import>
+ <import>
+ org.opends.server.admin.server.ConfigurationDeleteListener
+ </import>
+ <import>org.opends.server.config.ConfigException</import>
+ </xsl:if>
+ <xsl:if test="$this-all-relations/adm:one-to-zero-or-one">
+ <import>
+ org.opends.server.admin.OptionalRelationDefinition
+ </import>
+ <import>
+ org.opends.server.admin.server.ConfigurationAddListener
+ </import>
+ <import>
+ org.opends.server.admin.server.ConfigurationDeleteListener
+ </import>
+ <import>org.opends.server.config.ConfigException</import>
+ </xsl:if>
+ <xsl:if test="$this-all-relations/adm:one-to-one">
+ <import>
+ org.opends.server.admin.SingletonRelationDefinition
+ </import>
+ <import>org.opends.server.config.ConfigException</import>
+ </xsl:if>
+ <xsl:if test="$this-all-properties[@multi-valued='true']">
+ <import>java.util.SortedSet</import>
+ <import>java.util.Collection</import>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:if test="$this/@extends">
+ <xsl:if test="$parent-package != $this-package">
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($parent-package, '.meta.', $parent-java-class, 'CfgDefn')" />
+ </xsl:element>
+ </xsl:if>
+ </xsl:if>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-meta-class-declaration" />
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-meta-class-body" />
+ <xsl:text>}
</xsl:text>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/package-info.xsl b/opends/resource/admin/package-info.xsl
new file mode 100644
index 0000000..535bd56
--- /dev/null
+++ b/opends/resource/admin/package-info.xsl
@@ -0,0 +1,94 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:import href="java-utilities.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Global parameter: the sub-package name. Either 'meta', 'client', or 'server'.
+ -->
+ <xsl:param name="type" select="'.'" />
+ <!--
+ Main document parsing template.
+ -->
+ <xsl:template match="/">
+ <xsl:call-template name="copyright-notice" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="'/**
'" />
+ <xsl:choose>
+ <xsl:when test="$type='meta'">
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content"
+ select="concat('Provides introspection interfaces for the ',
+ normalize-space(adm:package/adm:synopsis),
+ ' This package provides programmatic access to ',
+ 'information about the managed objects, their ',
+ 'properties, their relationships with other ',
+ 'managed objects, and their inheritance model.')" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$type='client'">
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content"
+ select="concat('Provides client-side interfaces for querying ',
+ 'and managing the ',
+ normalize-space(adm:package/adm:synopsis),
+ ' Applications can use the interfaces defined ',
+ 'within this package to retrieve, list, create, ',
+ 'and remove managed objects, as well as query ',
+ 'and update their properties.')" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="$type='server'">
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content"
+ select="concat('Provides server-side interfaces for accessing ',
+ 'the ', normalize-space(adm:package/adm:synopsis),
+ ' Components within the server can use the ',
+ 'interfaces defined within this package to query ',
+ 'the properties of the managed objects and ',
+ 'register to be notified when managed objects are ',
+ 'added, removed, or modified.')" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Invalid package-info sub-package name: ', $type)" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of select="' */
'" />
+ <xsl:value-of
+ select="concat('package ', adm:package/@name, '.', $type, ';
')" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/preprocessor.xsl b/opends/resource/admin/preprocessor.xsl
new file mode 100644
index 0000000..26142fc
--- /dev/null
+++ b/opends/resource/admin/preprocessor.xsl
@@ -0,0 +1,902 @@
+<!-- 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:admpp="http://www.opends.org/admin-preprocessor"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common">
+ <xsl:import href="java-utilities.xsl" />
+ <xsl:output method="xml" indent="yes" />
+ <!--
+ Global parameter: the absolute path of the base directory where
+ XML managed object definitions can be found.
+ -->
+ <xsl:param name="base-dir" select="'.'" />
+ <!--
+ Get an absolute URI from a package, object name, and suffix.
+ -->
+ <xsl:template name="get-uri">
+ <xsl:param name="package" select="/.." />
+ <xsl:param name="name" select="/.." />
+ <xsl:param name="suffix" select="'.xml'" />
+ <!--
+ Convert the package name to a relative path.
+ -->
+ <xsl:variable name="rpath" select="translate($package, '.', '/')" />
+ <!--
+ Convert the managed object name to a file name.
+ -->
+ <xsl:variable name="java-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <!--
+ Get the absolute path.
+ -->
+ <xsl:value-of
+ select="concat($base-dir, '/', $rpath, '/', $java-name, $suffix)" />
+ </xsl:template>
+ <!--
+ Get the URI of the named package definition.
+ -->
+ <xsl:template name="get-package-uri">
+ <xsl:param name="package" select="/.." />
+ <xsl:call-template name="get-uri">
+ <xsl:with-param name="package" select="$package" />
+ <xsl:with-param name="name" select="'package'" />
+ </xsl:call-template>
+ </xsl:template>
+ <!--
+ Get the URI of the named managed object definition.
+ -->
+ <xsl:template name="get-managed-object-uri">
+ <xsl:param name="package" select="/.." />
+ <xsl:param name="name" select="/.." />
+ <xsl:call-template name="get-uri">
+ <xsl:with-param name="package" select="$package" />
+ <xsl:with-param name="name"
+ select="concat($name, '-configuration')" />
+ </xsl:call-template>
+ </xsl:template>
+ <!--
+ Pre-process the current managed object element.
+ -->
+ <xsl:template name="pre-process-managed-object">
+ <xsl:if test="not(adm:root-managed-object | adm:managed-object)">
+ <xsl:message terminate="yes">
+ <xsl:value-of select="'No managed object definition found.'" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:apply-templates
+ select="adm:root-managed-object | adm:managed-object"
+ mode="pre-process" />
+ </xsl:template>
+ <!--
+ Pre-process a managed object definition: pull in the managed object's
+ inherited property definitions and relations.
+ -->
+ <xsl:template match="adm:managed-object" mode="pre-process">
+ <xsl:if test="not(@name)">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="'Managed object definition does not specify managed object name.'" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:if test="not(@package)">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="'Managed object definition does not specify managed object package.'" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:variable name="parent-name" select="@extends" />
+ <xsl:variable name="parent-package">
+ <!--
+ The parent package defaults to this managed object's package.
+ -->
+ <xsl:choose>
+ <xsl:when test="@parent-package">
+ <xsl:value-of select="@parent-package" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@package" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <!--
+ Get this managed object's hierarchy if there is one.
+ -->
+ <xsl:variable name="_hierarchy">
+ <xsl:if test="$parent-name">
+ <xsl:variable name="uri">
+ <xsl:call-template name="get-managed-object-uri">
+ <xsl:with-param name="package" select="$parent-package" />
+ <xsl:with-param name="name" select="$parent-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="not(document($uri)/adm:managed-object)">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('No managed object definition found in ', $uri, '.')" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:if
+ test="not(document($uri)/adm:managed-object[@name=$parent-name and @package=$parent-package])">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Managed object definition found in ', $uri, ' but it did not define a managed object ', $parent-name, ' in package ', $parent-package, '.')" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:apply-templates select="document($uri)/adm:managed-object"
+ mode="pre-process" />
+ </xsl:if>
+ </xsl:variable>
+ <xsl:variable name="hierarchy" select="exsl:node-set($_hierarchy)" />
+ <!--
+ Now pre-process this managed object.
+ -->
+ <xsl:copy>
+ <!--
+ Shallow copy this element and its attributes.
+ -->
+ <xsl:copy-of select="@*" />
+ <!--
+ Pre-process this managed object's elements.
+ -->
+ <xsl:apply-templates
+ select="adm:TODO|adm:synopsis|adm:description|adm:profile"
+ mode="pre-process">
+ <xsl:with-param name="moname" select="@name" />
+ <xsl:with-param name="mopackage" select="@package" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ <!--
+ Add a pre-processor element defining this managed object's uppermost
+ definition.
+ -->
+ <xsl:if test="$parent-name">
+ <xsl:element name="adm:profile">
+ <xsl:attribute name="name">
+ <xsl:value-of select="'preprocessor'" />
+ </xsl:attribute>
+ <xsl:element name="admpp:parent-managed-object">
+ <xsl:attribute name="name">
+ <xsl:value-of select="$parent-name" />
+ </xsl:attribute>
+ <xsl:attribute name="package">
+ <xsl:value-of select="$parent-package" />
+ </xsl:attribute>
+ </xsl:element>
+ <xsl:copy-of
+ select="$hierarchy/adm:managed-object/adm:profile[@name='preprocessor']/admpp:parent-managed-object" />
+ </xsl:element>
+ </xsl:if>
+ <!--
+ Copy all inherited relations.
+ -->
+ <xsl:copy-of select="$hierarchy/adm:managed-object/adm:relation" />
+ <!--
+ Copy all local relations.
+ -->
+ <xsl:apply-templates select="adm:relation" mode="pre-process">
+ <xsl:with-param name="moname" select="@name" />
+ <xsl:with-param name="mopackage" select="@package" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ <!--
+ Copy all inherited properties.
+ -->
+ <xsl:copy-of select="$hierarchy/adm:managed-object/adm:property" />
+ <!--
+ Copy all local properties.
+ -->
+ <xsl:apply-templates select="adm:property|adm:property-reference"
+ mode="pre-process">
+ <xsl:with-param name="moname" select="@name" />
+ <xsl:with-param name="mopackage" select="@package" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Pre-process a managed object definition: pull in the managed object's
+ inherited property definitions and relations.
+ -->
+ <xsl:template match="adm:root-managed-object" mode="pre-process">
+ <!--
+ Now pre-process this root managed object.
+ By definition it has no hierarchy.
+ -->
+ <xsl:copy>
+ <!--
+ Shallow copy this element and its attributes.
+ -->
+ <xsl:copy-of select="@*" />
+ <!--
+ Pre-process this managed object's elements.
+ -->
+ <xsl:apply-templates mode="pre-process">
+ <xsl:with-param name="moname" select="'root'" />
+ <xsl:with-param name="mopackage"
+ select="'org.opends.server.admin.std'" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Pre-process a property definition by adding a "preprocessor" profile
+ which contains information about where the property was defined.
+ -->
+ <xsl:template match="adm:property" mode="pre-process">
+ <xsl:param name="mopackage" select="/.." />
+ <xsl:param name="moname" select="/.." />
+ <xsl:param name="hierarchy" select="/.." />
+ <!--
+ Make sure that this property does not have the same name as another
+ property or reference in this managed object.
+ -->
+ <xsl:variable name="name" select="@name" />
+ <xsl:if
+ test="../adm:property[@name=$name][2] |
+ ../adm:property-reference[@name=$name]">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Property definition ', @name, ' is already defined in this managed object')" />
+ </xsl:message>
+ </xsl:if>
+ <!--
+ Make sure that this property does not override an existing property.
+ -->
+ <xsl:if
+ test="$hierarchy/adm:managed-object/adm:property[@name=$name]">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Property definition ', @name, ' is already defined in a parent managed object')" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:copy>
+ <!--
+ Shallow copy this element and its attributes.
+ -->
+ <xsl:copy-of select="@*" />
+ <!--
+ Apply templates to subordinate elements (e.g. descriptions).
+ -->
+ <xsl:apply-templates mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ <!--
+ Now append the preprocessor profile.
+ -->
+ <xsl:element name="adm:profile">
+ <xsl:attribute name="name">
+ <xsl:value-of select="'preprocessor'" />
+ </xsl:attribute>
+ <xsl:element name="admpp:managed-object">
+ <xsl:attribute name="name">
+ <xsl:value-of select="$moname" />
+ </xsl:attribute>
+ <xsl:attribute name="package">
+ <xsl:value-of select="$mopackage" />
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:element>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Pre-process a property reference pulling in the referenced property
+ definition and by adding a "preprocessor" profile which contains
+ information about where the property was defined.
+ -->
+ <xsl:template match="adm:property-reference" mode="pre-process">
+ <xsl:param name="mopackage" select="/.." />
+ <xsl:param name="moname" select="/.." />
+ <xsl:param name="hierarchy" />
+ <!--
+ Make sure that this property reference does not have the same name as another
+ property or reference in this managed object.
+ -->
+ <xsl:variable name="name" select="@name" />
+ <xsl:if
+ test="../adm:property[@name=$name] |
+ ../adm:property-reference[@name=$name][2]">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Property definition ', @name, ' is already defined in this managed object')" />
+ </xsl:message>
+ </xsl:if>
+ <!--
+ Make sure that this property does not override an existing property.
+ -->
+ <xsl:if
+ test="$hierarchy/adm:managed-object/adm:property[@name=$name]">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Property reference ', @name, ' is already defined in a parent managed object')" />
+ </xsl:message>
+ </xsl:if>
+ <!--
+ Determine the package containing the reference property definition.
+ -->
+ <xsl:variable name="package">
+ <xsl:choose>
+ <xsl:when test="@package">
+ <xsl:value-of select="@package" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$mopackage" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <!--
+ Get the referenced package.
+ -->
+ <xsl:variable name="uri">
+ <xsl:call-template name="get-package-uri">
+ <xsl:with-param name="package" select="$package" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:if test="not(document($uri)/adm:package)">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('No package definition found in ', $uri, '.')" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:if test="not(document($uri)/adm:package[@name=$package])">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Package definition found in ', $uri, ' but it did not define package ', $package, '.')" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:if
+ test="not(document($uri)/adm:package[@name=$package]/adm:property[@name=$name])">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Referenced property definition "', $name,
+ '" not found in package definition "', $package,
+ '".')" />
+ </xsl:message>
+ </xsl:if>
+ <!--
+ Copy the referenced property definition taking care to override
+ the default behavior and admin action if required.
+ -->
+ <xsl:variable name="property"
+ select="document($uri)/adm:package[@name=$package]/adm:property[@name=$name]" />
+ <xsl:element name="adm:property">
+ <xsl:copy-of select="$property/@*" />
+ <xsl:apply-templates
+ select="$property/adm:TODO | $property/adm:synopsis | $property/adm:description"
+ mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ <xsl:choose>
+ <xsl:when test="adm:requires-admin-action">
+ <xsl:apply-templates select="adm:requires-admin-action"
+ mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates
+ select="$property/adm:requires-admin-action"
+ mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="adm:default-behavior">
+ <xsl:apply-templates select="adm:default-behavior"
+ mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="$property/adm:default-behavior"
+ mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:apply-templates
+ select="$property/adm:syntax | $property/adm:profile"
+ mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ <!--
+ Now append the preprocessor profile.
+ -->
+ <xsl:element name="adm:profile">
+ <xsl:attribute name="name">
+ <xsl:value-of select="'preprocessor'" />
+ </xsl:attribute>
+ <xsl:element name="admpp:managed-object">
+ <xsl:attribute name="name">
+ <xsl:value-of select="$moname" />
+ </xsl:attribute>
+ <xsl:attribute name="package">
+ <xsl:value-of select="$mopackage" />
+ </xsl:attribute>
+ </xsl:element>
+ <xsl:element name="admpp:package">
+ <xsl:attribute name="name">
+ <xsl:value-of select="$package" />
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:element>
+ </xsl:element>
+ </xsl:template>
+ <!--
+ Pre-process a relation, merging information from the referenced
+ managed object where required, and by adding a "preprocessor" profile
+ which contains information about where the relation was defined.
+ -->
+ <xsl:template match="adm:relation" mode="pre-process">
+ <xsl:param name="mopackage" select="/.." />
+ <xsl:param name="moname" select="/.." />
+ <xsl:param name="hierarchy" select="/.." />
+ <!--
+ Determine the name of the relation.
+ -->
+ <xsl:variable name="name" select="@name" />
+ <!--
+ Make sure that this relation does not override an existing relation.
+ -->
+ <xsl:if
+ test="$hierarchy/adm:managed-object/adm:relation[@name=$name]">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Relation ', $name, ' is already defined in a parent managed object.')" />
+ </xsl:message>
+ </xsl:if>
+ <!--
+ Make sure that this relation is not already defined in this managed object.
+ -->
+ <xsl:if test="../adm:relation[@name=$name][2]">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Relation ', $name, ' is already defined in this managed object.')" />
+ </xsl:message>
+ </xsl:if>
+ <!--
+ Now get the referenced managed object.
+ -->
+ <xsl:variable name="mname">
+ <xsl:choose>
+ <xsl:when test="not(@managed-object-name)">
+ <xsl:value-of select="$name" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@managed-object-name" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="mpackage">
+ <xsl:choose>
+ <xsl:when test="not(@managed-object-package)">
+ <xsl:value-of select="$mopackage" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@managed-object-package" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="uri">
+ <xsl:call-template name="get-managed-object-uri">
+ <xsl:with-param name="name" select="$mname" />
+ <xsl:with-param name="package" select="$mpackage" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="managed-object"
+ select="document($uri)/adm:managed-object[@name=$mname]" />
+ <xsl:if test="not($managed-object)">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Managed object definition "', $mname, '" not found in ', $uri, '.')" />
+ </xsl:message>
+ </xsl:if>
+ <!--
+ Now merge the relation.
+ -->
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <!--
+ Add missing attribute managed-object-name if it is not provided.
+ -->
+ <xsl:if test="not(@managed-object-name)">
+ <xsl:attribute name="managed-object-name">
+ <xsl:value-of select="$mname" />
+ </xsl:attribute>
+ </xsl:if>
+ <!--
+ Add missing attribute managed-object-package if it is not provided.
+ -->
+ <xsl:if test="not(@managed-object-package)">
+ <xsl:attribute name="managed-object-package">
+ <xsl:value-of select="$mpackage" />
+ </xsl:attribute>
+ </xsl:if>
+ <!--
+ Copy TODO element.
+ -->
+ <xsl:copy-of select="adm:TODO" />
+ <!--
+ Copy synopsis element from referenced managed object if it is undefined.
+ -->
+ <xsl:choose>
+ <xsl:when test="adm:synopsis">
+ <xsl:apply-templates select="adm:synopsis"
+ mode="merge-relation">
+ <xsl:with-param name="managed-object"
+ select="$managed-object" />
+ </xsl:apply-templates>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="$managed-object/adm:synopsis"
+ mode="merge-relation">
+ <xsl:with-param name="managed-object"
+ select="$managed-object" />
+ </xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+ <!--
+ Copy description element from referenced managed object if it is undefined.
+ -->
+ <xsl:choose>
+ <xsl:when test="adm:description">
+ <xsl:apply-templates select="adm:description"
+ mode="merge-relation">
+ <xsl:with-param name="managed-object"
+ select="$managed-object" />
+ </xsl:apply-templates>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="$managed-object/adm:description"
+ mode="merge-relation">
+ <xsl:with-param name="managed-object"
+ select="$managed-object" />
+ </xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+ <!--
+ Merge remaining elements.
+ -->
+ <xsl:apply-templates
+ select="*[not(self::adm:TODO|self::adm:synopsis|self::adm:description)]"
+ mode="merge-relation">
+ <xsl:with-param name="managed-object" select="$managed-object" />
+ </xsl:apply-templates>
+ <!--
+ Now append the preprocessor profile.
+ -->
+ <xsl:element name="adm:profile">
+ <xsl:attribute name="name">
+ <xsl:value-of select="'preprocessor'" />
+ </xsl:attribute>
+ <xsl:element name="admpp:managed-object">
+ <xsl:attribute name="name">
+ <xsl:value-of select="$moname" />
+ </xsl:attribute>
+ <xsl:attribute name="package">
+ <xsl:value-of select="$mopackage" />
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:element>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Default template for merging relations.
+ -->
+ <xsl:template match="*|comment()" mode="merge-relation">
+ <xsl:param name="managed-object" select="/.." />
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <xsl:apply-templates mode="merge-relation">
+ <xsl:with-param name="managed-object" select="$managed-object" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Merge a one-to-many relation.
+ -->
+ <xsl:template match="adm:one-to-many" mode="merge-relation">
+ <xsl:param name="managed-object" select="/.." />
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <!--
+ Add missing plural name attribute if not present.
+ -->
+ <xsl:if test="not(@plural-name)">
+ <xsl:attribute name="plural-name">
+ <xsl:value-of select="$managed-object/@plural-name" />
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates mode="merge-relation">
+ <xsl:with-param name="managed-object" select="$managed-object" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Process a rich-description element in a relation.
+ -->
+ <xsl:template match="adm:synopsis|adm:description"
+ mode="merge-relation">
+ <xsl:param name="managed-object" select="/.." />
+ <xsl:copy>
+ <!--
+ Shallow copy.
+ -->
+ <xsl:copy-of select="@*" />
+ <xsl:apply-templates mode="rich-description">
+ <xsl:with-param name="ufn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$managed-object/@name" />
+ </xsl:call-template>
+ </xsl:with-param>
+ <xsl:with-param name="ufpn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value"
+ select="$managed-object/@plural-name" />
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Process a rich-description element.
+ -->
+ <xsl:template
+ match="adm:synopsis|adm:description|adm:unit-description"
+ mode="pre-process">
+ <xsl:copy>
+ <!--
+ Shallow copy.
+ -->
+ <xsl:copy-of select="@*" />
+ <xsl:apply-templates mode="rich-description">
+ <xsl:with-param name="ufn" select="$this-ufn" />
+ <xsl:with-param name="ufpn" select="$this-ufpn" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Process a user-friendly-name element.
+ -->
+ <xsl:template match="adm:user-friendly-name"
+ mode="rich-description">
+ <xsl:param name="ufn" select="/.." />
+ <xsl:value-of select="$ufn" />
+ </xsl:template>
+ <!--
+ Process a user-friendly-plural-name element.
+ -->
+ <xsl:template match="adm:user-friendly-plural-name"
+ mode="rich-description">
+ <xsl:param name="ufpn" select="/.." />
+ <xsl:value-of select="$ufpn" />
+ </xsl:template>
+ <!--
+ Process a product-name element.
+ -->
+ <xsl:template match="adm:product-name" mode="rich-description">
+ <xsl:value-of select="$product-name" />
+ </xsl:template>
+ <!--
+ Default template for rich descriptions.
+ -->
+ <xsl:template match="*|comment()" mode="rich-description">
+ <xsl:param name="ufn" select="/.." />
+ <xsl:param name="ufpn" select="/.." />
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <xsl:apply-templates mode="rich-description">
+ <xsl:with-param name="ufn" select="$ufn" />
+ <xsl:with-param name="ufpn" select="$ufpn" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Default template for pre-processing.
+ -->
+ <xsl:template match="*|comment()" mode="pre-process">
+ <xsl:param name="mopackage" select="/.." />
+ <xsl:param name="moname" select="/.." />
+ <xsl:param name="hierarchy" />
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <xsl:apply-templates mode="pre-process">
+ <xsl:with-param name="mopackage" select="$mopackage" />
+ <xsl:with-param name="moname" select="$moname" />
+ <xsl:with-param name="hierarchy" select="$hierarchy" />
+ </xsl:apply-templates>
+ </xsl:copy>
+ </xsl:template>
+ <!--
+ Useful variables relating to the current managed object.
+ -->
+ <!--
+ Product name.
+
+ FIXME: should get this from the root configuration but for some
+ reason we get a circular dependency error when constructing
+ the URI in JDK1.6.
+ -->
+ <xsl:variable name="product-name" select="'OpenDS Directory Server'" />
+ <xsl:variable name="this-name">
+ <xsl:choose>
+ <xsl:when test="/adm:managed-object">
+ <xsl:value-of select="/adm:managed-object/@name" />
+ </xsl:when>
+ <xsl:otherwise>
+ <!--
+ Must be the root configuration.
+ -->
+ <xsl:value-of select="'root'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="this-plural-name">
+ <xsl:choose>
+ <xsl:when test="/adm:managed-object">
+ <xsl:value-of select="/adm:managed-object/@plural-name" />
+ </xsl:when>
+ <xsl:otherwise>
+ <!--
+ Must be the root configuration - the plural form should never
+ be required as this is a singleton. We'll define it for
+ consistency.
+ -->
+ <xsl:value-of select="'roots'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="this-ufn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$this-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="this-ufpn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$this-plural-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="_this">
+ <xsl:call-template name="pre-process-managed-object" />
+ </xsl:variable>
+ <xsl:variable name="_this_tmp" select="exsl:node-set($_this)" />
+ <xsl:variable name="this"
+ select="$_this_tmp/adm:managed-object | $_this_tmp/adm:root-managed-object" />
+ <xsl:variable name="this-is-abstract"
+ select="boolean(string($this/@abstract) = 'true')" />
+ <xsl:variable name="this-is-root"
+ select="not(local-name($this) = 'managed-object')" />
+ <xsl:variable name="this-package">
+ <xsl:choose>
+ <xsl:when test="not($this-is-root)">
+ <xsl:value-of select="$this/@package" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'org.opends.server.admin.std'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="this-java-class">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$this-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="this-short-name">
+ <xsl:variable name="top-name"
+ select="$this/adm:profile[@name='preprocessor']/admpp:parent-managed-object[last()]/@name" />
+ <xsl:choose>
+ <xsl:when test="$this-is-root">
+ <xsl:value-of select="''" />
+ </xsl:when>
+ <xsl:when test="not($top-name)">
+ <xsl:value-of select="''" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="top-length"
+ select="string-length($top-name)" />
+ <xsl:variable name="this-length"
+ select="string-length($this-name)" />
+ <xsl:variable name="diff" select="$this-length - $top-length" />
+ <xsl:variable name="start"
+ select="substring($this-name, 1, $diff - 1)" />
+ <xsl:variable name="middle"
+ select="substring($this-name, $diff, 1)" />
+ <xsl:variable name="end"
+ select="substring($this-name, $diff + 1, $top-length)" />
+ <xsl:if test="$middle != '-' or $end != $top-name">
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('The managed object ', $this-name, ' should end with ', $top-name)" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:value-of select="$start" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="this-short-java-class">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$this-short-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <!--
+ Useful variables relating to the parent managed object.
+ -->
+ <xsl:variable name="parent-name" select="$this/@extends" />
+ <xsl:variable name="parent-package">
+ <xsl:choose>
+ <xsl:when test="$this/@parent-package">
+ <xsl:value-of select="$this/@parent-package" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$this-package" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="parent-java-class">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$parent-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <!--
+ Useful variables relating to managed object's relations.
+ -->
+ <xsl:variable name="this-local-relations"
+ select="$this/adm:relation[adm:profile[@name='preprocessor']/admpp:managed-object[@name=$this-name and @package=$this-package]]" />
+ <xsl:variable name="this-inherited-relations"
+ select="$this/adm:relation[adm:profile[@name='preprocessor']/admpp:managed-object[not(@name=$this-name and @package=$this-package)]]" />
+ <xsl:variable name="this-all-relations" select="$this/adm:relation" />
+ <!--
+ Useful variables relating to managed object's properties.
+ -->
+ <xsl:variable name="this-local-properties"
+ select="$this/adm:property[adm:profile[@name='preprocessor']/admpp:managed-object[@name=$this-name and @package=$this-package]]" />
+ <xsl:variable name="this-inherited-properties"
+ select="$this/adm:property[adm:profile[@name='preprocessor']/admpp:managed-object[not(@name=$this-name and @package=$this-package)]]" />
+ <xsl:variable name="this-all-properties" select="$this/adm:property" />
+ <!--
+ Default rule for testing.
+ -->
+ <xsl:template match="/">
+ <xsl:copy-of select="$this" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types.xsl b/opends/resource/admin/property-types.xsl
new file mode 100644
index 0000000..9dc2aac
--- /dev/null
+++ b/opends/resource/admin/property-types.xsl
@@ -0,0 +1,335 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+
+
+
+ WARNING: when new property types are defined, they must be
+ included here.
+
+ These stylesheets are included and NOT imported so that they
+ have the same import precedence as the default rules.
+
+
+
+ -->
+ <xsl:include href="property-types/attribute-type.xsl" />
+ <xsl:include href="property-types/boolean.xsl" />
+ <xsl:include href="property-types/dn.xsl" />
+ <xsl:include href="property-types/duration.xsl" />
+ <xsl:include href="property-types/enumeration.xsl" />
+ <xsl:include href="property-types/integer.xsl" />
+ <xsl:include href="property-types/ip-address-mask.xsl" />
+ <xsl:include href="property-types/ip-address.xsl" />
+ <xsl:include href="property-types/java-class.xsl" />
+ <xsl:include href="property-types/oid.xsl" />
+ <xsl:include href="property-types/password.xsl" />
+ <xsl:include href="property-types/size.xsl" />
+ <xsl:include href="property-types/string.xsl" />
+ <!--
+
+
+
+ Default rules applicable to each property type.
+
+ Property type stylesheets should override these where necessary.
+
+
+
+ -->
+ <!--
+ Get the Java object-based type associated with a property syntax.
+
+ By default property values are represented using strings.
+ -->
+ <xsl:template match="*" mode="java-value-type">
+ <xsl:value-of select="'String'" />
+ </xsl:template>
+ <!--
+ Get the Java primitive type, if applicable, associated with a
+ property syntax.
+
+ By default property values are represented using the type defined by
+ java-value-type.
+ -->
+ <xsl:template match="*" mode="java-value-primitive-type">
+ <xsl:apply-templates select="." mode="java-value-type" />
+ </xsl:template>
+ <!--
+ Generate import elements represesenting the import statements
+ required by values of the property.
+
+ By default property values are represented using strings which
+ don't require an import statement - so do nothing.
+ -->
+ <xsl:template match="*" mode="java-value-imports" />
+ <!--
+ Generate the Java definition type used to define the property.
+
+ By default properties are defined using string property
+ definitions.
+ -->
+ <xsl:template match="*" mode="java-definition-type">
+ <xsl:value-of select="'StringPropertyDefinition'" />
+ </xsl:template>
+ <!--
+ Generate import elements represesenting the import statements
+ required by the property's definition and its values.
+
+ By default assume that the definition type is in
+ org.opends.server.admin and is derived directly from the
+ java-definition-type (might not be the case for parameterized
+ types. In addition pull in the value imports.
+ -->
+ <xsl:template match="*" mode="java-definition-imports">
+ <xsl:element name="import">
+ <xsl:value-of select="'org.opends.server.admin.'" />
+ <xsl:apply-templates select="." mode="java-definition-type" />
+ </xsl:element>
+ <xsl:apply-templates select="." mode="java-value-imports" />
+ </xsl:template>
+ <!--
+ If the property definition is generic, get the generic type. Otherwise,
+ do nothing.
+
+ Default: do nothing.
+ -->
+ <xsl:template match="*" mode="java-definition-generic-type" />
+ <!--
+ Generate property definition specific constructor setters.
+
+ By default, do nothing.
+ -->
+ <xsl:template match="*" mode="java-definition-ctor" />
+ <!--
+
+
+ Wrapper templates which can be called directly instead of
+ requiring the more indirect and less readable apply-templates
+ mechanism.
+
+
+ -->
+ <!--
+ Get the Java imports required for a property's values.
+ -->
+ <xsl:template name="get-property-java-imports">
+ <xsl:apply-templates select="adm:syntax/*"
+ mode="java-value-imports" />
+ </xsl:template>
+ <!--
+ Get the Java imports required for a property's definition.
+ -->
+ <xsl:template name="get-property-definition-java-imports">
+ <xsl:apply-templates select="adm:syntax/*"
+ mode="java-definition-imports" />
+ </xsl:template>
+ <!--
+ Get the Java object-based type associated with a property syntax.
+ -->
+ <xsl:template name="get-property-java-type">
+ <xsl:apply-templates select="adm:syntax/*" mode="java-value-type" />
+ </xsl:template>
+ <!--
+ Get the Java primitive type, if applicable, associated with a
+ property syntax.
+ -->
+ <xsl:template name="get-property-java-primitive-type">
+ <xsl:apply-templates select="adm:syntax/*"
+ mode="java-value-primitive-type" />
+ </xsl:template>
+ <!--
+ Get the property definition type associated with a
+ property syntax.
+ -->
+ <xsl:template name="get-property-definition-type">
+ <xsl:apply-templates select="adm:syntax/*"
+ mode="java-definition-type" />
+ </xsl:template>
+ <!--
+ If the property definition is generic, get the generic type. Otherwise,
+ do nothing.
+ -->
+ <xsl:template name="get-property-definition-generic-type">
+ <xsl:apply-templates select="adm:syntax/*"
+ mode="java-definition-generic-type" />
+ </xsl:template>
+ <!--
+ Generate property definition specific constructor setters.
+ -->
+ <xsl:template name="get-property-definition-ctor">
+ <xsl:apply-templates select="adm:syntax/*"
+ mode="java-definition-ctor" />
+ </xsl:template>
+ <!--
+ Generate the property getter declarations.
+ -->
+ <xsl:template name="generate-property-getter-declaration">
+ <xsl:param name="interface" select="/.." />
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="java-property-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Get the "', $name,'" property.
')" />
+ <xsl:if test="adm:synopsis">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:synopsis" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="adm:description">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:description" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="string(@multi-valued) != 'true'">
+ <xsl:value-of
+ select="concat(' *
',
+ ' * @return Returns the value of the "', $name,'" property.
',
+ ' */
')" />
+ <xsl:value-of select="' '" />
+ <xsl:choose>
+ <xsl:when test="adm:default-behavior/adm:defined">
+ <!--
+ The method is guaranteed to return a value since there is a
+ well-defined default value.
+ -->
+ <xsl:call-template name="get-property-java-primitive-type" />
+ </xsl:when>
+ <xsl:when
+ test="$interface = 'server' and @mandatory = 'true'">
+ <!--
+ The method is guaranteed to return a value in the server interface, but
+ not necessarily in the client, since the mandatory property might not
+ have been created yet.
+ -->
+ <xsl:call-template name="get-property-java-primitive-type" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="get-property-java-type" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat(' *
',
+ ' * @return Returns the values of the "', $name,'" property.
',
+ ' */
')" />
+ <xsl:value-of select="' SortedSet<'" />
+ <xsl:call-template name="get-property-java-type" />
+ <xsl:value-of select="'>'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="adm:syntax/adm:boolean">
+ <xsl:value-of select="' is'" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="' get'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of
+ select="concat($java-property-name,
+ '();
')" />
+ </xsl:template>
+ <!--
+ Generate the property setter declarations.
+ -->
+ <xsl:template name="generate-property-setter-declaration">
+ <xsl:if test="string(@read-only) != 'true'">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="java-property-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Set the "', $name, '" property.
')" />
+ <xsl:if test="adm:synopsis">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:synopsis" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="adm:description">
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="adm:description" />
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="string(@multi-valued) != 'true'">
+ <xsl:value-of
+ select="concat(' *
',
+ ' * @param value The value of the "', $name, '" property.
',
+ ' * @throws IllegalPropertyValueException
',
+ ' * If the new value is invalid.
',
+ ' *
',
+ ' */
',
+ ' void set', $java-property-name, '(')" />
+ <xsl:choose>
+ <xsl:when test="@mandatory = 'true'">
+ <xsl:call-template
+ name="get-property-java-primitive-type" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="get-property-java-type" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of
+ select="' value) throws IllegalPropertyValueException;
'" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat(' *
',
+ ' * @param values The values of the "', $name, '" property.
',
+ ' * @throws IllegalPropertyValueException
',
+ ' * If one or more of the new values are invalid.
',
+ ' *
',
+ ' */
',
+ ' void set', $java-property-name, '(Collection<')" />
+ <xsl:call-template name="get-property-java-type" />
+ <xsl:value-of
+ select="'> values) throws IllegalPropertyValueException;
'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/attribute-type.xsl b/opends/resource/admin/property-types/attribute-type.xsl
new file mode 100644
index 0000000..1d351e4
--- /dev/null
+++ b/opends/resource/admin/property-types/attribute-type.xsl
@@ -0,0 +1,42 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing attribute type properties.
+ -->
+ <xsl:template match="adm:attribute-type" mode="java-value-imports">
+ <import>org.opends.server.types.AttributeType</import>
+ </xsl:template>
+ <xsl:template match="adm:attribute-type" mode="java-value-type">
+ <xsl:value-of select="'AttributeType'" />
+ </xsl:template>
+ <xsl:template match="adm:attribute-type"
+ mode="java-definition-type">
+ <xsl:value-of select="'AttributeTypePropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/boolean.xsl b/opends/resource/admin/property-types/boolean.xsl
new file mode 100644
index 0000000..6343b3f
--- /dev/null
+++ b/opends/resource/admin/property-types/boolean.xsl
@@ -0,0 +1,41 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing boolean properties.
+ -->
+ <xsl:template match="adm:boolean" mode="java-value-type">
+ <xsl:value-of select="'Boolean'" />
+ </xsl:template>
+ <xsl:template match="adm:boolean" mode="java-value-primitive-type">
+ <xsl:value-of select="'boolean'" />
+ </xsl:template>
+ <xsl:template match="adm:boolean" mode="java-definition-type">
+ <xsl:value-of select="'BooleanPropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/dn.xsl b/opends/resource/admin/property-types/dn.xsl
new file mode 100644
index 0000000..60bdaf2
--- /dev/null
+++ b/opends/resource/admin/property-types/dn.xsl
@@ -0,0 +1,48 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing DN properties.
+ -->
+ <xsl:template match="adm:dn" mode="java-value-imports">
+ <import>org.opends.server.types.DN</import>
+ </xsl:template>
+ <xsl:template match="adm:dn" mode="java-value-type">
+ <xsl:value-of select="'DN'" />
+ </xsl:template>
+ <xsl:template match="adm:dn" mode="java-definition-type">
+ <xsl:value-of select="'DNPropertyDefinition'" />
+ </xsl:template>
+ <xsl:template match="adm:dn" mode="java-definition-ctor">
+ <xsl:if test="adm:base">
+ <xsl:value-of
+ select="concat(' builder.setBaseDN("',
+ normalize-space(adm:base), '");
')" />
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/duration.xsl b/opends/resource/admin/property-types/duration.xsl
new file mode 100644
index 0000000..acd3506
--- /dev/null
+++ b/opends/resource/admin/property-types/duration.xsl
@@ -0,0 +1,68 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing duration properties.
+ -->
+ <xsl:template match="adm:duration" mode="java-value-type">
+ <xsl:value-of select="'Long'" />
+ </xsl:template>
+ <xsl:template match="adm:duration" mode="java-value-primitive-type">
+ <xsl:value-of select="'long'" />
+ </xsl:template>
+ <xsl:template match="adm:duration" mode="java-definition-type">
+ <xsl:value-of select="'DurationPropertyDefinition'" />
+ </xsl:template>
+ <xsl:template match="adm:duration" mode="java-definition-ctor">
+ <xsl:if test="boolean(@allow-unlimited)">
+ <xsl:value-of
+ select="concat(' builder.setAllowUnlimited(',
+ @allow-unlimited, ');
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@base-unit)">
+ <xsl:value-of
+ select="concat(' builder.setBaseUnit("',
+ @base-unit, '");
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@maximum-unit)">
+ <xsl:value-of
+ select="concat(' builder.setMaximumUnit("',
+ @maximum-unit, '");
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@upper-limit)">
+ <xsl:value-of
+ select="concat(' builder.setUpperLimit(',
+ @upper-limit, 'L);
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@lower-limit)">
+ <xsl:value-of
+ select="concat(' builder.setLowerLimit(',
+ @lower-limit, 'L);
')" />
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/enumeration.xsl b/opends/resource/admin/property-types/enumeration.xsl
new file mode 100644
index 0000000..fa18fab
--- /dev/null
+++ b/opends/resource/admin/property-types/enumeration.xsl
@@ -0,0 +1,86 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:admpp="http://www.opends.org/admin-preprocessor"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing enumeration properties.
+ -->
+ <xsl:template match="adm:enumeration" mode="java-value-imports">
+ <xsl:variable name="pp"
+ select="../../adm:profile[@name='preprocessor']" />
+ <xsl:element name="import">
+ <xsl:choose>
+ <xsl:when test="$pp/admpp:package">
+ <xsl:value-of select="concat($pp/admpp:package/@name, '.')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="concat($pp/admpp:managed-object/@package, '.meta.')" />
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value"
+ select="$pp/admpp:managed-object/@name" />
+ </xsl:call-template>
+ <xsl:value-of select="'CfgDefn.'" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:apply-templates select="." mode="java-value-type" />
+ </xsl:element>
+ </xsl:template>
+ <xsl:template match="adm:enumeration"
+ mode="java-definition-imports">
+ <xsl:element name="import">
+ <xsl:value-of
+ select="'org.opends.server.admin.EnumPropertyDefinition'" />
+ </xsl:element>
+ <xsl:variable name="pp"
+ select="../../adm:profile[@name='preprocessor']" />
+ <xsl:if test="$pp/admpp:package">
+ <xsl:element name="import">
+ <xsl:value-of select="concat($pp/admpp:package/@name, '.')" />
+ <xsl:apply-templates select="." mode="java-value-type" />
+ </xsl:element>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template match="adm:enumeration" mode="java-value-type">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="../../@name" />
+ </xsl:call-template>
+ </xsl:template>
+ <xsl:template match="adm:enumeration" mode="java-definition-type">
+ <xsl:value-of select="'EnumPropertyDefinition'" />
+ </xsl:template>
+ <xsl:template match="adm:enumeration"
+ mode="java-definition-generic-type">
+ <xsl:apply-templates select="." mode="java-value-type" />
+ </xsl:template>
+ <xsl:template match="adm:enumeration" mode="java-definition-ctor">
+ <xsl:value-of select="' builder.setEnumClass('" />
+ <xsl:apply-templates select="." mode="java-value-type" />
+ <xsl:value-of select="'.class);
'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/integer.xsl b/opends/resource/admin/property-types/integer.xsl
new file mode 100644
index 0000000..a6c8c2a
--- /dev/null
+++ b/opends/resource/admin/property-types/integer.xsl
@@ -0,0 +1,58 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing integer properties.
+ -->
+ <xsl:template match="adm:integer" mode="java-value-type">
+ <xsl:value-of select="'Integer'" />
+ </xsl:template>
+ <xsl:template match="adm:integer" mode="java-value-primitive-type">
+ <xsl:value-of select="'int'" />
+ </xsl:template>
+ <xsl:template match="adm:integer" mode="java-definition-type">
+ <xsl:value-of select="'IntegerPropertyDefinition'" />
+ </xsl:template>
+ <xsl:template match="adm:integer" mode="java-definition-ctor">
+ <xsl:if test="boolean(@allow-unlimited)">
+ <xsl:value-of
+ select="concat(' builder.setAllowUnlimited(',
+ @allow-unlimited, ');
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@upper-limit)">
+ <xsl:value-of
+ select="concat(' builder.setUpperLimit(',
+ @upper-limit, ');
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@lower-limit)">
+ <xsl:value-of
+ select="concat(' builder.setLowerLimit(',
+ @lower-limit, ');
')" />
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/ip-address-mask.xsl b/opends/resource/admin/property-types/ip-address-mask.xsl
new file mode 100644
index 0000000..3bee7e3
--- /dev/null
+++ b/opends/resource/admin/property-types/ip-address-mask.xsl
@@ -0,0 +1,41 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing IP address mask properties.
+ -->
+ <xsl:template match="adm:ip-address-mask" mode="java-value-imports">
+ <import>org.opends.server.types.AddressMask</import>
+ </xsl:template>
+ <xsl:template match="adm:ip-address-mask" mode="java-value-type">
+ <xsl:value-of select="'AddressMask'" />
+ </xsl:template>
+ <xsl:template match="adm:ip-address-mask" mode="java-definition-type">
+ <xsl:value-of select="'IPAddressMaskPropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/ip-address.xsl b/opends/resource/admin/property-types/ip-address.xsl
new file mode 100644
index 0000000..7e61a98
--- /dev/null
+++ b/opends/resource/admin/property-types/ip-address.xsl
@@ -0,0 +1,41 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing IP address properties.
+ -->
+ <xsl:template match="adm:ip-address" mode="java-value-imports">
+ <import>java.net.InetAddress</import>
+ </xsl:template>
+ <xsl:template match="adm:ip-address" mode="java-value-type">
+ <xsl:value-of select="'InetAddress'" />
+ </xsl:template>
+ <xsl:template match="adm:ip-address" mode="java-definition-type">
+ <xsl:value-of select="'IPAddressPropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/java-class.xsl b/opends/resource/admin/property-types/java-class.xsl
new file mode 100644
index 0000000..0482f20
--- /dev/null
+++ b/opends/resource/admin/property-types/java-class.xsl
@@ -0,0 +1,52 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing java class properties.
+ -->
+ <xsl:template match="adm:java-class" mode="java-value-type">
+ <xsl:value-of select="'String'" />
+ </xsl:template>
+ <xsl:template match="adm:java-class" mode="java-definition-type">
+ <xsl:value-of select="'ClassPropertyDefinition'" />
+ </xsl:template>
+ <xsl:template match="adm:java-class" mode="java-definition-ctor">
+ <xsl:for-each select="adm:instance-of">
+ <!--
+ The first instance of element added to the definition
+ will become the primary type for the class. This first
+ element is guaranteed to be the first instance-of field
+ appearing in the property's definition heirarchy working
+ up from the bottom.
+ -->
+ <xsl:value-of
+ select="concat(' builder.addInstanceOf("',
+ normalize-space(), '");
')" />
+ </xsl:for-each>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/oid.xsl b/opends/resource/admin/property-types/oid.xsl
new file mode 100644
index 0000000..aead45f
--- /dev/null
+++ b/opends/resource/admin/property-types/oid.xsl
@@ -0,0 +1,38 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing OID properties.
+ -->
+ <xsl:template match="adm:oid" mode="java-value-type">
+ <xsl:value-of select="'String'" />
+ </xsl:template>
+ <xsl:template match="adm:oid" mode="java-definition-type">
+ <xsl:value-of select="'StringPropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/password.xsl b/opends/resource/admin/property-types/password.xsl
new file mode 100644
index 0000000..3b70d41
--- /dev/null
+++ b/opends/resource/admin/property-types/password.xsl
@@ -0,0 +1,38 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing password properties.
+ -->
+ <xsl:template match="adm:password" mode="java-value-type">
+ <xsl:value-of select="'String'" />
+ </xsl:template>
+ <xsl:template match="adm:password" mode="java-definition-type">
+ <xsl:value-of select="'StringPropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/size.xsl b/opends/resource/admin/property-types/size.xsl
new file mode 100644
index 0000000..86223b8
--- /dev/null
+++ b/opends/resource/admin/property-types/size.xsl
@@ -0,0 +1,58 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing size properties.
+ -->
+ <xsl:template match="adm:size" mode="java-value-type">
+ <xsl:value-of select="'Long'" />
+ </xsl:template>
+ <xsl:template match="adm:size" mode="java-value-primitive-type">
+ <xsl:value-of select="'long'" />
+ </xsl:template>
+ <xsl:template match="adm:size" mode="java-definition-type">
+ <xsl:value-of select="'SizePropertyDefinition'" />
+ </xsl:template>
+ <xsl:template match="adm:size" mode="java-definition-ctor">
+ <xsl:if test="boolean(@allow-unlimited)">
+ <xsl:value-of
+ select="concat(' builder.setAllowUnlimited(',
+ @allow-unlimited, ');
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@upper-limit)">
+ <xsl:value-of
+ select="concat(' builder.setUpperLimit("',
+ @upper-limit, '");
')" />
+ </xsl:if>
+ <xsl:if test="boolean(@lower-limit)">
+ <xsl:value-of
+ select="concat(' builder.setLowerLimit("',
+ @lower-limit, '");
')" />
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/property-types/string.xsl b/opends/resource/admin/property-types/string.xsl
new file mode 100644
index 0000000..c9ad8c9
--- /dev/null
+++ b/opends/resource/admin/property-types/string.xsl
@@ -0,0 +1,38 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ Templates for processing string properties.
+ -->
+ <xsl:template match="adm:string" mode="java-value-type">
+ <xsl:value-of select="'String'" />
+ </xsl:template>
+ <xsl:template match="adm:string" mode="java-definition-type">
+ <xsl:value-of select="'StringPropertyDefinition'" />
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/serverMO.xsl b/opends/resource/admin/serverMO.xsl
new file mode 100644
index 0000000..e090765
--- /dev/null
+++ b/opends/resource/admin/serverMO.xsl
@@ -0,0 +1,423 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0" xmlns:adm="http://www.opends.org/admin"
+ xmlns:admpp="http://www.opends.org/admin-preprocessor"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:import href="java-utilities.xsl" />
+ <xsl:import href="preprocessor.xsl" />
+ <xsl:import href="property-types.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Template for generating the interface declaration.
+ -->
+ <xsl:template name="generate-interface-declaration">
+ <xsl:value-of select="'/**
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content"
+ select="concat('A server-side interface for querying ', $this-ufn,
+ ' settings.')" />
+ </xsl:call-template>
+ <xsl:value-of select="' * <p>
'" />
+ <xsl:call-template name="add-java-comment">
+ <xsl:with-param name="indent-text" select="' *'" />
+ <xsl:with-param name="content" select="$this/adm:synopsis" />
+ </xsl:call-template>
+ <xsl:value-of select="' */
'" />
+ <xsl:value-of
+ select="concat('public interface ',
+ $this-java-class ,
+ 'Cfg extends ')" />
+ <xsl:choose>
+ <xsl:when test="boolean($this/@extends)">
+ <xsl:value-of select="concat($parent-java-class,'Cfg ')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'Configuration '" />
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>{
</xsl:text>
+ </xsl:template>
+ <!--
+ Template for generating the configuration definition getter.
+ -->
+ <xsl:template name="generate-configuration-definition-getter">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Get the configuration definition associated with this ', $this-ufn, '.
',
+ ' *
',
+ ' * @return Returns the configuration definition associated with this ', $this-ufn, '.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ManagedObjectDefinition<? extends ', $this-java-class,'CfgClient, ? extends ', $this-java-class,'Cfg> definition();
')" />
+ </xsl:template>
+ <!--
+ Template for generating the change listener declaration.
+ -->
+ <xsl:template name="generate-change-listener-declaration">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Register to be notified when this ', $this-ufn,' is changed.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $this-ufn,' configuration change listener.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void add', $this-short-java-class,
+ 'ChangeListener(ConfigurationChangeListener<',
+ $this-java-class,'Cfg> listener);
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Deregister an existing ', $this-ufn,' configuration change listener.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $this-ufn,' configuration change listener.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void remove', $this-short-java-class,
+ 'ChangeListener(ConfigurationChangeListener<',
+ $this-java-class,'Cfg> listener);
')" />
+ </xsl:template>
+ <!--
+ Template for generating the relation getter declarations.
+ -->
+ <xsl:template name="generate-relation-declarations">
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="ufn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-relation-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-class-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="@managed-object-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="adm:one-to-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Gets the ', $ufn,'.
',
+ ' *
',
+ ' * @return Returns the ', $ufn,'.
',
+ ' * @throws ConfigException
',
+ ' * If the ', $ufn,' could not be found or it could not
',
+ ' * be successfully decoded.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ', $java-class-name, 'Cfg get',
+ $java-relation-name, '() throws ConfigException;
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-zero-or-one">
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Determines whether or not the ', $ufn,' exists.
',
+ ' *
',
+ ' * @return Returns <true> if the ', $ufn,' exists.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' boolean has',
+ $java-relation-name, '();
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Gets the ', $ufn,' if it is present.
',
+ ' *
',
+ ' * @return Returns the ', $ufn,' if it is present.
',
+ ' * @throws ConfigException
',
+ ' * If the ', $ufn,' does not exist or it could not
',
+ ' * be successfully decoded.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ', $java-class-name, 'Cfg get',
+ $java-relation-name, '() throws ConfigException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Registers to be notified when the ', $ufn,' is added.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration add listener.
',
+ ' * @throws ConfigException
',
+ ' * If the add listener could not be registered.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void add', $java-relation-name,
+ 'AddListener(ConfigurationAddListener<',
+ $java-class-name,'Cfg> listener) throws ConfigException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Deregisters an existing ', $ufn,' configuration add listener.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration add listener.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void remove', $java-relation-name,
+ 'AddListener(ConfigurationAddListener<',
+ $java-class-name,'Cfg> listener);
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Registers to be notified the ', $ufn,' is deleted.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration delete listener.
',
+ ' * @throws ConfigException
',
+ ' * If the delete listener could not be registered.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void add', $java-relation-name,
+ 'DeleteListener(ConfigurationDeleteListener<',
+ $java-class-name,'Cfg> listener) throws ConfigException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Deregisters an existing ', $ufn,' configuration delete listener.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration delete listener.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void remove', $java-relation-name,
+ 'DeleteListener(ConfigurationDeleteListener<',
+ $java-class-name,'Cfg> listener);
')" />
+ </xsl:when>
+ <xsl:when test="adm:one-to-many">
+ <xsl:variable name="plural-name"
+ select="adm:one-to-many/@plural-name" />
+ <xsl:variable name="ufpn">
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$plural-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="java-relation-plural-name">
+ <xsl:call-template name="name-to-java">
+ <xsl:with-param name="value" select="$plural-name" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Lists the ', $ufpn, '.
',
+ ' *
',
+ ' * @return Returns an array containing the names of the
',
+ ' * ', $ufpn,'.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' String[] list', $java-relation-plural-name, '();
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Gets the named ', $ufn,'.
',
+ ' *
',
+ ' * @param name
',
+ ' * The name of the ',$ufn,' to retrieve.
',
+ ' * @return Returns the named ', $ufn,'.
',
+ ' * @throws ConfigException
',
+ ' * If the ', $ufn,' could not be found or it
',
+ ' * could not be successfully decoded.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' ', $java-class-name, 'Cfg get',
+ $java-relation-name, '(String name) throws ConfigException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Registers to be notified when new ', $ufpn,' are added.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration add listener.
',
+ ' * @throws ConfigException
',
+ ' * If the add listener could not be registered.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void add', $java-relation-name,
+ 'AddListener(ConfigurationAddListener<',
+ $java-class-name,'Cfg> listener) throws ConfigException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Deregisters an existing ', $ufn,' configuration add listener.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration add listener.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void remove', $java-relation-name,
+ 'AddListener(ConfigurationAddListener<',
+ $java-class-name,'Cfg> listener);
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Registers to be notified when existing ', $ufpn,' are deleted.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration delete listener.
',
+ ' * @throws ConfigException
',
+ ' * If the delete listener could not be registered.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void add', $java-relation-name,
+ 'DeleteListener(ConfigurationDeleteListener<',
+ $java-class-name,'Cfg> listener) throws ConfigException;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:value-of
+ select="concat(' /**
',
+ ' * Deregisters an existing ', $ufn,' configuration delete listener.
',
+ ' *
',
+ ' * @param listener
',
+ ' * The ', $ufn,' configuration delete listener.
',
+ ' */
')" />
+ <xsl:value-of
+ select="concat(' void remove', $java-relation-name,
+ 'DeleteListener(ConfigurationDeleteListener<',
+ $java-class-name,'Cfg> listener);
')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">
+ <xsl:value-of
+ select="concat('Unknown relation type "', local-name(*), '" in relation "', $name, '".')" />
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Main document parsing template.
+ -->
+ <xsl:template match="/">
+ <xsl:call-template name="copyright-notice" />
+ <xsl:value-of
+ select="concat('package ', $this-package, '.server;
')" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-import-statements">
+ <xsl:with-param name="imports">
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($this-package, '.client.', $this-java-class, 'CfgClient')" />
+ </xsl:element>
+ <xsl:for-each select="$this-local-properties">
+ <xsl:call-template name="get-property-java-imports" />
+ </xsl:for-each>
+ <xsl:if test="$this-local-properties[@multi-valued='true']">
+ <import>java.util.SortedSet</import>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test="$this/@extends">
+ <xsl:if test="$parent-package != $this-package">
+ <xsl:element name="import">
+ <xsl:value-of
+ select="concat($parent-package, '.server.', $parent-java-class, 'Cfg')" />
+ </xsl:element>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <import>org.opends.server.admin.Configuration</import>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:if test="not($this-is-root)">
+ <import>
+ org.opends.server.admin.server.ConfigurationChangeListener
+ </import>
+ </xsl:if>
+ <xsl:if test="$this-local-relations">
+ <import>org.opends.server.config.ConfigException</import>
+ </xsl:if>
+ <xsl:if
+ test="$this-local-relations/adm:one-to-zero-or-one|$this-local-relations/adm:one-to-many">
+ <import>
+ org.opends.server.admin.server.ConfigurationAddListener
+ </import>
+ <import>
+ org.opends.server.admin.server.ConfigurationDeleteListener
+ </import>
+ </xsl:if>
+ <import>org.opends.server.admin.ManagedObjectDefinition</import>
+ </xsl:with-param>
+ </xsl:call-template>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-interface-declaration" />
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-configuration-definition-getter" />
+ <xsl:if test="not($this-is-root)">
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-change-listener-declaration" />
+ </xsl:if>
+ <xsl:for-each select="$this-local-properties">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-property-getter-declaration">
+ <xsl:with-param name="interface" select="'server'" />
+ </xsl:call-template>
+ </xsl:for-each>
+ <xsl:for-each select="$this-local-relations">
+ <xsl:sort select="@name" />
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:text>
</xsl:text>
+ <xsl:call-template name="generate-relation-declarations" />
+ </xsl:for-each>
+ <xsl:text>
</xsl:text>
+ <xsl:text>}
</xsl:text>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/text-utilities.xsl b/opends/resource/admin/text-utilities.xsl
new file mode 100644
index 0000000..4c7d089
--- /dev/null
+++ b/opends/resource/admin/text-utilities.xsl
@@ -0,0 +1,187 @@
+<!--
+ ! 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.
+ ! -->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <!--
+ This XSLT file contains generic templates which can be used for any
+ application.
+ -->
+ <xsl:import href="abbreviations.xsl" />
+ <xsl:output method="text" encoding="us-ascii" />
+ <!--
+ Format a block of text. This template handles two levels of
+ indentation: the indentation string for the first line, and a
+ second indentation string used for subsequent lines. The template
+ will output the content wrapping at the nearest word boundary to
+ the specified column.
+
+ @param indent-text
+ The indentation text used for the first line.
+
+ @param indent-text2
+ The indentation text used for all lines except
+ the first - defaults to the value of indent-text.
+
+ @param content
+ The text to be formatted.
+
+ @param wrap-column
+ The text column before which text should be word
+ wrapped.
+ -->
+ <xsl:template name="format-text">
+ <xsl:param name="indent-text" />
+ <xsl:param name="indent-text2" select="$indent-text" />
+ <xsl:param name="wrap-column" />
+ <xsl:param name="content" />
+ <xsl:value-of select="$indent-text" />
+ <xsl:call-template name="format-text-help">
+ <xsl:with-param name="indent-text" select="$indent-text2" />
+ <xsl:with-param name="wrap-column" select="$wrap-column" />
+ <xsl:with-param name="content" select="normalize-space($content)" />
+ <xsl:with-param name="column"
+ select="string-length($indent-text) + 1" />
+ </xsl:call-template>
+ <xsl:text>
</xsl:text>
+ </xsl:template>
+ <!--
+ PRIVATE implementation template for format-text.
+ -->
+ <xsl:template name="format-text-help">
+ <xsl:param name="indent-text" />
+ <xsl:param name="wrap-column" />
+ <xsl:param name="content" />
+ <xsl:param name="column" />
+ <xsl:variable name="head" select="substring-before($content, ' ')" />
+ <xsl:variable name="tail" select="substring-after($content, ' ')" />
+ <xsl:if test="string-length($content)">
+ <xsl:choose>
+ <xsl:when test="string-length($head) = 0">
+ <xsl:if
+ test="(string-length($content) + $column) > $wrap-column">
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="$indent-text" />
+ </xsl:if>
+ <xsl:value-of select="' '" />
+ <xsl:value-of select="$content" />
+ </xsl:when>
+ <xsl:when
+ test="(string-length($head) + $column) > $wrap-column">
+ <xsl:text>
</xsl:text>
+ <xsl:value-of select="$indent-text" />
+ <xsl:value-of select="' '" />
+ <xsl:value-of select="$head" />
+ <xsl:call-template name="format-text-help">
+ <xsl:with-param name="indent-text" select="$indent-text" />
+ <xsl:with-param name="wrap-column" select="$wrap-column" />
+ <xsl:with-param name="content" select="$tail" />
+ <xsl:with-param name="column"
+ select="string-length($indent-text) + string-length($head) + 1" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="concat(' ', $head)" />
+ <xsl:call-template name="format-text-help">
+ <xsl:with-param name="indent-text" select="$indent-text" />
+ <xsl:with-param name="wrap-column" select="$wrap-column" />
+ <xsl:with-param name="content" select="$tail" />
+ <xsl:with-param name="column"
+ select="$column + string-length($head) + 1" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+ <!--
+ Convert a string to title-case or, if the string is a known
+ abbreviation, convert it to upper-case. For example, the string
+ "hello" will be converted to the string "Hello", but the string
+ "ldap" will be converted to "LDAP".
+
+ @param value
+ The string to be converted to title-case.
+ -->
+ <xsl:template name="to-title-case">
+ <xsl:param name="value" />
+ <xsl:variable name="is-abbreviation">
+ <xsl:call-template name="is-abbreviation">
+ <xsl:with-param name="value" select="$value" />
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <!-- Convert common abbreviations to uppercase -->
+ <xsl:when test="$is-abbreviation = 'true'">
+ <xsl:value-of
+ select="translate($value,
+ 'abcdefghijklmnopqrstuvwxyz',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="first" select="substring($value, 1, 1)" />
+ <xsl:variable name="remainder" select="substring($value, 2)" />
+ <xsl:variable name="first-upper"
+ select="translate($first,
+ 'abcdefghijklmnopqrstuvwxyz',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
+ <xsl:value-of select="concat($first-upper, $remainder)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+ <!--
+ Convert an entity or property ID to a user friendly mixed-cased
+ name. For example, the string "my-string-value" will be converted to
+ the string "My String Value".
+
+ @param value
+ The ID string to be converted to a Java name.
+ -->
+ <xsl:template name="name-to-ufn">
+ <xsl:param name="value" select="/.." />
+ <xsl:if test="string-length($value)">
+ <xsl:choose>
+ <xsl:when test="contains($value, '-')">
+ <xsl:variable name="head"
+ select="substring-before($value, '-')" />
+ <xsl:variable name="tail"
+ select="substring-after($value, '-')" />
+ <xsl:call-template name="to-title-case">
+ <xsl:with-param name="value" select="$head" />
+ </xsl:call-template>
+ <xsl:value-of select="' '" />
+ <xsl:call-template name="name-to-ufn">
+ <xsl:with-param name="value" select="$tail" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="to-title-case">
+ <xsl:with-param name="value" select="$value" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/opends/resource/admin/xml.xsd b/opends/resource/admin/xml.xsd
new file mode 100644
index 0000000..bb367cc
--- /dev/null
+++ b/opends/resource/admin/xml.xsd
@@ -0,0 +1,146 @@
+<?xml version="1.0"?>
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en">
+
+ <xs:annotation>
+ <xs:documentation>
+ See http://www.w3.org/XML/1998/namespace.html and
+ http://www.w3.org/TR/REC-xml for information about this namespace.
+
+ This schema document describes the XML namespace, in a form
+ suitable for import by other schema documents.
+
+ Note that local names in this namespace are intended to be defined
+ only by the World Wide Web Consortium or its subgroups. The
+ following names are currently defined in this namespace and should
+ not be used with conflicting semantics by any Working Group,
+ specification, or document instance:
+
+ base (as an attribute name): denotes an attribute whose value
+ provides a URI to be used as the base for interpreting any
+ relative URIs in the scope of the element on which it
+ appears; its value is inherited. This name is reserved
+ by virtue of its definition in the XML Base specification.
+
+ id (as an attribute name): denotes an attribute whose value
+ should be interpreted as if declared to be of type ID.
+ The xml:id specification is not yet a W3C Recommendation,
+ but this attribute is included here to facilitate experimentation
+ with the mechanisms it proposes. Note that it is _not_ included
+ in the specialAttrs attribute group.
+
+ lang (as an attribute name): denotes an attribute whose value
+ is a language code for the natural language of the content of
+ any element; its value is inherited. This name is reserved
+ by virtue of its definition in the XML specification.
+
+ space (as an attribute name): denotes an attribute whose
+ value is a keyword indicating what whitespace processing
+ discipline is intended for the content of the element; its
+ value is inherited. This name is reserved by virtue of its
+ definition in the XML specification.
+
+ Father (in any context at all): denotes Jon Bosak, the chair of
+ the original XML Working Group. This name is reserved by
+ the following decision of the W3C XML Plenary and
+ XML Coordination groups:
+
+ In appreciation for his vision, leadership and dedication
+ the W3C XML Plenary on this 10th day of February, 2000
+ reserves for Jon Bosak in perpetuity the XML name
+ xml:Father
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>This schema defines attributes and an attribute group
+ suitable for use by
+ schemas wishing to allow xml:base, xml:lang, xml:space or xml:id
+ attributes on elements they define.
+
+ To enable this, such a schema must import this schema
+ for the XML namespace, e.g. as follows:
+ <schema . . .>
+ . . .
+ <import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+
+ Subsequently, qualified reference to any of the attributes
+ or the group defined below will have the desired effect, e.g.
+
+ <type . . .>
+ . . .
+ <attributeGroup ref="xml:specialAttrs"/>
+
+ will define a type which will schema-validate an instance
+ element with any of those attributes</xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+ <xs:documentation>In keeping with the XML Schema WG's standard versioning
+ policy, this schema document will persist at
+ http://www.w3.org/2005/08/xml.xsd.
+ At the date of issue it can also be found at
+ http://www.w3.org/2001/xml.xsd.
+ The schema document at that URI may however change in the future,
+ in order to remain compatible with the latest version of XML Schema
+ itself, or with the XML namespace itself. In other words, if the XML
+ Schema or XML namespaces change, the version of this document at
+ http://www.w3.org/2001/xml.xsd will change
+ accordingly; the version at
+ http://www.w3.org/2005/08/xml.xsd will not change.
+ </xs:documentation>
+ </xs:annotation>
+
+ <xs:attribute name="lang">
+ <xs:annotation>
+ <xs:documentation>Attempting to install the relevant ISO 2- and 3-letter
+ codes as the enumerated possible values is probably never
+ going to be a realistic possibility. See
+ RFC 3066 at http://www.ietf.org/rfc/rfc3066.txt and the IANA registry
+ at http://www.iana.org/assignments/lang-tag-apps.htm for
+ further information.
+
+ The union allows for the 'un-declaration' of xml:lang with
+ the empty string.</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:union memberTypes="xs:language">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value=""/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="space">
+ <xs:simpleType>
+ <xs:restriction base="xs:NCName">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="preserve"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="base" type="xs:anyURI">
+ <xs:annotation>
+ <xs:documentation>See http://www.w3.org/TR/xmlbase/ for
+ information about this attribute.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="id" type="xs:ID">
+ <xs:annotation>
+ <xs:documentation>See http://www.w3.org/TR/xml-id/ for
+ information about this attribute.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+ <xs:attribute ref="xml:base"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute ref="xml:space"/>
+ </xs:attributeGroup>
+
+</xs:schema>
\ No newline at end of file
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/CertificateMapperConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/CertificateMapperConfiguration.xml
new file mode 100644
index 0000000..b816ada
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/CertificateMapperConfiguration.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="certificate-mapper"
+ plural-name="certificate-mappers"
+ package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ are responsible for establishing a mapping between a client certificate and
+ the entry for the user that corresponds to that certificate.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.12</ldap:oid>
+ <ldap:name>ds-cfg-certificate-mapper</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="enabled" mandatory="true">
+ <adm:synopsis>
+ Indicate whether the
+ <adm:user-friendly-name />
+ is enabled for use.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.20</ldap:oid>
+ <ldap:name>ds-cfg-certificate-mapper-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="mapper-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.api.CertificateMapper
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.19</ldap:oid>
+ <ldap:name>ds-cfg-certificate-mapper-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/ConnectionHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/ConnectionHandlerConfiguration.xml
new file mode 100644
index 0000000..026fd11
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/ConnectionHandlerConfiguration.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="connection-handler"
+ plural-name="connection-handlers"
+ package="org.opends.server.admin.std" abstract="true"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ are responsible for handling all interaction with the clients,
+ including accepting the connections, reading requests, and sending
+ responses.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.13</ldap:oid>
+ <ldap:name>ds-cfg-connection-handler</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="enabled" mandatory="true">
+ <adm:synopsis>
+ Indicate whether the
+ <adm:user-friendly-name />
+ is enabled for use.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.24</ldap:oid>
+ <ldap:name>ds-cfg-connection-handler-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="java-implementation-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.api.ConnectionHandler
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.23</ldap:oid>
+ <ldap:name>ds-cfg-connection-handler-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="allowed-clients" multi-valued="true">
+ <adm:synopsis>
+ This property specifies a set of address masks that may be used to
+ determine the addresses of the clients that are allowed to
+ establish connections to this connection handler.
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take effect
+ immediately but will not interfere with connections that may
+ already be established.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ All clients with addresses that do not match an address on the
+ deny list will be allowed.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:ip-address-mask />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.6</ldap:oid>
+ <ldap:name>ds-cfg-allowed-client</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="denied-clients" multi-valued="true">
+ <adm:synopsis>
+ This property specifies a set of address masks that may be used to
+ determine the addresses of the clients that are not allowed to
+ establish connections to this connection handler.
+ </adm:synopsis>
+ <adm:description>
+ If both allowed and denied client masks are defined and a client
+ connection matches one or more masks in both lists, then the
+ connection will be denied. If only a denied list is specified,
+ then any client not matching a mask in that list will be allowed.
+ Changes to this configuration attribute will take effect
+ immediately but will not interfere with connections that may
+ already be established.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ All clients with addresses that do match an address on the
+ allow list will be allowed.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:ip-address-mask />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.32</ldap:oid>
+ <ldap:name>ds-cfg-denied-client</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/CramMD5SASLMechanismHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/CramMD5SASLMechanismHandlerConfiguration.xml
new file mode 100644
index 0000000..39f22b5
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/CramMD5SASLMechanismHandlerConfiguration.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="cram-md5-sasl-mechanism-handler"
+ plural-name="cram-md5-sasl-mechanism-handlers"
+ package="org.opends.server.admin.std" extends="sasl-mechanism-handler"
+ 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 perform all processing related to SASL CRAM-MD5 authentication.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.46</ldap:oid>
+ <ldap:name>ds-cfg-cram-md5-sasl-mechanism-handler</ldap:name>
+ <ldap:superior>ds-cfg-sasl-mechanism-handler</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="identity-mapper-dn" mandatory="true">
+ <adm:synopsis>
+ Specifies the DN of the identity mapper to use.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the DN of the configuration entry for the identity mapper that
+ should be used to match the client authentication ID to a user entry.
+ </adm:description>
+ <adm:syntax>
+ <adm:dn>
+ <adm:base>cn=identity mappers,cn=config</adm:base>
+ </adm:dn>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.148</ldap:oid>
+ <ldap:name>ds-cfg-identity-mapper-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/DigestMD5SASLMechanismHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/DigestMD5SASLMechanismHandlerConfiguration.xml
new file mode 100644
index 0000000..6faf34e
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/DigestMD5SASLMechanismHandlerConfiguration.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="digest-md5-sasl-mechanism-handler"
+ plural-name="digest-md5-sasl-mechanism-handlers"
+ package="org.opends.server.admin.std" extends="sasl-mechanism-handler"
+ 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 perform all processing related to SASL DIGEST-MD5
+ authentication.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.47</ldap:oid>
+ <ldap:name>ds-cfg-digest-md5-sasl-mechanism-handler</ldap:name>
+ <ldap:superior>ds-cfg-sasl-mechanism-handler</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="realm" mandatory="false">
+ <adm:synopsis>
+ The realm that should be used for DIGEST-MD5 authentication.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the realm that should be used by the server for DIGEST-MD5
+ authentication. If this is not provided, then the server will default
+ to using a set of realm names that correspond to the defined suffixes.
+ Changes to this configuration attribute will take effect immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will default to a set of realm names that correspond to the
+ defined suffixes.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.86</ldap:oid>
+ <ldap:name>ds-cfg-realm</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="identity-mapper-dn" mandatory="true">
+ <adm:synopsis>
+ Specifies the DN of the identity mapper to use.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the DN of the configuration entry for the identity mapper that
+ should be used to match client authentication and authorization IDs to
+ user entries.
+ </adm:description>
+ <adm:syntax>
+ <adm:dn>
+ <adm:base>cn=identity mappers,cn=config</adm:base>
+ </adm:dn>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.148</ldap:oid>
+ <ldap:name>ds-cfg-identity-mapper-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/ExactMatchIdentityMapperConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/ExactMatchIdentityMapperConfiguration.xml
new file mode 100644
index 0000000..3523ce6
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/ExactMatchIdentityMapperConfiguration.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="exact-match-identity-mapper"
+ plural-name="exact-match-identity-mappers"
+ package="org.opends.server.admin.std" extends="identity-mapper"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The
+ <adm:user-friendly-name />
+ maps an identifier string to user entries by searching for the entry
+ containing a specified attribute whose value is the provided identifer.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.45</ldap:oid>
+ <ldap:name>ds-cfg-exact-match-identity-mapper</ldap:name>
+ <ldap:superior>ds-cfg-identity-mapper</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="match-attribute" mandatory="true" multi-valued="true">
+ <adm:synopsis>
+ Specifies the attribute to use to perform the mapping.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the name or OID of the attribute whose value should exactly
+ match the ID string provided to this identity mapper. At least one
+ value must be provided. All values must refer to the name or OID of an
+ attribute type defined in the Directory Server schema. If multiple
+ attribute type names or OIDs are provided, then at least one of those
+ attributes must contain the provided ID string value in exactly one
+ entry.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.146</ldap:oid>
+ <ldap:name>ds-cfg-match-attribute</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="match-base-dn" mandatory="false" multi-valued="true">
+ <adm:synopsis>
+ Specifies the set of base DNs below which to search for users.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the base DN(s) that should be used when performing searches to
+ map the provided ID string to a user entry. If no values are provided,
+ then the server will search below all public naming contexts.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will search below all public naming contexts.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:dn />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.147</ldap:oid>
+ <ldap:name>ds-cfg-match-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/ExternalSASLMechanismHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/ExternalSASLMechanismHandlerConfiguration.xml
new file mode 100644
index 0000000..e4119ef
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/ExternalSASLMechanismHandlerConfiguration.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="external-sasl-mechanism-handler"
+ plural-name="external-sasl-mechanism-handlers"
+ package="org.opends.server.admin.std" extends="sasl-mechanism-handler"
+ 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 perform all processing related to SASL EXTERNAL authentication.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.44</ldap:oid>
+ <ldap:name>ds-cfg-external-sasl-mechanism-handler</ldap:name>
+ <ldap:superior>ds-cfg-sasl-mechanism-handler</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="certificate-validation-policy" mandatory="true">
+ <adm:synopsis>
+ Indicates whether to attempt to validate the peer certificate against a
+ value held in the user's entry.
+ </adm:synopsis>
+ <adm:description>
+ Indicates whether the SASL EXTERNAL mechanism handler should attempt to
+ validate the peer certificate against a certificate in the corresponding
+ user's entry. The value must be one of "true" (which will always
+ attempt to validate the certificate and will fail if no certificates are
+ present), "false" (which will never attempt to validate the peer
+ certificate), and "ifpresent" (which will validate the peer certificate
+ if there are one or more certificates in the user's entry, but will not
+ fail if there are no certificates in the entry. Changes to this
+ configuration attribute will take effect immediately.
+ </adm:description>
+ <adm:syntax>
+ <adm:enumeration>
+ <adm:value name="always">
+ <adm:synopsis>
+ Always require the peer certificate to be present in the user's
+ entry.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="ifpresent">
+ <adm:synopsis>
+ If the user's entry contains one or more certificates, require that
+ one of them match the peer certificate.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="never">
+ <adm:synopsis>
+ Do not look for the peer certificate to be present in the user's
+ entry.
+ </adm:synopsis>
+ </adm:value>
+ </adm:enumeration>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.22</ldap:oid>
+ <ldap:name>ds-cfg-client-certificate-validation-policy</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="certificate-attribute" mandatory="false">
+ <adm:synopsis>
+ Specifies the attribute that should hold user certificates.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the name of the attribute that will be used to hold the
+ certificate information in user entries for the purpose of validation.
+ This must specify the name of a valid attribute type defined in the
+ server schema. Changes to this configuration attribute will take effect
+ immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>userCertificate</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.18</ldap:oid>
+ <ldap:name>ds-cfg-certificate-attribute</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="certificate-mapper-dn" mandatory="true">
+ <adm:synopsis>
+ Specifies the DN of the certificate mapper to use.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the DN of the configuration entry for the certificate mapper
+ that should be used to match client certificates to user entries.
+ </adm:description>
+ <adm:syntax>
+ <adm:dn>
+ <adm:base>cn=certificate mappers,cn=config</adm:base>
+ </adm:dn>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.309</ldap:oid>
+ <ldap:name>ds-cfg-certificate-mapper-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/FileBasedKeyManagerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/FileBasedKeyManagerConfiguration.xml
new file mode 100644
index 0000000..2e3fbf5
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/FileBasedKeyManagerConfiguration.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="file-based-key-manager"
+ plural-name="file-based-key-managers"
+ package="org.opends.server.admin.std" extends="key-manager"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:TODO>
+ The key manager must be able to get a pin from somewhere. It looks
+ in property, then an environment variable, then a file, and finally
+ in a configuration attribute. At least one must be present. Can we
+ express this ordering and this "at least one" constraint? Perhaps
+ support a "one-of" element which can be used to group a set of
+ properties.
+ </adm:TODO>
+ <adm:synopsis>
+ The
+ <adm:user-friendly-name />
+ provider accesses key information in a file on the local filesystem.
+ Multiple file formats may be supported, depending on the providers
+ supported by the underlying Java runtime.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.20</ldap:oid>
+ <ldap:name>ds-cfg-file-based-key-manager-provider</ldap:name>
+ <ldap:superior>ds-cfg-key-manager-provider</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="key-store-file" mandatory="true">
+ <adm:TODO>Should use a file-based property definition?</adm:TODO>
+ <adm:synopsis>
+ Specifies the path to the file containing the private key
+ information. It may be an absolute path, or a path that is
+ relative to the
+ <adm:product-name />
+ instance root.
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take effect the next
+ time that the key manager is accessed.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.50</ldap:oid>
+ <ldap:name>ds-cfg-key-store-file</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-store-type">
+ <adm:TODO>
+ Can we restrict this to an enumeration? How can the client guess
+ which values are possible? What is the default value?
+ </adm:TODO>
+ <adm:synopsis>
+ Specifies the format for the data in the key store file.
+ </adm:synopsis>
+ <adm:description>
+ Valid values should always include 'JKS' and 'PKCS12', but
+ different implementations may allow other values as well. If no
+ value is provided, then the JVM-default value will be used.
+ Changes to this configuration attribute will take effect the next
+ time that the key manager is accessed.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.55</ldap:oid>
+ <ldap:name>ds-cfg-key-store-type</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property-reference name="key-store-pin" />
+ <adm:property-reference name="key-store-pin-property" />
+ <adm:property-reference name="key-store-pin-environment-variable" />
+ <adm:property-reference name="key-store-pin-file" />
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/FingerprintCertificateMapperConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/FingerprintCertificateMapperConfiguration.xml
new file mode 100644
index 0000000..31b5463
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/FingerprintCertificateMapperConfiguration.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="fingerprint-certificate-mapper"
+ plural-name="fingerprint-certificate-mappers"
+ package="org.opends.server.admin.std" extends="certificate-mapper"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The
+ <adm:user-friendly-name />
+ maps client certificates to user entries by looking for the MD5 or SHA1
+ fingerprint in a specified attribute of user entries.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.86</ldap:oid>
+ <ldap:name>ds-cfg-fingerprint-certificate-mapper</ldap:name>
+ <ldap:superior>ds-cfg-certificate-mapper</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="fingerprint-attribute" mandatory="true">
+ <adm:synopsis>
+ Specifies the attribute in which to look for the fingerprint.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the name or OID of the attribute whose value should exactly
+ match the MD5 or SHA1 representation of the certificate fingerprint.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.317</ldap:oid>
+ <ldap:name>ds-cfg-certificate-fingerprint-attribute-type</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="fingerprint-algorithm" mandatory="true">
+ <adm:synopsis>
+ Specifies the certificate fingerprint algorithm.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the name of the digest algorithm that should be used to
+ compute the fingerprint of client certificates. The value must be either
+ "MD5" or "SHA1".
+ </adm:description>
+ <adm:syntax>
+ <adm:enumeration>
+ <adm:value name="md5">
+ <adm:synopsis>
+ Use the MD5 digest algorithm to compute certificate fingerprints.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="sha1">
+ <adm:synopsis>
+ Use the SHA-1 digest algorithm to compute certificate fingerprints.
+ </adm:synopsis>
+ </adm:value>
+ </adm:enumeration>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.318</ldap:oid>
+ <ldap:name>ds-cfg-certificate-fingerprint-algorithm</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="user-base-dn" mandatory="false" multi-valued="true">
+ <adm:synopsis>
+ Specifies the set of base DNs below which to search for users.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the base DN(s) that should be used when performing searches to
+ map the client certificate to a user entry. If no values are provided,
+ then the server will search below all public naming contexts.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will perform the search in all public naming contexts.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:dn />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.313</ldap:oid>
+ <ldap:name>ds-cfg-certificate-user-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/GSSAPISASLMechanismHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/GSSAPISASLMechanismHandlerConfiguration.xml
new file mode 100644
index 0000000..4556da3
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/GSSAPISASLMechanismHandlerConfiguration.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="gssapi-sasl-mechanism-handler"
+ plural-name="gssapi-sasl-mechanism-handlers"
+ package="org.opends.server.admin.std" extends="sasl-mechanism-handler"
+ 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 perform all processing related to SASL GSSAPI authentication
+ using Kerberos V5.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.48</ldap:oid>
+ <ldap:name>ds-cfg-gssapi-sasl-mechanism-handler</ldap:name>
+ <ldap:superior>ds-cfg-sasl-mechanism-handler</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="realm" mandatory="false">
+ <adm:synopsis>
+ Specifies the realm that should be used for GSSAPI authentication.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the realm that should be used by the server for GSSAPI
+ authentication. If this is not provided, then the server will attempt to
+ determine the realm from the Kerberos configuration of the underlying
+ system. Changes to this configuration attribute will take effect
+ immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will attempt to determine the realm from the underlying
+ system configuration.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.86</ldap:oid>
+ <ldap:name>ds-cfg-realm</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="kdc-address" mandatory="false">
+ <adm:synopsis>
+ Specifies the address of the KDC that should be used for Kerberos
+ processing.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the address of the KDC that should be used for Kerberos
+ processing. If provided, this should be a fully-qualified DNS-resolvable
+ name. If this is not provided, then the server will attempt to determine
+ the KDC address from the Kerberos configuration of the underlying system.
+ Changes to this configuration attribute will take effect immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will attempt to determine the KDC address from the
+ underlying system configuration.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.45</ldap:oid>
+ <ldap:name>ds-cfg-kdc-address</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="keytab" mandatory="false">
+ <adm:synopsis>
+ Specifies the path to the keytab file that should be used for Kerberos
+ processing.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the path to the keytab file that should be used for Kerberos
+ processing. If provided, this should be either an absolute path or one
+ that is relative to the server instance root. If this is not provided,
+ then the server will attempt to use the default keytab from the
+ underlying system configuration. Changes to this configuration attribute
+ will take effect immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will attempt to use the system-wide default keytab.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.46</ldap:oid>
+ <ldap:name>ds-cfg-keytab</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="server-fqdn" mandatory="false">
+ <adm:synopsis>
+ Specifies the fully-qualified domain name for the system.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the DNS-resolvable fully-qualified domain name for the system.
+ If this is not provided, then the server will attempt to determine this
+ dynamically. Changes to this configuration attribute will take effect
+ immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will attempt to dynamically determine the fully-qualified
+ domain name.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.115</ldap:oid>
+ <ldap:name>ds-cfg-server-fqdn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="identity-mapper-dn" mandatory="true">
+ <adm:synopsis>
+ Specifies the DN of the identity mapper to use.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the DN of the configuration entry for the identity mapper that
+ should be used to match the Kerberos principal to a user entry.
+ </adm:description>
+ <adm:syntax>
+ <adm:dn>
+ <adm:base>cn=identity mappers,cn=config</adm:base>
+ </adm:dn>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.148</ldap:oid>
+ <ldap:name>ds-cfg-identity-mapper-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
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
new file mode 100644
index 0000000..42b2ce2
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="global" plural-name="globals"
+ package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The global configuration contains properties that affect the overall
+ operation of the
+ <adm:product-name />
+ .
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.13</ldap:oid>
+ <ldap:name>ds-cfg-root-config</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="check-schema" mandatory="true">
+ <adm:synopsis>
+ Indicates whether schema enforcement is active.
+ </adm:synopsis>
+ <adm:description>
+ This property indicates whether the
+ <adm:product-name />
+ should ensure that all operations result in entries that are valid
+ according to the defined server schema. It is strongly recommended
+ that this option be left enabled to prevent the inadvertent
+ addition of invalid data into the server.
+ </adm:description>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.24</ldap:oid>
+ <ldap:name>ds-cfg-check-schema</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/IdentityMapperConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/IdentityMapperConfiguration.xml
new file mode 100644
index 0000000..669c0ff
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/IdentityMapperConfiguration.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="identity-mapper"
+ plural-name="identity-mappers"
+ package="org.opends.server.admin.std" abstract="true"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ are responsible for establishing a mapping between an identifier string and
+ the entry for the user that corresponds to that identifier.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.55</ldap:oid>
+ <ldap:name>ds-cfg-identity-mapper</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="enabled" mandatory="true">
+ <adm:synopsis>
+ Indicate whether the
+ <adm:user-friendly-name />
+ is enabled for use.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.145</ldap:oid>
+ <ldap:name>ds-cfg-identity-mapper-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="mapper-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.api.IdentityMapper
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.144</ldap:oid>
+ <ldap:name>ds-cfg-identity-mapper-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
new file mode 100644
index 0000000..9dc8978
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="jmx-connection-handler"
+ plural-name="jmx-connection-handlers"
+ package="org.opends.server.admin.std" extends="connection-handler"
+ 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 interact with clients using the Java Management
+ Extensions (JMX) protocol.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.63</ldap:oid>
+ <ldap:name>ds-cfg-jmx-connection-handler</ldap:name>
+ <ldap:superior>ds-cfg-connection-handler</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property-reference name="listen-port" />
+ <adm:property-reference name="use-ssl" />
+ <adm:property-reference name="ssl-cert-nickname" />
+ <adm:property-reference name="key-manager-provider-dn" />
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/KeyManagerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/KeyManagerConfiguration.xml
new file mode 100644
index 0000000..4036272
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/KeyManagerConfiguration.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="key-manager" plural-name="key-managers"
+ package="org.opends.server.admin.std" abstract="true"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ are responsible for managing the key material which is used to
+ authenticate an SSL connection to its peer.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.19</ldap:oid>
+ <ldap:name>ds-cfg-key-manager-provider</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="enabled" mandatory="true">
+ <adm:synopsis>
+ Indicate whether the
+ <adm:user-friendly-name />
+ is enabled for use.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.49</ldap:oid>
+ <ldap:name>ds-cfg-key-manager-provider-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="java-implementation-class" mandatory="true">
+ <adm:synopsis>
+ The fully-qualified name of the Java class that should to provide
+ the
+ <adm:user-friendly-name />
+ implementation.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:java-class>
+ <adm:instance-of>
+ org.opends.server.api.KeyManagerProvider
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.48</ldap:oid>
+ <ldap:name>ds-cfg-key-manager-provider-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml
new file mode 100644
index 0000000..21a63c4
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml
@@ -0,0 +1,460 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="ldap-connection-handler"
+ plural-name="ldap-connection-handlers"
+ package="org.opends.server.admin.std" extends="connection-handler"
+ 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 interact with clients using LDAP. In particular, it
+ provides full support for LDAPv3 and limited support for LDAPv2.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.14</ldap:oid>
+ <ldap:name>ds-cfg-ldap-connection-handler</ldap:name>
+ <ldap:superior>ds-cfg-connection-handler</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property-reference name="listen-port" />
+ <adm:property-reference name="use-ssl" />
+ <adm:property-reference name="ssl-cert-nickname" />
+ <adm:property-reference name="key-manager-provider-dn" />
+ <adm:property-reference name="trust-manager-provider-dn" />
+ <adm:property name="listen-addresses" multi-valued="true">
+ <adm:synopsis>
+ Specifies the address or set of addresses on which this
+ <adm:user-friendly-name />
+ should listen for connections from LDAP clients.
+ </adm:synopsis>
+ <adm:description>
+ Multiple addresses may be provided as separate values for this
+ attribute. If no values are provided, then the
+ <adm:user-friendly-name />
+ will listen on all interfaces.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>0.0.0.0</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:ip-address />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.56</ldap:oid>
+ <ldap:name>ds-cfg-listen-address</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="allow-ldap-v2">
+ <adm:synopsis>
+ Indicates whether connections from LDAPv2 clients will be allowed.
+ </adm:synopsis>
+ <adm:description>
+ If LDAPv2 clients will be allowed, then only a minimal degree of
+ special support will be provided for them to ensure that
+ LDAPv3-specific protocol elements (e.g., Configuration Guide 25
+ controls, extended response messages, intermediate response
+ messages, referrals, etc.) are not sent to an LDAPv2 client.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.7</ldap:oid>
+ <ldap:name>ds-cfg-allow-ldapv2</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="keep-stats">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ should keep statistics.
+ </adm:synopsis>
+ <adm:description>
+ If enabled, the
+ <adm:user-friendly-name />
+ will maintain statistics about the number and types of operations
+ requested over LDAP and the amount of data sent and received.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.47</ldap:oid>
+ <ldap:name>ds-cfg-keep-stats</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="use-tcp-keep-alive">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ should use TCP keep-alive.
+ </adm:synopsis>
+ <adm:description>
+ If enabled, the SO_KEEPALIVE socket option to indicate that TCP
+ keepalive messages should periodically be sent to the client to
+ verify that the associated connection is still valid. This may
+ also help prevent cases in which intermediate network hardware
+ could silently drop an otherwise idle client connection, provided
+ that the keepalive interval configured in the underlying operating
+ system is smaller than the timeout enforced by the network
+ hardware.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.138</ldap:oid>
+ <ldap:name>ds-cfg-use-tcp-keepalive</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="use-tcp-no-delay">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ should use TCP no-delay.
+ </adm:synopsis>
+ <adm:description>
+ If enabled, the TCP_NODELAY socket option will be used to ensure
+ that response messages to the client are sent immediately rather
+ than potentially waiting to determine whether additional response
+ messages can be sent in the same packet. In most cases, using the
+ TCP_NODELAY socket option will provide better performance and
+ lower response times, but disabling it may help for some cases in
+ which the server will send a large number of entries to a client
+ in response to a search request.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.139</ldap:oid>
+ <ldap:name>ds-cfg-use-tcp-nodelay</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="allow-tcp-reuse-address">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ should reuse socket descriptors.
+ </adm:synopsis>
+ <adm:description>
+ If enabled, the SO_REUSEADDR socket option will be used on the
+ server listen socket to potentially allow the reuse of socket
+ descriptors for clients in a TIME_WAIT state. This may help the
+ server avoid temporarily running out of socket descriptors in
+ cases in which a very large number of short-lived connections have
+ been established from the same client system.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.9</ldap:oid>
+ <ldap:name>ds-cfg-allow-tcp-reuse-address</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="send-rejection-notice">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ should send a notice of disconnection extended response message to
+ the client if a new connection is rejected for some reason.
+ </adm:synopsis>
+ <adm:description>
+ The extended response message may provide an explanation
+ indicating the reason that the connection was rejected.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.114</ldap:oid>
+ <ldap:name>ds-cfg-send-rejection-notice</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="max-request-size">
+ <adm:synopsis>
+ Specifies the size of the largest LDAP request message that will
+ be allowed by this
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ This property is analogous to the maxBERSize configuration
+ attribute of the Sun Java System Directory Server. This can help
+ prevent denial-of-service attacks by clients that indicate they
+ will send extremely large requests to the server causing it to
+ attempt to allocate large amounts of memory.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>5mib</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:size upper-limit="2147483647b"></adm:size>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.67</ldap:oid>
+ <ldap:name>ds-cfg-max-request-size</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="num-request-handlers">
+ <adm:synopsis>
+ Specifies the number of request handlers that will be used to read
+ requests from clients.
+ </adm:synopsis>
+ <adm:description>
+ The
+ <adm:user-friendly-name />
+ uses one thread to accept new connections from clients, but uses
+ one or more additional threads to read requests from existing
+ client connections. This can help ensure that new requests are
+ read efficiently and that the connection handler itself does not
+ become a bottleneck when the server is under heavy load from many
+ clients at the same time.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>1</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:integer lower-limit="1" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.72</ldap:oid>
+ <ldap:name>ds-cfg-num-request-handlers</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="allow-start-tls">
+ <adm:synopsis>
+ Indicates whether clients will be allowed to use StartTLS.
+ </adm:synopsis>
+ <adm:description>
+ If enabled, the
+ <adm:user-friendly-name />
+ will allow clients to use the StartTLS extended operation to
+ initiate secure communication over an otherwise insecure channel.
+ Note that this will only be allowed if the
+ <adm:user-friendly-name />
+ is not configured to use SSL, and if the server is configured with
+ a valid key manager provider and a valid trust manager provider.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.8</ldap:oid>
+ <ldap:name>ds-cfg-allow-start-tls</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="ssl-client-auth-policy">
+ <adm:synopsis>
+ Specifies the policy that the
+ <adm:user-friendly-name />
+ should use regarding client SSL certificates.
+ </adm:synopsis>
+ <adm:description>
+ This is only applicable if clients are allowed to use SSL.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>optional</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:enumeration>
+ <adm:value name="disabled">
+ <adm:synopsis>
+ Clients will not be required to provide their own
+ certificates when performing SSL negotiation.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="optional">
+ <adm:synopsis>
+ Clients will be requested to provide their own certificates
+ when performing SSL negotiation, but will still accept the
+ connection even if the client does not provide a
+ certificate.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="required">
+ <adm:synopsis>
+ Clients will be required to provide their own certificates
+ when performing SSL negotiation, and will be refused access
+ if the do not provide a certificate.
+ </adm:synopsis>
+ </adm:value>
+ </adm:enumeration>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.119</ldap:oid>
+ <ldap:name>ds-cfg-ssl-client-auth-policy</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="accept-backlog">
+ <adm:synopsis>
+ Specifies the maximum number of pending connection attempts that
+ will be allowed to queue up in the accept backlog before the
+ server starts rejecting new connection attempts.
+ </adm:synopsis>
+ <adm:description>
+ This is primarily an issue for cases in which a large number of
+ connections are established to the server in a very short period
+ of time (e.g., a benchmark utility that creates a large number of
+ client threads that each have their own connection to the server)
+ and the connection handler is unable to keep up with the rate at
+ which the new connections are established.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>128</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:integer lower-limit="1">
+ <adm:unit-synopsis>connections</adm:unit-synopsis>
+ </adm:integer>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.153</ldap:oid>
+ <ldap:name>ds-cfg-accept-backlog</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="ssl-protocols" multi-valued="true">
+ <adm:TODO>No LDAP OID is assigned for this yet!</adm:TODO>
+ <adm:synopsis>
+ Specifies the names of the SSL protocols that will be allowed for
+ use in SSL or StartTLS communication.
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take immediately but
+ will only impact new SSL/TLS-based sessions created after the
+ change.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ Uses the default set of SSL protocols provided by the server's
+ JVM.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.9999</ldap:oid>
+ <ldap:name>ds-cfg-ssl-protocols</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="ssl-cipher-suites" multi-valued="true">
+ <adm:TODO>No LDAP OID is assigned for this yet!</adm:TODO>
+ <adm:synopsis>
+ Specifies the names of the SSL cipher suites that will be allowed
+ for use in SSL or StartTLS communication.
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take immediately but
+ will only impact new SSL/TLS-based sessions created after the
+ change.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ Uses the default set of SSL cipher suites provided by the
+ server's JVM.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.9999</ldap:oid>
+ <ldap:name>ds-cfg-ssl-protocols</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/LengthBasedPasswordValidatorConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/LengthBasedPasswordValidatorConfiguration.xml
new file mode 100644
index 0000000..9711781
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/LengthBasedPasswordValidatorConfiguration.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="length-based-password-validator"
+ plural-name="length-based-password-validators"
+ package="org.opends.server.admin.std" extends="password-validator"
+ 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 determine whether a proposed password is acceptable based on
+ whether the number of characters it contains falls within an acceptable
+ range of values.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.59</ldap:oid>
+ <ldap:name>ds-cfg-length-based-password-validator</ldap:name>
+ <ldap:superior>ds-cfg-password-validator</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="maximum-password-length" mandatory="false">
+ <adm:synopsis>
+ Specifies the maximum number of characters that may be included in a
+ proposed password.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the maximum number of characters that may be included in a
+ proposed password. A value of zero indicates that there will be no
+ upper bound enforced. Changes to this configuration attribute will take
+ effect immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>0</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:integer lower-limit="0" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.168</ldap:oid>
+ <ldap:name>ds-cfg-maximum-password-length</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="minimum-password-length" mandatory="false">
+ <adm:synopsis>
+ Specifies the minimum number of characters that must be included in a
+ proposed password.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the minimum number of characters that must be included in a
+ proposed password. A value of zero indicates that there will be no
+ lower bound enforced. Changes to this configuration attribute will take
+ effect immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>1</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:integer lower-limit="0" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.169</ldap:oid>
+ <ldap:name>ds-cfg-minimum-password-length</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PKCS11KeyManagerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PKCS11KeyManagerConfiguration.xml
new file mode 100644
index 0000000..451bd6e
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PKCS11KeyManagerConfiguration.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="pkcs11-key-manager"
+ plural-name="pkcs11-key-managers"
+ package="org.opends.server.admin.std" extends="key-manager"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:TODO>
+ The key manager must be able to get a pin from somewhere. It looks
+ in property, then an environment variable, then a file, and finally
+ in a configuration attribute. At least one must be present. Can we
+ express this ordering and this "at least one" constraint? Perhaps
+ support a "one-of" element which can be used to group a set of
+ properties.
+ </adm:TODO>
+ <adm:synopsis>
+ The
+ <adm:user-friendly-name />
+ provider provides the ability for the server to access the private
+ key information through the PKCS11 interface. This standard
+ interface is used by cryptographic accelerators and hardware
+ security modules.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.21</ldap:oid>
+ <ldap:name>ds-cfg-pkcs11-key-manager-provider</ldap:name>
+ <ldap:superior>ds-cfg-key-manager-provider</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property-reference name="key-store-pin" />
+ <adm:property-reference name="key-store-pin-property" />
+ <adm:property-reference name="key-store-pin-environment-variable" />
+ <adm:property-reference name="key-store-pin-file" />
+</adm:managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/Package.xml b/opends/src/admin/defn/org/opends/server/admin/std/Package.xml
new file mode 100644
index 0000000..780c11f
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/Package.xml
@@ -0,0 +1,245 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:package name="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ Core OpenDS Directory Server administrative components.
+ </adm:synopsis>
+ <adm:property name="listen-port" mandatory="true">
+ <adm:synopsis>
+ Specifies the port number on which the
+ <adm:user-friendly-name />
+ will listen for connections from clients.
+ </adm:synopsis>
+ <adm:description>
+ Only a single port number may be provided.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:syntax>
+ <adm:integer lower-limit="1" upper-limit="65535" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.57</ldap:oid>
+ <ldap:name>ds-cfg-listen-port</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="use-ssl">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ should use SSL.
+ </adm:synopsis>
+ <adm:description>
+ If enabled, the
+ <adm:user-friendly-name />
+ will use SSL to encrypt communication with the clients.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>false</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.137</ldap:oid>
+ <ldap:name>ds-cfg-use-ssl</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="ssl-cert-nickname">
+ <adm:TODO>Need a better default description.</adm:TODO>
+ <adm:synopsis>
+ Specifies the nickname (also called the alias) of the certificate
+ that the
+ <adm:user-friendly-name />
+ should use when performing SSL communication.
+ </adm:synopsis>
+ <adm:description>
+ This is only applicable when the
+ <adm:user-friendly-name />
+ is configured to use SSL.
+ </adm:description>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ Let the server decide.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string></adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.120</ldap:oid>
+ <ldap:name>ds-cfg-ssl-cert-nickname</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-store-pin">
+ <adm:synopsis>
+ Specifies the clear-text PIN needed to access the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take effect the next
+ time that the key manager is accessed.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>jks</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.51</ldap:oid>
+ <ldap:name>ds-cfg-key-store-pin</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-store-pin-property">
+ <adm:TODO>Better syntax for property name?</adm:TODO>
+ <adm:synopsis>
+ Specifies the name of the Java property that contains the
+ clear-text PIN needed to access the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take effect the next
+ time that the key manager is accessed.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.54</ldap:oid>
+ <ldap:name>ds-cfg-key-store-pin-property</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-store-pin-environment-variable">
+ <adm:synopsis>
+ Specifies the name of the environment variable that contains the
+ clear-text PIN needed to access the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take effect the next
+ time that the key manager is accessed.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.52</ldap:oid>
+ <ldap:name>ds-cfg-key-store-pin-environment-variable</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-store-pin-file">
+ <adm:TODO>Should use a file-based property definition?</adm:TODO>
+ <adm:synopsis>
+ Specifies the path to the text file whose only contents should be
+ a single line containing the clear-text PIN needed to access the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ Changes to this configuration attribute will take effect the next
+ time that the key manager is accessed.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.53</ldap:oid>
+ <ldap:name>ds-cfg-key-store-pin-file</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-manager-provider-dn">
+ <adm:synopsis>
+ Specifies the DN of the configuration entry for the key manager
+ provider that should be used with this
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ Changes to this attribute will take effect immediately, but only
+ for subsequent attempts to access the key manager provider for
+ associated client connections.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:dn>
+ <adm:base>cn=key manager providers,cn=config</adm:base>
+ </adm:dn>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.310</ldap:oid>
+ <ldap:name>ds-cfg-key-manager-provider-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="trust-manager-provider-dn">
+ <adm:synopsis>
+ Specifies the DN of the configuration entry for the trust manager
+ provider that should be used with this
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ Changes to this attribute will take effect immediately, but only
+ for subsequent attempts to access the trust manager provider for
+ associated client connections.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:dn>
+ <adm:base>cn=trust manager providers,cn=config</adm:base>
+ </adm:dn>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.311</ldap:oid>
+ <ldap:name>ds-cfg-trust-manager-provider-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:package>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PasswordValidatorConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PasswordValidatorConfiguration.xml
new file mode 100644
index 0000000..1b58a9e
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PasswordValidatorConfiguration.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="password-validator" plural-name="password-validators"
+ package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ are responsible for determining whether proposed passwords are acceptable
+ for use.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.36</ldap:oid>
+ <ldap:name>ds-cfg-password-validator</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="enabled" mandatory="true">
+ <adm:synopsis>
+ Indicate whether the
+ <adm:user-friendly-name />
+ is enabled for use.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.78</ldap:oid>
+ <ldap:name>ds-cfg-password-validator-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="validator-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.api.PasswordValidator
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.77</ldap:oid>
+ <ldap:name>ds-cfg-password-validator-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PlainSASLMechanismHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PlainSASLMechanismHandlerConfiguration.xml
new file mode 100644
index 0000000..d57ec42
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PlainSASLMechanismHandlerConfiguration.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="plain-sasl-mechanism-handler"
+ plural-name="plain-sasl-mechanism-handlers"
+ package="org.opends.server.admin.std" extends="sasl-mechanism-handler"
+ 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 perform all processing related to SASL PLAIN authentication.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.45</ldap:oid>
+ <ldap:name>ds-cfg-plain-sasl-mechanism-handler</ldap:name>
+ <ldap:superior>ds-cfg-sasl-mechanism-handler</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="identity-mapper-dn" mandatory="true">
+ <adm:synopsis>
+ Specifies the DN of the identity mapper to use.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the DN of the configuration entry for the identity mapper that
+ should be used to match client authentication and authorization IDs to
+ user entries.
+ </adm:description>
+ <adm:syntax>
+ <adm:dn>
+ <adm:base>cn=identity mappers,cn=config</adm:base>
+ </adm:dn>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.148</ldap:oid>
+ <ldap:name>ds-cfg-identity-mapper-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
new file mode 100644
index 0000000..076ccf6
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
@@ -0,0 +1,309 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="plugin"
+ plural-name="plugins"
+ package="org.opends.server.admin.std" abstract="false"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ provide a mechanism for executing custom code at specified points in
+ operation processing and in the course of other events like connection
+ establishment and termination, server startup and shutdown, and LDIF import
+ and export.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.37</ldap:oid>
+ <ldap:name>ds-cfg-plugin</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="enabled" mandatory="true">
+ <adm:synopsis>
+ Indicate whether the
+ <adm:user-friendly-name />
+ is enabled for use.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.80</ldap:oid>
+ <ldap:name>ds-cfg-plugin-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="plugin-class" mandatory="true">
+ <adm:synopsis>
+ The fully-qualified name of the Java class that provides the
+ <adm:user-friendly-name />
+ implementation.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:java-class>
+ <adm:instance-of>
+ org.opends.server.api.plugin.DirectoryServerPlugin
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.79</ldap:oid>
+ <ldap:name>ds-cfg-plugin-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="plugin-type" mandatory="true" multi-valued="true">
+ <adm:synopsis>
+ The plugin types, which define the conditions under which this plugin
+ should be invoked.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:enumeration>
+ <adm:value name="startup">
+ <adm:synopsis>
+ Invoked during the Directory Server startup process.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="shutdown">
+ <adm:synopsis>
+ Invoked during a graceful Directory Server shutdown.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postconnect">
+ <adm:synopsis>
+ Invoked whenever a new connection is established to the server.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postdisconnect">
+ <adm:synopsis>
+ Invoked whenever an existing connection is terminated (by either
+ the client or the server).
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="ldifimport">
+ <adm:synopsis>
+ Invoked for each entry read during an LDIF import.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="ldifexport">
+ <adm:synopsis>
+ Invoked for each operation to be written during an LDIF export.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparseabandon">
+ <adm:synopsis>
+ Invoked prior to parsing an abandon request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparseadd">
+ <adm:synopsis>
+ Invoked prior to parsing an add request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparsebind">
+ <adm:synopsis>
+ Invoked prior to parsing a bind request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparsecompare">
+ <adm:synopsis>
+ Invoked prior to parsing a compare request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparsedelete">
+ <adm:synopsis>
+ Invoked prior to parsing a delete request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparseextended">
+ <adm:synopsis>
+ Invoked prior to parsing an extended request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparsemodify">
+ <adm:synopsis>
+ Invoked prior to parsing a modify request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparsemodifydn">
+ <adm:synopsis>
+ Invoked prior to parsing a modify DN request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparsesearch">
+ <adm:synopsis>
+ Invoked prior to parsing a search request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preparseunbind">
+ <adm:synopsis>
+ Invoked prior to parsing an unbind request.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationadd">
+ <adm:synopsis>
+ Invoked prior to performing the core add processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationbind">
+ <adm:synopsis>
+ Invoked prior to performing the core bind processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationcompare">
+ <adm:synopsis>
+ Invoked prior to performing the core compare processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationdelete">
+ <adm:synopsis>
+ Invoked prior to performing the core delete processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationextended">
+ <adm:synopsis>
+ Invoked prior to performing the core extended processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationmodify">
+ <adm:synopsis>
+ Invoked prior to performing the core modify processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationmodifydn">
+ <adm:synopsis>
+ Invoked prior to performing the core modify DN processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="preoperationsearch">
+ <adm:synopsis>
+ Invoked prior to performing the core search processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationabandon">
+ <adm:synopsis>
+ Invoked after completing the abandon processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationadd">
+ <adm:synopsis>
+ Invoked after completing the core add processing but before sending
+ the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationbind">
+ <adm:synopsis>
+ Invoked after completing the core bind processing but before
+ sending the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationcompare">
+ <adm:synopsis>
+ Invoked after completing the core compare processing but before
+ sending the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationdelete">
+ <adm:synopsis>
+ Invoked after completing the core delete processing but before
+ sending the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationextended">
+ <adm:synopsis>
+ Invoked after completing the core extended processing but before
+ sending the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationmodify">
+ <adm:synopsis>
+ Invoked after completing the core modify processing but before
+ sending the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationmodifydn">
+ <adm:synopsis>
+ Invoked after completing the core modify DN processing but before
+ sending the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationsearch">
+ <adm:synopsis>
+ Invoked after completing the core search processing but before
+ sending the response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postoperationunbind">
+ <adm:synopsis>
+ Invoked after completing the unbind processing.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponseadd">
+ <adm:synopsis>
+ Invoked after sending the add response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponsebind">
+ <adm:synopsis>
+ Invoked after sending the bind response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponsecompare">
+ <adm:synopsis>
+ Invoked after sending the compare response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponsedelete">
+ <adm:synopsis>
+ Invoked after sending the delete response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponseextended">
+ <adm:synopsis>
+ Invoked after sending the extended response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponsemodify">
+ <adm:synopsis>
+ Invoked after sending the modify response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponsemodifydn">
+ <adm:synopsis>
+ Invoked after sending the modify DN response to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="postresponsesearch">
+ <adm:synopsis>
+ Invoked after sending the search result done message to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="searchresultentry">
+ <adm:synopsis>
+ Invoked before sending a search result entry to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="searchresultreference">
+ <adm:synopsis>
+ Invoked before sending a search result reference to the client.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="intermediateresponse">
+ <adm:synopsis>
+ Invoked before sending an intermediate repsonse message to the
+ client.
+ </adm:synopsis>
+ </adm:value>
+ </adm:enumeration>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.81</ldap:oid>
+ <ldap:name>ds-cfg-plugin-type</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/ProfilerPluginConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/ProfilerPluginConfiguration.xml
new file mode 100644
index 0000000..295ddb5
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/ProfilerPluginConfiguration.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="profiler-plugin"
+ plural-name="profiler-plugins"
+ package="org.opends.server.admin.std" extends="plugin"
+ 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 capture profiling information about operations performed inside
+ the JVM while the Directory Server is running.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.38</ldap:oid>
+ <ldap:name>ds-cfg-profiler-plugin</ldap:name>
+ <ldap:superior>ds-cfg-plugin</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="profile-sample-interval" mandatory="true">
+ <adm:synopsis>
+ Specifies the profiler sample interval.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the sample interval that should be used when capturing
+ profiling information in the server. Changes to this configuration
+ attribute will take effect the next time the profiler is started.
+ </adm:description>
+ <adm:syntax>
+ <adm:duration lower-limit="1" base-unit="ms" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.85</ldap:oid>
+ <ldap:name>ds-cfg-profile-sample-interval</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="profile-directory" mandatory="true">
+ <adm:synopsis>
+ Specifies the directory for writing profile information.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the path to the directory into which profile information will
+ be written. The directory must exist and the Directory Server must have
+ permission to create new files in it. Changes to this configuration
+ attribute will take effect immediately.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.83</ldap:oid>
+ <ldap:name>ds-cfg-profile-directory</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="enable-profiling-on-startup" mandatory="true">
+ <adm:synopsis>
+ Indicates whether to automatically begin capturing profile data when the
+ server is started.
+ </adm:synopsis>
+ <adm:description>
+ Indicates whether the profiler plugin should start collecting data
+ automatically when the Directory Server is started. This will only be
+ read when the server is started, and any changes will take effect on the
+ next restart.
+ </adm:description>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.33</ldap:oid>
+ <ldap:name>ds-cfg-enable-profiling-on-startup</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="profile-action" mandatory="false">
+ <adm:synopsis>
+ Specifies the action that should be taken by the profiler.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the action that should be taken by the profiler. A value of
+ "start" will cause the profiler thread to start collecting data if it is
+ not already active. A value of "stop" will cause the profiler thread to
+ stop collecting data and write it do disk, and a value of "cancel" will
+ cause the profiler thread to stop collecting data and discard anything
+ that has been captured. These operations will occur immediately.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>none</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:enumeration>
+ <adm:value name="none">
+ <adm:synopsis>
+ Do not take any action.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="start">
+ <adm:synopsis>
+ Start collecting profile data.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="stop">
+ <adm:synopsis>
+ Stop collecting profile data and write what has been captured to
+ a file in the profile directory.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="cancel">
+ <adm:synopsis>
+ Stop collecting profile data and discard what has been captured.
+ </adm:synopsis>
+ </adm:value>
+ </adm:enumeration>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.82</ldap:oid>
+ <ldap:name>ds-cfg-profile-action</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
new file mode 100644
index 0000000..72785fe
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:root-managed-object xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The root configuration provides an entry point to the rest of the
+ <adm:product-name />
+ configuration.
+ </adm:synopsis>
+ <adm:relation name="global-configuration"
+ managed-object-name="global">
+ <adm:one-to-one />
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>cn=config</ldap:rdn-sequence>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="connection-handler">
+ <adm:one-to-many />
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=connection handlers, cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="identity-mapper">
+ <adm:one-to-many />
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=Identity Mappers,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="certificate-mapper">
+ <adm:one-to-many />
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=Certificate Mappers,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="sasl-mechanism-handler">
+ <adm:one-to-many />
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=SASL Mechanisms,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="password-validator">
+ <adm:one-to-many />
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=Password Validators,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ </adm:relation>
+ <adm:relation name="plugin">
+ <adm:one-to-many />
+ <adm:profile name="ldap">
+ <ldap:rdn-sequence>
+ cn=Plugins,cn=config
+ </ldap:rdn-sequence>
+ </adm:profile>
+ </adm:relation>
+ <adm:product-name>OpenDS Directory Server</adm:product-name>
+</adm:root-managed-object>
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/SASLMechanismHandlerConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/SASLMechanismHandlerConfiguration.xml
new file mode 100644
index 0000000..e2f1e5a
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/SASLMechanismHandlerConfiguration.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="sasl-mechanism-handler"
+ plural-name="sasl-mechanism-handlers"
+ package="org.opends.server.admin.std"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ are responsible for the processing associated with SASL bind operations.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.43</ldap:oid>
+ <ldap:name>ds-cfg-sasl-mechanism-handler</ldap:name>
+ <ldap:superior>top</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="enabled" mandatory="true">
+ <adm:synopsis>
+ Indicate whether the
+ <adm:user-friendly-name />
+ is enabled for use.
+ </adm:synopsis>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.112</ldap:oid>
+ <ldap:name>ds-cfg-sasl-mechanism-handler-enabled</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="handler-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.api.SASLMechanismHandler
+ </adm:instance-of>
+ </adm:java-class>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.111</ldap:oid>
+ <ldap:name>ds-cfg-sasl-mechanism-handler-class</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/SubjectAttributeToUserAttributeCertificateMapperConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/SubjectAttributeToUserAttributeCertificateMapperConfiguration.xml
new file mode 100644
index 0000000..da3dd26
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/SubjectAttributeToUserAttributeCertificateMapperConfiguration.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="subject-attribute-to-user-attribute-certificate-mapper"
+ plural-name="subject-attribute-to-user-attribute-certificate-mappers"
+ package="org.opends.server.admin.std" extends="certificate-mapper"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The
+ <adm:user-friendly-name />
+ maps client certificates to user entries by mapping the values of
+ attributes contained in the certificate subject to attributes contained in
+ user entries.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.84</ldap:oid>
+ <ldap:name>ds-cfg-subject-attribute-to-user-attribute-certificate-mapper</ldap:name>
+ <ldap:superior>ds-cfg-certificate-mapper</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="subject-attribute-mapping" mandatory="true"
+ multi-valued="true">
+ <adm:synopsis>
+ Specifies a mapping between certificate attributes and user attributes.
+ </adm:synopsis>
+ <adm:description>
+ Specifies a mapping between certificate attributes and user attributes.
+ Each value should be in the form "certattr:userattr" where certattr is
+ the name of the attribute in the certificate subject and userattr is the
+ name of the corresponding attribute in user entries. There may be
+ multiple mappings defined, and when performing the mapping values for all
+ attributes present in the certificate subject that have mappings defined
+ must be present in the corresponding user entries.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.315</ldap:oid>
+ <ldap:name>ds-cfg-certificate-subject-attribute-mapping</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="user-base-dn" mandatory="false" multi-valued="true">
+ <adm:synopsis>
+ Specifies the set of base DNs below which to search for users.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the base DN(s) that should be used when performing searches to
+ map the client certificate to a user entry. If no values are provided,
+ then the server will search below all public naming contexts.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will perform the search in all public naming contexts.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:dn />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.313</ldap:oid>
+ <ldap:name>ds-cfg-certificate-user-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/SubjectDNToUserAttributeCertificateMapperConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/SubjectDNToUserAttributeCertificateMapperConfiguration.xml
new file mode 100644
index 0000000..2321cd5
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/SubjectDNToUserAttributeCertificateMapperConfiguration.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adm:managed-object name="subject-dn-to-user-attribute-certificate-mapper"
+ plural-name="subject-dn-to-user-attribute-certificate-mappers"
+ package="org.opends.server.admin.std" extends="certificate-mapper"
+ xmlns:adm="http://www.opends.org/admin"
+ xmlns:ldap="http://www.opends.org/admin-ldap">
+ <adm:synopsis>
+ The
+ <adm:user-friendly-name />
+ maps client certificates to user entries by looking for the certificate
+ subject DN in a specified attribute of user entries.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:oid>1.3.6.1.4.1.26027.1.2.84</ldap:oid>
+ <ldap:name>ds-cfg-subject-dn-to-user-attribute-certificate-mapper</ldap:name>
+ <ldap:superior>ds-cfg-certificate-mapper</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property name="subject-attribute" mandatory="true">
+ <adm:synopsis>
+ Specifies the attribute in which to look for the subject DN.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the name or OID of the attribute whose value should exactly
+ match the certificate subject DN.
+ </adm:description>
+ <adm:syntax>
+ <adm:string />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.312</ldap:oid>
+ <ldap:name>ds-cfg-certificate-subject-attribute-type</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="user-base-dn" mandatory="false" multi-valued="true">
+ <adm:synopsis>
+ Specifies the set of base DNs below which to search for users.
+ </adm:synopsis>
+ <adm:description>
+ Specifies the base DN(s) that should be used when performing searches to
+ map the client certificate to a user entry. If no values are provided,
+ then the server will search below all public naming contexts.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ The server will perform the search in all public naming contexts.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:dn />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:oid>1.3.6.1.4.1.26027.1.1.313</ldap:oid>
+ <ldap:name>ds-cfg-certificate-user-base-dn</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/server/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java b/opends/src/server/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java
new file mode 100644
index 0000000..d6b82c5
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java
@@ -0,0 +1,99 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A default behavior provider which retrieves default values from a managed
+ * object in an abolute location. It should be used by properties which inherit
+ * their default value(s) from properties held in an other managed object.
+ *
+ * @param <T>
+ * The type of values represented by this provider.
+ */
+public final class AbsoluteInheritedDefaultBehaviorProvider<T> implements
+ DefaultBehaviorProvider<T> {
+
+ // The absolute path to the managed object containing the property.
+ private final ManagedObjectPath path;
+
+ // The name of the property containing the inherited default values.
+ private final String propertyName;
+
+
+
+ /**
+ * Create an absolute inherited default behavior provider associated with the
+ * managed object at the specified absolute location.
+ *
+ * @param path
+ * The absolute location of the managed object.
+ * @param propertyName
+ * The name of the property containing the inherited default values.
+ */
+ public AbsoluteInheritedDefaultBehaviorProvider(ManagedObjectPath path,
+ String propertyName) {
+ this.path = path;
+ this.propertyName = propertyName;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
+ return v.visitAbsoluteInherited(this, p);
+ }
+
+
+
+ /**
+ * Get the absolute path of the managed object containing the property which
+ * has the default values.
+ *
+ * @return Returns the absolute path of the managed object containing the
+ * property which has the default values.
+ */
+ public ManagedObjectPath getManagedObjectPath() {
+ return path;
+ }
+
+
+
+ /**
+ * Get the name of the property containing the inherited default values.
+ *
+ * @return Returns the name of the property containing the inherited default
+ * values.
+ */
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java b/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
new file mode 100644
index 0000000..70d6f32
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
@@ -0,0 +1,418 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opends.server.admin.DefinitionDecodingException.Reason;
+
+
+
+/**
+ * Defines the structure of an abstract managed object. Abstract managed objects
+ * cannot be instantiated.
+ * <p>
+ * Applications can query a managed object definition in order to determine the
+ * overall configuration model of an application.
+ *
+ * @param <C>
+ * The type of client managed object configuration that this definition
+ * represents.
+ * @param <S>
+ * The type of server managed object configuration that this definition
+ * represents.
+ */
+public abstract class AbstractManagedObjectDefinition
+ <C extends ConfigurationClient, S extends Configuration> {
+
+ // The name of the definition.
+ private final String name;
+
+ // The parent managed object definition if applicable.
+ private final AbstractManagedObjectDefinition<? super C, ? super S> parent;
+
+ // The set of property definitions applicable to this managed object
+ // definition.
+ private final Map<String, PropertyDefinition<?>> propertyDefinitions;
+
+ // The set of relation definitions applicable to this managed object
+ // definition.
+ private final Map<String, RelationDefinition<?, ?>> relationDefinitions;
+
+ // The set of managed object definitions which inherit from this definition.
+ private final Map<String,
+ AbstractManagedObjectDefinition<? extends C, ? extends S>> children;
+
+
+
+ /**
+ * Create a new abstract managed object definition.
+ *
+ * @param name
+ * The name of the definition.
+ * @param parent
+ * The parent definition, or <code>null</code> if there is no
+ * parent.
+ */
+ protected AbstractManagedObjectDefinition(String name,
+ AbstractManagedObjectDefinition<? super C, ? super S> parent) {
+ this.name = name;
+ this.parent = parent;
+
+ // If we have a parent definition then inherit its features.
+ if (parent != null) {
+ this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>(
+ parent.propertyDefinitions);
+ this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>(
+ parent.relationDefinitions);
+ parent.children.put(name, this);
+ } else {
+ this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+ this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>();
+ }
+
+ this.children = new HashMap<String,
+ AbstractManagedObjectDefinition<? extends C, ? extends S>>();
+ }
+
+
+
+ /**
+ * Get the named child managed object definition which inherits from this
+ * managed object definition.
+ *
+ * @param name
+ * The name of the managed object definition sub-type.
+ * @return Returns the named child managed object definition which inherits
+ * from this managed object definition.
+ * @throws IllegalArgumentException
+ * If the specified managed object definition name was null or empty
+ * or if the requested subordinate managed object definition was not
+ * found.
+ */
+ public final AbstractManagedObjectDefinition<? extends C, ? extends S>
+ getChild(String name) throws IllegalArgumentException {
+ if ((name == null) || (name.length() == 0)) {
+ throw new IllegalArgumentException("null or empty managed object name");
+ }
+
+ AbstractManagedObjectDefinition<? extends C, ? extends S> d = children
+ .get(name);
+ if (d == null) {
+ throw new IllegalArgumentException("managed object definition \"" + name
+ + "\" not found");
+ }
+
+ return d;
+ }
+
+
+
+ /**
+ * Get all the child managed object definitions which inherit from
+ * this managed object definition.
+ *
+ * @return Returns an unmodifiable collection containing all the
+ * subordinate managed object definitions which inherit from
+ * this managed object definition.
+ */
+ public final Collection<AbstractManagedObjectDefinition
+ <? extends C, ? extends S>> getChildren() {
+ return Collections.unmodifiableCollection(children.values());
+ }
+
+
+
+ /**
+ * Get the name of the definition.
+ *
+ * @return Returns the name of the definition.
+ */
+ public final String getName() {
+ return name;
+ }
+
+
+
+ /**
+ * Get the parent managed object definition, if applicable.
+ *
+ * @return Returns the parent of this managed object definition, or
+ * <code>null</code> if this definition does not have a parent.
+ */
+ public final AbstractManagedObjectDefinition<? super C,
+ ? super S> getParent() {
+ return parent;
+ }
+
+
+
+ /**
+ * Get the specified property definition associated with this type of managed
+ * object.
+ *
+ * @param name
+ * The name of the property definition to be retrieved.
+ * @return Returns the specified property definition associated with this type
+ * of managed object.
+ * @throws IllegalArgumentException
+ * If the specified property name was null or empty or if the
+ * requested property definition was not found.
+ */
+ public final PropertyDefinition getPropertyDefinition(String name)
+ throws IllegalArgumentException {
+ if ((name == null) || (name.length() == 0)) {
+ throw new IllegalArgumentException("null or empty property name");
+ }
+
+ PropertyDefinition d = propertyDefinitions.get(name);
+ if (d == null) {
+ throw new IllegalArgumentException("property definition \"" + name
+ + "\" not found");
+ }
+
+ return d;
+ }
+
+
+
+ /**
+ * Get all the property definitions associated with this type of
+ * managed object.
+ *
+ * @return Returns an unmodifiable collection containing all the
+ * property definitions associated with this type of managed
+ * object.
+ */
+ public final Collection<PropertyDefinition<?>> getPropertyDefinitions() {
+ return Collections.unmodifiableCollection(propertyDefinitions
+ .values());
+ }
+
+
+
+ /**
+ * Get the specified relation definition associated with this type of managed
+ * object.
+ *
+ * @param name
+ * The name of the relation definition to be retrieved.
+ * @return Returns the specified relation definition associated with this type
+ * of managed object.
+ * @throws IllegalArgumentException
+ * If the specified relation name was null or empty or if the
+ * requested relation definition was not found.
+ */
+ public final RelationDefinition getRelationDefinition(String name)
+ throws IllegalArgumentException {
+ if ((name == null) || (name.length() == 0)) {
+ throw new IllegalArgumentException("null or empty relation name");
+ }
+
+ RelationDefinition d = relationDefinitions.get(name);
+ if (d == null) {
+ throw new IllegalArgumentException("relation definition \"" + name
+ + "\" not found");
+ }
+
+ return d;
+ }
+
+
+
+ /**
+ * Get all the relation definitions associated with this type of
+ * managed object.
+ *
+ * @return Returns an unmodifiable collection containing all the
+ * relation definitions associated with this type of managed
+ * object.
+ */
+ public final Collection<RelationDefinition<?,?>> getRelationDefinitions() {
+ return Collections.unmodifiableCollection(relationDefinitions
+ .values());
+ }
+
+
+
+ /**
+ * Determine whether there are any child managed object definitions which
+ * inherit from this managed object definition.
+ *
+ * @return Returns <code>true</code> if this type of managed object has any
+ * child managed object definitions, <code>false</code> otherwise.
+ */
+ public final boolean hasChildren() {
+ return !children.isEmpty();
+ }
+
+
+
+ /**
+ * Determine whether this type of managed object has any property definitions.
+ *
+ * @return Returns <code>true</code> if this type of managed object has any
+ * property definitions, <code>false</code> otherwise.
+ */
+ public final boolean hasPropertyDefinitions() {
+ return !propertyDefinitions.isEmpty();
+ }
+
+
+
+ /**
+ * Determine whether this type of managed object has any relation definitions.
+ *
+ * @return Returns <code>true</code> if this type of managed object has any
+ * relation definitions, <code>false</code> otherwise.
+ */
+ public final boolean hasRelationDefinitions() {
+ return !relationDefinitions.isEmpty();
+ }
+
+
+
+ /**
+ * Register a property definition with the managed object definition,
+ * overriding any existing property definition with the same name.
+ * <p>
+ * This method <b>must not</b> be called by applications.
+ *
+ * @param d
+ * The property definition to be registered.
+ */
+ public final void registerPropertyDefinition(PropertyDefinition d) {
+ String name = d.getName();
+
+ propertyDefinitions.put(name, d);
+ }
+
+
+
+ /**
+ * Register a relation definition with the managed object definition,
+ * overriding any existing relation definition with the same name.
+ * <p>
+ * This method <b>must not</b> be called by applications.
+ *
+ * @param d
+ * The relation definition to be registered.
+ */
+ public final void registerRelationDefinition(RelationDefinition d) {
+ String name = d.getName();
+
+ relationDefinitions.put(name, d);
+ }
+
+
+
+ /**
+ * Finds a sub-type of this managed object definition which most closely
+ * corresponds to the matching criteria of the provided definition resolver.
+ *
+ * @param r
+ * The definition resolver.
+ * @return Returns the sub-type of this managed object definition which most
+ * closely corresponds to the matching criteria of the provided
+ * definition resolver.
+ * @throws DefinitionDecodingException
+ * If no matching sub-type could be found or if the resolved
+ * definition was abstract.
+ * @see DefinitionResolver
+ */
+ @SuppressWarnings("unchecked")
+ public final ManagedObjectDefinition<? extends C, ? extends S>
+ resolveManagedObjectDefinition(
+ DefinitionResolver r) throws DefinitionDecodingException {
+ AbstractManagedObjectDefinition<? extends C, ? extends S> rd;
+ rd = resolveManagedObjectDefinitionAux(this, r);
+ if (rd == null) {
+ // Unable to resolve the definition.
+ throw new DefinitionDecodingException(Reason.WRONG_TYPE_INFORMATION);
+ } else if (rd instanceof ManagedObjectDefinition) {
+ return (ManagedObjectDefinition<? extends C, ? extends S>) rd;
+ } else {
+ // Resolved definition was abstract.
+ throw new DefinitionDecodingException(Reason.ABSTRACT_TYPE_INFORMATION);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final String toString() {
+ StringBuilder builder = new StringBuilder();
+ toString(builder);
+ return builder.toString();
+ }
+
+
+
+ /**
+ * Append a string representation of the managed object definition to the
+ * provided string builder.
+ *
+ * @param builder
+ * The string builder where the string representation should be
+ * appended.
+ */
+ public final void toString(StringBuilder builder) {
+ builder.append(getName());
+ }
+
+
+
+ // Recursively descend definition hierarchy to find the best match definition.
+ private AbstractManagedObjectDefinition<? extends C, ? extends S>
+ resolveManagedObjectDefinitionAux(
+ AbstractManagedObjectDefinition<? extends C, ? extends S> d,
+ DefinitionResolver r) {
+ if (!r.matches(d)) {
+ return null;
+ }
+
+ for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : d
+ .getChildren()) {
+ AbstractManagedObjectDefinition<? extends C, ? extends S> rd =
+ resolveManagedObjectDefinitionAux(child, r);
+ if (rd != null) {
+ return rd;
+ }
+ }
+
+ return d;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/AbstractPropertyDefinition.java b/opends/src/server/org/opends/server/admin/AbstractPropertyDefinition.java
new file mode 100644
index 0000000..87ff5a0
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AbstractPropertyDefinition.java
@@ -0,0 +1,357 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+
+
+/**
+ * Skeleton property definition implementation.
+ *
+ * @param <T>
+ * The data-type of values of the property.
+ */
+public abstract class AbstractPropertyDefinition<T> implements
+ PropertyDefinition<T> {
+
+ /**
+ * An interface for incrementally constructing property definitions.
+ *
+ * @param <T>
+ * The data-type of values of the property.
+ * @param <D>
+ * The type of property definition constructed by this builder.
+ */
+ protected abstract static class AbstractBuilder<T,
+ D extends PropertyDefinition<T>> {
+
+ // The name of this property definition.
+ private final String propertyName;
+
+ // The options applicable to this definition.
+ private final EnumSet<PropertyOption> options;
+
+ // The default behavior provider.
+ private DefaultBehaviorProvider<T> defaultBehavior;
+
+
+
+ /**
+ * Create a property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ */
+ protected AbstractBuilder(String propertyName) {
+ this.propertyName = propertyName;
+ this.options = EnumSet.noneOf(PropertyOption.class);
+ this.defaultBehavior = new UndefinedDefaultBehaviorProvider<T>();
+ }
+
+
+
+ /**
+ * Construct a property definition based on the properties of this builder.
+ *
+ * @return The new property definition.
+ */
+ public final D getInstance() {
+ return buildInstance(propertyName, options, defaultBehavior);
+ }
+
+
+
+ /**
+ * Set the default behavior provider.
+ *
+ * @param defaultBehavior
+ * The default behavior provider.
+ */
+ public final void setDefaultBehaviorProvider(
+ DefaultBehaviorProvider<T> defaultBehavior) {
+ ensureNotNull(defaultBehavior);
+ this.defaultBehavior = defaultBehavior;
+ }
+
+
+
+ /**
+ * Add a property definition option.
+ *
+ * @param option
+ * The property option.
+ */
+ public final void setOption(PropertyOption option) {
+ ensureNotNull(option);
+ options.add(option);
+ }
+
+
+
+ /**
+ * Build a property definition based on the properties of this builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @param options
+ * Options applicable to this definition.
+ * @param defaultBehavior
+ * The default behavior provider.
+ * @return The new property definition.
+ */
+ protected abstract D buildInstance(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<T> defaultBehavior);
+ }
+
+ // The property name.
+ private final String propertyName;
+
+ // The property value class.
+ private final Class<T> theClass;
+
+ // Options applicable to this definition.
+ private final Set<PropertyOption> options;
+
+ // The default behavior provider.
+ private final DefaultBehaviorProvider<T> defaultBehavior;
+
+
+
+ /**
+ * Create a property definition.
+ *
+ * @param theClass
+ * The property value class.
+ * @param propertyName
+ * The property name.
+ * @param options
+ * Options applicable to this definition.
+ * @param defaultBehavior
+ * The default behavior provider.
+ */
+ protected AbstractPropertyDefinition(Class<T> theClass, String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<T> defaultBehavior) {
+ ensureNotNull(theClass, propertyName, options, defaultBehavior);
+
+ this.theClass = theClass;
+ this.propertyName = propertyName;
+ this.options = EnumSet.copyOf(options);
+ this.defaultBehavior = defaultBehavior;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p);
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public final T castValue(Object object) throws ClassCastException {
+ return theClass.cast(object);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This default implementation normalizes both values using
+ * {@link #normalizeValue(Object)} and then performs a case-sensitive string
+ * comparison.
+ */
+ public int compare(T o1, T o2) {
+ ensureNotNull(o1, o2);
+
+ String s1 = normalizeValue(o1);
+ String s2 = normalizeValue(o2);
+
+ return s1.compareTo(s2);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(PropertyDefinition<?> o) {
+ int rc = getName().compareTo(o.getName());
+ if (rc == 0) {
+ // TODO: see comment in equals().
+ rc = getClass().getName().compareTo(o.getClass().getName());
+ }
+ return rc;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract T decodeValue(String value)
+ throws IllegalPropertyValueStringException;
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This default implementation simply returns invokes the
+ * {@link Object#toString()} method on the provided value.
+ */
+ public String encodeValue(T value) throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ return value.toString();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ } else if (obj instanceof PropertyDefinition) {
+ PropertyDefinition other = (PropertyDefinition) obj;
+ if (getName().equals(other.getName())) {
+ // TODO: this isn't quite right - should be comparing the value types
+ // not the definition type. It's ok for now though.
+ if (getClass().equals(other.getClass())) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return false;
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public DefaultBehaviorProvider<T> getDefaultBehaviorProvider() {
+ return defaultBehavior;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public final String getName() {
+ return propertyName;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ // TODO: see comment in equals().
+ int rc = 17 + getName().hashCode();
+ return 37 * rc + getClass().hashCode();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public final boolean hasOption(PropertyOption option) {
+ return options.contains(option);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This default implementation simply returns the string representation of the
+ * provided value. Sub-classes might want to override this method if this
+ * behavior is insufficient (for example, a string property definition might
+ * strip white-space and convert characters to lower-case).
+ */
+ public String normalizeValue(T value) throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ return encodeValue(value);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final String toString() {
+ StringBuilder builder = new StringBuilder();
+ toString(builder);
+ return builder.toString();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This simple implementation just outputs the propertyName of the property
+ * definition. Sub-classes should override this method to provide more
+ * complete string representations.
+ */
+ public void toString(StringBuilder builder) {
+ builder.append(propertyName);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract void validateValue(T value)
+ throws IllegalPropertyValueException;
+
+}
diff --git a/opends/src/server/org/opends/server/admin/AbstractPropertyDefinitionVisitor.java b/opends/src/server/org/opends/server/admin/AbstractPropertyDefinitionVisitor.java
new file mode 100644
index 0000000..7876ca4
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AbstractPropertyDefinitionVisitor.java
@@ -0,0 +1,172 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A skeletal implementation of a property definition visitor. Each
+ * <code>visitXXX</code> method is provided with a default
+ * implementation which calls
+ * {@link #visitUnknown(PropertyDefinition, Object)}. Sub-classes can
+ * override any or all of the methods to provide their own
+ * type-specific behavior.
+ *
+ * @param <R>
+ * The return type of this visitor's methods. Use
+ * {@link java.lang.Void} for visitors that do not need to
+ * return results.
+ * @param <P>
+ * The type of the additional parameter to this visitor's
+ * methods. Use {@link java.lang.Void} for visitors that do
+ * not need an additional parameter.
+ */
+public abstract class AbstractPropertyDefinitionVisitor<R, P>
+ implements PropertyDefinitionVisitor<R, P> {
+
+ /**
+ * Default constructor.
+ */
+ protected AbstractPropertyDefinitionVisitor() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitAttributeType(AttributeTypePropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitBoolean(BooleanPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitClass(ClassPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitDN(DNPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitDuration(DurationPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitInteger(IntegerPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitIPAddress(IPAddressPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitIPAddressMask(IPAddressMaskPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitSize(SizePropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitString(StringPropertyDefinition d, P p) {
+ return visitUnknown(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation of this method is throw an
+ * {@link UnknownPropertyDefinitionException}. Sub-classes can
+ * override this method with their own default behavior.
+ */
+ public R visitUnknown(PropertyDefinition d, P p)
+ throws UnknownPropertyDefinitionException {
+ throw new UnknownPropertyDefinitionException(d, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public R visitEnum(EnumPropertyDefinition<?> d, P p) {
+ return visitUnknown(d, p);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/AdminClassLoaderProvider.java b/opends/src/server/org/opends/server/admin/AdminClassLoaderProvider.java
new file mode 100644
index 0000000..56b45b4
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AdminClassLoaderProvider.java
@@ -0,0 +1,560 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.loggers.Error.logError;
+import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.debugMessage;
+import static org.opends.server.messages.AdminMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.opends.server.admin.std.meta.RootConfigurationDefinition;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.InitializationException;
+
+
+
+/**
+ * Manages the class loader which should be used for loading
+ * configuration definition classes and associated extensions.
+ * <p>
+ * For extensions which define their own extended configuration
+ * definitions, the class loader will make sure that the configuration
+ * definition classes are loaded and initialized.
+ */
+public final class AdminClassLoaderProvider {
+
+ /**
+ * Private URLClassLoader implementation. This is only required so
+ * that we can provide access to the addURL method.
+ */
+ private static final class MyURLClassLoader extends URLClassLoader {
+
+ /**
+ * Create a class loader with the default parent class loader.
+ */
+ public MyURLClassLoader() {
+ super(new URL[0]);
+ }
+
+
+
+ /**
+ * Create a class loader with the provided parent class loader.
+ *
+ * @param parent
+ * The parent class loader.
+ */
+ public MyURLClassLoader(ClassLoader parent) {
+ super(new URL[0], parent);
+ }
+
+
+
+ /**
+ * Add a Jar file to this class loader.
+ *
+ * @param jarFile
+ * The name of the Jar file.
+ * @throws MalformedURLException
+ * If a protocol handler for the URL could not be found,
+ * or if some other error occurred while constructing
+ * the URL.
+ * @throws SecurityException
+ * If a required system property value cannot be
+ * accessed.
+ */
+ public void addJarFile(File jarFile) throws SecurityException,
+ MalformedURLException {
+ addURL(jarFile.toURI().toURL());
+ }
+
+ }
+
+ // The name of the manifest file listing the core configuration
+ // definition classes.
+ private static final String CORE_MANIFEST = "core.manifest";
+
+ // The name of the manifest file listing a extension's configuration
+ // definition classes.
+ private static final String EXTENSION_MANIFEST = "extension.manifest";
+
+ // The name of the lib directory.
+ private static final String LIB_DIR = "lib";
+
+ // The name of the extensions directory.
+ private static final String EXTENSIONS_DIR = "extensions";
+
+ // The singleton instance.
+ private static final AdminClassLoaderProvider INSTANCE =
+ new AdminClassLoaderProvider();
+
+
+
+ /**
+ * Gets the application-wide administration framework class loader.
+ *
+ * @return Returns the application-wide administration framework
+ * class loader.
+ */
+ public static AdminClassLoaderProvider getInstance() {
+ return INSTANCE;
+ }
+
+ // Flag indicating whether one-off initialization has been
+ // performed.
+ private boolean initialized = false;
+
+ // Set of registered Jar files.
+ private Set<File> jarFiles = new HashSet<File>();
+
+ // Underlying class loader used to load classes and resources.
+ //
+ // We contain a reference to the URLClassLoader rather than
+ // sub-class it so that it is possible to replace the loader at
+ // run-time. For example, when removing or replacing extension Jar
+ // files (the URLClassLoader only supports adding new
+ // URLs, not removal).
+ private MyURLClassLoader loader = new MyURLClassLoader();
+
+
+
+ // Private constructor.
+ private AdminClassLoaderProvider() {
+ // No additional implementation required.
+ }
+
+
+
+ /**
+ * Add the named extensions to this class loader.
+ *
+ * @param extensions
+ * The names of the extensions to be loaded.
+ * @throws InitializationException
+ * If one of the extensions could not be loaded and
+ * initialized.
+ * @throws IllegalStateException
+ * If this class loader provider has not been initialized.
+ */
+ public synchronized void addExtension(File... extensions)
+ throws InitializationException, IllegalStateException {
+ if (!initialized) {
+ throw new IllegalStateException(
+ "The class loader provider is not initialized");
+ }
+
+ // First add the Jar files to the class loader.
+ List<JarFile> jars = new LinkedList<JarFile>();
+ for (File extension : extensions) {
+ if (jarFiles.contains(extension)) {
+ // Skip this file as it is already loaded.
+ continue;
+ }
+
+ // Attempt to load it.
+ jars.add(loadJarFile(extension));
+
+ // Register the Jar file with the class loader.
+ try {
+ loader.addJarFile(extension);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_OPEN_JAR_FILE;
+ String message = getMessage(msgID, extension.getName(), extension
+ .getParent(), stackTraceToSingleLineString(e));
+
+ throw new InitializationException(msgID, message);
+ }
+ jarFiles.add(extension);
+ }
+
+ // Now forcefully load the configuration definition classes.
+ for (JarFile jar : jars) {
+ initializeExtension(jar);
+ }
+ }
+
+
+
+ /**
+ * Gets the class loader which should be used for loading classes
+ * and resources.
+ *
+ * @return Returns the class loader which should be used for loading
+ * classes and resources.
+ * @throws IllegalStateException
+ * If this class loader provider has not been initialized.
+ */
+ public synchronized ClassLoader getClassLoader()
+ throws IllegalStateException {
+ if (!initialized) {
+ throw new IllegalStateException(
+ "The class loader provider is not initialized");
+ }
+
+ return loader;
+ }
+
+
+
+ /**
+ * Initialize this class loader provider using the default parent
+ * class loader.
+ *
+ * @throws InitializationException
+ * If the administration class loader could not initialize
+ * successfully.
+ * @throws IllegalStateException
+ * If this class loader provider is already initialized.
+ */
+ public synchronized void initialize()
+ throws InitializationException, IllegalStateException {
+ initialize(null);
+ }
+
+
+
+ /**
+ * Initialize this class loader provider using the provided parent
+ * class loader.
+ *
+ * @param parent
+ * The parent class loader.
+ * @throws InitializationException
+ * If the administration class loader could not initialize
+ * successfully.
+ * @throws IllegalStateException
+ * If this class loader provider is already initialized.
+ */
+ public synchronized void initialize(ClassLoader parent)
+ throws InitializationException, IllegalStateException {
+ if (initialized) {
+ throw new IllegalStateException(
+ "The class loader provider is already initialized");
+ }
+
+ // Prevent multiple initialization.
+ initialized = true;
+
+ // Create the new loader.
+ if (parent == null) {
+ loader = new MyURLClassLoader();
+ } else {
+ loader = new MyURLClassLoader(parent);
+ }
+
+ // Forcefully load all configuration definition classes in
+ // OpenDS.jar.
+ initializeCoreComponents();
+
+ // Put extensions jars into the class loader and load all
+ // configuration definition classes in that they contain.
+ initializeAllExtensions();
+ }
+
+
+
+ /**
+ * Put extensions jars into the class loader and load all configuration
+ * definition classes in that they contain.
+ *
+ * @throws InitializationException
+ * If the extensions folder could not be accessed or if a
+ * extension jar file could not be accessed or if one of the
+ * configuration definition classes could not be
+ * initialized.
+ */
+ private void initializeAllExtensions() throws InitializationException {
+ File libPath = new File(DirectoryServer.getServerRoot(), LIB_DIR);
+ File extensionsPath = new File(libPath, EXTENSIONS_DIR);
+
+ try {
+ if (!extensionsPath.exists()) {
+ // The extensions directory does not exist. This is not a
+ // critical problem.
+ int msgID = MSGID_ADMIN_NO_EXTENSIONS_DIR;
+ String message = getMessage(msgID, extensionsPath);
+
+ logError(ErrorLogCategory.EXTENSIONS,
+ ErrorLogSeverity.MILD_ERROR, message, msgID);
+ return;
+ }
+
+ if (!extensionsPath.isDirectory()) {
+ // The extensions directory is not a directory. This is more
+ // critical.
+ int msgID = MSGID_ADMIN_EXTENSIONS_DIR_NOT_DIRECTORY;
+ String message = getMessage(msgID, extensionsPath);
+
+ throw new InitializationException(msgID, message);
+ }
+
+ // Get each extension file name.
+ FileFilter filter = new FileFilter() {
+
+ /**
+ * Must be a Jar file.
+ */
+ public boolean accept(File pathname) {
+ if (!pathname.isFile()) {
+ return false;
+ }
+
+ String name = pathname.getName();
+ return name.endsWith(".jar");
+ }
+
+ };
+
+ // Add and initialize the extensions.
+ addExtension(extensionsPath.listFiles(filter));
+ } catch (InitializationException e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ throw e;
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_EXTENSIONS_CANNOT_LIST_FILES;
+ String message = getMessage(msgID, extensionsPath,
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
+ }
+
+
+
+ /**
+ * Make sure all core configuration definitions are loaded.
+ *
+ * @throws InitializationException
+ * If the core manifest file could not be read or if one
+ * of the configuration definition classes could not be
+ * initialized.
+ */
+ private void initializeCoreComponents()
+ throws InitializationException {
+ InputStream is = RootConfigurationDefinition.class
+ .getResourceAsStream("/admin/" + CORE_MANIFEST);
+
+ if (is == null) {
+ int msgID = MSGID_ADMIN_CANNOT_FIND_CORE_MANIFEST;
+ String message = getMessage(msgID, CORE_MANIFEST);
+ throw new InitializationException(msgID, message);
+ }
+
+ try {
+ loadDefinitionClasses(is);
+ } catch (IOException e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_READ_CORE_MANIFEST;
+ String message = getMessage(msgID, CORE_MANIFEST,
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_CORE_MANIFEST;
+ String message = getMessage(msgID, CORE_MANIFEST,
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ }
+ }
+
+
+
+ /**
+ * Make sure all the configuration definition classes in a extension
+ * are loaded.
+ *
+ * @param jarFile
+ * The extension's Jar file.
+ * @throws InitializationException
+ * If the extension jar file could not be accessed or if one
+ * of the configuration definition classes could not be
+ * initialized.
+ */
+ private void initializeExtension(JarFile jarFile)
+ throws InitializationException {
+ JarEntry entry = jarFile.getJarEntry("admin/" + EXTENSION_MANIFEST);
+ if (entry != null) {
+ InputStream is;
+ try {
+ is = jarFile.getInputStream(entry);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_READ_EXTENSION_MANIFEST;
+ String message = getMessage(msgID, EXTENSION_MANIFEST, jarFile
+ .getName(), stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ }
+
+ try {
+ loadDefinitionClasses(is);
+ } catch (IOException e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_READ_EXTENSION_MANIFEST;
+ String message = getMessage(msgID, EXTENSION_MANIFEST, jarFile
+ .getName(), stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_EXTENSION_MANIFEST;
+ String message = getMessage(msgID, EXTENSION_MANIFEST, jarFile
+ .getName(), stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ }
+ }
+ }
+
+
+
+ /**
+ * Forcefully load configuration definition classes named in a
+ * manifest file.
+ *
+ * @param is
+ * The manifest file input stream.
+ * @throws IOException
+ * If an IO error occurred whilst reading the manifest
+ * file.
+ * @throws ClassNotFoundException
+ * If an IO error occurred whilst reading the manifest
+ * file.
+ * @throws LinkageError
+ * If the linkage fails.
+ * @throws ExceptionInInitializerError
+ * If the initialization provoked by this method fails.
+ */
+ private void loadDefinitionClasses(InputStream is)
+ throws IOException, ClassNotFoundException, LinkageError,
+ ExceptionInInitializerError {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ is));
+ while (true) {
+ String className = reader.readLine();
+
+ // Break out when the end of the manifest is reached.
+ if (className == null) {
+ break;
+ }
+
+ // Skip blank lines.
+ className = className.trim();
+ if (className.length() == 0) {
+ continue;
+ }
+
+ // Skip lines beginning with #.
+ if (className.startsWith("#")) {
+ continue;
+ }
+
+ debugMessage(DebugLogLevel.INFO, "Loading class " + className);
+
+ // Use the underlying loader.
+ Class.forName(className, true, loader);
+ }
+ }
+
+
+
+ /**
+ * Load the named Jar file.
+ *
+ * @param jar
+ * The name of the Jar file to load.
+ * @return Returns the loaded Jar file.
+ * @throws InitializationException
+ * If the Jar file could not be loaded.
+ */
+ private JarFile loadJarFile(File jar)
+ throws InitializationException {
+ JarFile jarFile;
+
+ try {
+ // Load the extension jar file.
+ jarFile = new JarFile(jar);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_OPEN_JAR_FILE;
+ String message = getMessage(msgID, jar.getName(), jar
+ .getParent(), stackTraceToSingleLineString(e));
+
+ throw new InitializationException(msgID, message);
+ }
+ return jarFile;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/AdminException.java b/opends/src/server/org/opends/server/admin/AdminException.java
new file mode 100644
index 0000000..a22de72
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AdminException.java
@@ -0,0 +1,81 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Exceptions thrown when interacting with administration framework.
+ */
+public abstract class AdminException extends Exception {
+
+ /**
+ * Create an admin exception.
+ */
+ protected AdminException() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Create an admin exception with a cause.
+ *
+ * @param cause
+ * The cause.
+ */
+ protected AdminException(Throwable cause) {
+ super(cause);
+ }
+
+
+
+ /**
+ * Create an admin exception with a message and cause.
+ *
+ * @param message
+ * The message.
+ * @param cause
+ * The cause.
+ */
+ protected AdminException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+
+
+ /**
+ * Create an admin exception with a message.
+ *
+ * @param message
+ * The message.
+ */
+ protected AdminException(String message) {
+ super(message);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/AdminRuntimeException.java b/opends/src/server/org/opends/server/admin/AdminRuntimeException.java
new file mode 100644
index 0000000..ed0dfc5
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AdminRuntimeException.java
@@ -0,0 +1,82 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Exceptions thrown when interacting with administration framework that
+ * applications are not expected to catch.
+ */
+public abstract class AdminRuntimeException extends RuntimeException {
+
+ /**
+ * Create an admin runtime exception.
+ */
+ protected AdminRuntimeException() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Create an admin runtime exception with a cause.
+ *
+ * @param cause
+ * The cause.
+ */
+ protected AdminRuntimeException(Throwable cause) {
+ super(cause);
+ }
+
+
+
+ /**
+ * Create an admin runtime exception with a message and cause.
+ *
+ * @param message
+ * The message.
+ * @param cause
+ * The cause.
+ */
+ protected AdminRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+
+
+ /**
+ * Create an admin runtime exception with a message.
+ *
+ * @param message
+ * The message.
+ */
+ protected AdminRuntimeException(String message) {
+ super(message);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/AggregationRelationDefinition.java b/opends/src/server/org/opends/server/admin/AggregationRelationDefinition.java
new file mode 100644
index 0000000..9b0f159
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AggregationRelationDefinition.java
@@ -0,0 +1,190 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+
+
+/**
+ * A managed object aggregation relationship definition.
+ *
+ * @param <C>
+ * The type of client managed object configuration that this
+ * relation definition refers to.
+ * @param <S>
+ * The type of server managed object configuration that this
+ * relation definition refers to.
+ */
+public final class AggregationRelationDefinition
+ <C extends ConfigurationClient, S extends Configuration>
+ extends RelationDefinition<C, S> {
+
+ // The plural name of the relation.
+ private final String pluralName;
+
+ // The path identifying the location of the referenced managed
+ // objects.
+ private final ManagedObjectPath path;
+
+ // The minimum number of referenced managed objects.
+ private final int minOccurs;
+
+ // The maximum number of referenced managed objects.
+ private final int maxOccurs;
+
+
+
+ /**
+ * Create a new aggregation managed object relation definition.
+ *
+ * @param pd
+ * The parent managed object definition.
+ * @param name
+ * The name of this relation.
+ * @param pluralName
+ * The plural name of the relation.
+ * @param cd
+ * The child managed object definition.
+ * @param path
+ * The path identifying the location of the referenced
+ * managed objects.
+ * @param minOccurs
+ * The minimum number of referenced managed objects.
+ * @param maxOccurs
+ * The maximum number of referenced managed objects (or
+ * zero if there is no upper limit).
+ * @throws IllegalArgumentException
+ * If minOccurs is less than zero or maxOccurs is less
+ * than minOccurs.
+ */
+ public AggregationRelationDefinition(
+ AbstractManagedObjectDefinition<?, ?> pd, String name, String pluralName,
+ AbstractManagedObjectDefinition<C, S> cd,
+ ManagedObjectPath path, int minOccurs, int maxOccurs)
+ throws IllegalArgumentException {
+ super(pd, name, cd);
+
+ ensureNotNull(path);
+
+ if (minOccurs < 0) {
+ throw new IllegalArgumentException(
+ "minOccurs is less than zero");
+ }
+
+ if (maxOccurs != 0 && maxOccurs < minOccurs) {
+ throw new IllegalArgumentException(
+ "maxOccurs is less than minOccurs");
+ }
+
+ this.pluralName = pluralName;
+ this.path = path;
+ this.minOccurs = minOccurs;
+ this.maxOccurs = maxOccurs;
+ }
+
+
+
+ /**
+ * Get the plural name of the relation.
+ *
+ * @return Returns the plural name of the relation.
+ */
+ public final String getPluralName() {
+ return pluralName;
+ }
+
+
+
+ /**
+ * Get the path identifying the location of the referenced managed
+ * objects.
+ *
+ * @return Returns the path identifying the location of the
+ * referenced managed objects.
+ */
+ public ManagedObjectPath getPath() {
+ return path;
+ }
+
+
+
+ /**
+ * Get the minimum number of referenced managed objects.
+ *
+ * @return Returns the minimum number of referenced managed objects.
+ */
+ public int getMinOccurs() {
+ return minOccurs;
+ }
+
+
+
+ /**
+ * Get the maximum number of referenced managed objects.
+ *
+ * @return Returns the maximum number of referenced managed objects
+ * (or zero if there is no upper limit).
+ */
+ public int getMaxOccurs() {
+ return maxOccurs;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void toString(StringBuilder builder) {
+ builder.append("name=");
+ builder.append(getName());
+ builder.append(" type=aggregation parent=");
+ builder.append(getParentDefinition().getName());
+ builder.append(" child=");
+ builder.append(getChildDefinition().getName());
+ builder.append(" minOccurs=");
+ builder.append(minOccurs);
+ if (maxOccurs != 0) {
+ builder.append(" maxOccurs=");
+ builder.append(maxOccurs);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
+ return v.visitAggregation(this, p);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/AliasDefaultBehaviorProvider.java b/opends/src/server/org/opends/server/admin/AliasDefaultBehaviorProvider.java
new file mode 100644
index 0000000..dd0a5ad
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AliasDefaultBehaviorProvider.java
@@ -0,0 +1,61 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A default behavior provider which indicates special behavior. It should be
+ * used by properties which have a default behavior which cannot be directly
+ * represented using real values of the property. For example, a property
+ * containing a set of user names might default to "all users" when no values
+ * are provided. This meaning cannot be represented using a finite set of
+ * values.
+ *
+ * @param <T>
+ * The type of values represented by this provider.
+ */
+public final class AliasDefaultBehaviorProvider<T> implements
+ DefaultBehaviorProvider<T> {
+
+ /**
+ * Create an alias default behavior provider.
+ */
+ public AliasDefaultBehaviorProvider() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
+ return v.visitAlias(this, p);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/AttributeTypePropertyDefinition.java b/opends/src/server/org/opends/server/admin/AttributeTypePropertyDefinition.java
new file mode 100644
index 0000000..95150a7
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/AttributeTypePropertyDefinition.java
@@ -0,0 +1,193 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.AttributeType;
+
+
+
+/**
+ * Attribute type property definition.
+ */
+public final class AttributeTypePropertyDefinition extends
+ AbstractPropertyDefinition<AttributeType> {
+
+ /**
+ * An interface for incrementally constructing attribute type
+ * property definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<AttributeType, AttributeTypePropertyDefinition> {
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected AttributeTypePropertyDefinition buildInstance(
+ String propertyName, EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<AttributeType> defaultBehavior) {
+ return new AttributeTypePropertyDefinition(propertyName,
+ options, defaultBehavior);
+ }
+ }
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 4622133184170201490L;
+
+ // Flag indicating whether or not attribute type names should be
+ // validated against the schema.
+ private static boolean isCheckSchema = true;
+
+
+
+ /**
+ * Create a attribute type property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new attribute type property definition
+ * builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ /**
+ * Determines whether or not attribute type names should be
+ * validated against the schema.
+ *
+ * @return Returns <code>true</code> if attribute type names
+ * should be validated against the schema.
+ */
+ public static boolean isCheckSchema() {
+ return isCheckSchema;
+ }
+
+
+
+ /**
+ * Specify whether or not attribute type names should be validated
+ * against the schema.
+ * <p>
+ * By default validation is switched on.
+ *
+ * @param value
+ * <code>true</code> if attribute type names should be
+ * validated against the schema.
+ */
+ public static void setCheckSchema(boolean value) {
+ isCheckSchema = value;
+ }
+
+
+
+ // Private constructor.
+ private AttributeTypePropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<AttributeType> defaultBehavior) {
+ super(AttributeType.class, propertyName, options,
+ defaultBehavior);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitAttributeType(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(AttributeType o1, AttributeType o2) {
+ return o1.getNameOrOID().compareToIgnoreCase(o2.getNameOrOID());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AttributeType decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ String name = value.trim().toLowerCase();
+ AttributeType type = DirectoryServer.getAttributeType(name,
+ !isCheckSchema);
+
+ if (type == null) {
+ throw new IllegalPropertyValueStringException(this, value);
+ } else {
+ try {
+ validateValue(type);
+ return type;
+ } catch (IllegalPropertyValueException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(AttributeType value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // No implementation required.
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/BooleanPropertyDefinition.java b/opends/src/server/org/opends/server/admin/BooleanPropertyDefinition.java
new file mode 100644
index 0000000..48d9c5f
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/BooleanPropertyDefinition.java
@@ -0,0 +1,177 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+
+
+/**
+ * Boolean property definition.
+ */
+public final class BooleanPropertyDefinition extends
+ AbstractPropertyDefinition<Boolean> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -3615113733243221668L;
+
+ /**
+ * Mapping used for parsing boolean values. This mapping is more flexible than
+ * the standard boolean string parser and supports common true/false synonyms
+ * used in configuration.
+ */
+ private static final Map<String, Boolean> VALUE_MAP;
+ static {
+ VALUE_MAP = new HashMap<String, Boolean>();
+
+ VALUE_MAP.put("0", Boolean.FALSE);
+ VALUE_MAP.put("no", Boolean.FALSE);
+ VALUE_MAP.put("off", Boolean.FALSE);
+ VALUE_MAP.put("false", Boolean.FALSE);
+ VALUE_MAP.put("disable", Boolean.FALSE);
+ VALUE_MAP.put("disabled", Boolean.FALSE);
+
+ VALUE_MAP.put("1", Boolean.TRUE);
+ VALUE_MAP.put("yes", Boolean.TRUE);
+ VALUE_MAP.put("on", Boolean.TRUE);
+ VALUE_MAP.put("true", Boolean.TRUE);
+ VALUE_MAP.put("enable", Boolean.TRUE);
+ VALUE_MAP.put("enabled", Boolean.TRUE);
+ }
+
+
+
+ /**
+ * An interface for incrementally constructing boolean property definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<Boolean, BooleanPropertyDefinition> {
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected BooleanPropertyDefinition buildInstance(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Boolean> defaultBehavior) {
+ return new BooleanPropertyDefinition(propertyName, options,
+ defaultBehavior);
+ }
+
+ }
+
+
+
+ /**
+ * Create a boolean property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new boolean property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private BooleanPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Boolean> defaultBehavior) {
+ super(Boolean.class, propertyName, options, defaultBehavior);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(Boolean value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // No additional validation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Boolean decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ String nvalue = value.trim().toLowerCase();
+ Boolean b = VALUE_MAP.get(nvalue);
+
+ if (b == null) {
+ throw new IllegalPropertyValueStringException(this, value);
+ } else {
+ return b;
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitBoolean(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(Boolean o1, Boolean o2) {
+ return o1.compareTo(o2);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/ClassLoaderProvider.java b/opends/src/server/org/opends/server/admin/ClassLoaderProvider.java
new file mode 100644
index 0000000..91643c9
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ClassLoaderProvider.java
@@ -0,0 +1,637 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.loggers.Error.logError;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.messages.AdminMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.opends.server.admin.std.meta.RootCfgDefn;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.ErrorLogCategory;
+import org.opends.server.types.ErrorLogSeverity;
+import org.opends.server.types.InitializationException;
+import org.opends.server.util.Validator;
+
+
+
+/**
+ * Manages the class loader which should be used for loading
+ * configuration definition classes and associated extensions.
+ * <p>
+ * For extensions which define their own extended configuration
+ * definitions, the class loader will make sure that the configuration
+ * definition classes are loaded and initialized.
+ * <p>
+ * Initially the class loader provider is disabled, and calls to the
+ * {@link #getClassLoader()} will return the system default class
+ * loader.
+ * <p>
+ * Applications <b>MUST NOT</b> maintain persistent references to the
+ * class loader as it can change at run-time.
+ */
+public final class ClassLoaderProvider {
+
+ /**
+ * Private URLClassLoader implementation. This is only required so
+ * that we can provide access to the addURL method.
+ */
+ private static final class MyURLClassLoader extends URLClassLoader {
+
+ /**
+ * Create a class loader with the default parent class loader.
+ */
+ public MyURLClassLoader() {
+ super(new URL[0]);
+ }
+
+
+
+ /**
+ * Create a class loader with the provided parent class loader.
+ *
+ * @param parent
+ * The parent class loader.
+ */
+ public MyURLClassLoader(ClassLoader parent) {
+ super(new URL[0], parent);
+ }
+
+
+
+ /**
+ * Add a Jar file to this class loader.
+ *
+ * @param jarFile
+ * The name of the Jar file.
+ * @throws MalformedURLException
+ * If a protocol handler for the URL could not be found,
+ * or if some other error occurred while constructing
+ * the URL.
+ * @throws SecurityException
+ * If a required system property value cannot be
+ * accessed.
+ */
+ public void addJarFile(File jarFile) throws SecurityException,
+ MalformedURLException {
+ addURL(jarFile.toURI().toURL());
+ }
+
+ }
+
+ // The name of the manifest file listing the core configuration
+ // definition classes.
+ private static final String CORE_MANIFEST = "core.manifest";
+
+ // The name of the manifest file listing a extension's configuration
+ // definition classes.
+ private static final String EXTENSION_MANIFEST = "extension.manifest";
+
+ // The name of the lib directory.
+ private static final String LIB_DIR = "lib";
+
+ // The name of the extensions directory.
+ private static final String EXTENSIONS_DIR = "extensions";
+
+ // The singleton instance.
+ private static final ClassLoaderProvider INSTANCE = new ClassLoaderProvider();
+
+
+
+ /**
+ * Get the single application wide class loader provider instance.
+ *
+ * @return Returns the single application wide class loader provider
+ * instance.
+ */
+ public static ClassLoaderProvider getInstance() {
+ return INSTANCE;
+ }
+
+ // Set of registered Jar files.
+ private Set<File> jarFiles = new HashSet<File>();
+
+ // Underlying class loader used to load classes and resources (null
+ // if disabled).
+ //
+ // We contain a reference to the URLClassLoader rather than
+ // sub-class it so that it is possible to replace the loader at
+ // run-time. For example, when removing or replacing extension Jar
+ // files (the URLClassLoader only supports adding new
+ // URLs, not removal).
+ private MyURLClassLoader loader = null;
+
+
+
+ // Private constructor.
+ private ClassLoaderProvider() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Add the named extensions to this class loader provider.
+ *
+ * @param extensions
+ * The names of the extensions to be loaded. The names
+ * should not contain any path elements and must be located
+ * within the extensions folder.
+ * @throws InitializationException
+ * If one of the extensions could not be loaded and
+ * initialized.
+ * @throws IllegalStateException
+ * If this class loader provider is disabled.
+ * @throws IllegalArgumentException
+ * If one of the extension names was not a single relative
+ * path name element or was an absolute path.
+ */
+ public synchronized void addExtension(String... extensions)
+ throws InitializationException, IllegalStateException,
+ IllegalArgumentException {
+ Validator.ensureNotNull(extensions);
+
+ if (loader == null) {
+ throw new IllegalStateException(
+ "Class loader provider is disabled.");
+ }
+
+ File libPath = new File(DirectoryServer.getServerRoot(), LIB_DIR);
+ File extensionsPath = new File(libPath, EXTENSIONS_DIR);
+
+ ArrayList<File> files = new ArrayList<File>(extensions.length);
+ for (String extension : extensions) {
+ File file = new File(extensionsPath, extension);
+
+ // For security reasons we need to make sure that the file name
+ // passed in did not contain any path elements and names a file
+ // in the extensions folder.
+
+ // Can handle potential null parent.
+ if (!extensionsPath.equals(file.getParentFile())) {
+ throw new IllegalArgumentException("Illegal file name: "
+ + extension);
+ }
+
+ // The file is valid.
+ files.add(file);
+ }
+
+ // Add the extensions.
+ addExtension(files.toArray(new File[files.size()]));
+ }
+
+
+
+ /**
+ * Disable this class loader provider and removed any registered
+ * extensions.
+ *
+ * @throws IllegalStateException
+ * If this class loader provider is already disabled.
+ */
+ public synchronized void disable() throws IllegalStateException {
+ if (loader == null) {
+ throw new IllegalStateException(
+ "Class loader provider already disabled.");
+ }
+ loader = null;
+ jarFiles = new HashSet<File>();
+ }
+
+
+
+ /**
+ * Enable this class loader provider using the default parent class
+ * loader.
+ *
+ * @throws InitializationException
+ * If the class loader provider could not initialize
+ * successfully.
+ * @throws IllegalStateException
+ * If this class loader provider is already enabled.
+ */
+ public synchronized void enable() throws InitializationException,
+ IllegalStateException {
+ enable(null);
+ }
+
+
+
+ /**
+ * Enable this class loader provider using the provided parent class
+ * loader.
+ *
+ * @param parent
+ * The parent class loader.
+ * @throws InitializationException
+ * If the class loader provider could not initialize
+ * successfully.
+ * @throws IllegalStateException
+ * If this class loader provider is already enabled.
+ */
+ public synchronized void enable(ClassLoader parent)
+ throws InitializationException, IllegalStateException {
+ if (loader != null) {
+ throw new IllegalStateException(
+ "Class loader provider already enabled.");
+ }
+
+ if (parent != null) {
+ loader = new MyURLClassLoader(parent);
+ } else {
+ loader = new MyURLClassLoader();
+ }
+
+ // Forcefully load all configuration definition classes in
+ // OpenDS.jar.
+ initializeCoreComponents();
+
+ // Put extensions jars into the class loader and load all
+ // configuration definition classes in that they contain.
+ initializeAllExtensions();
+ }
+
+
+
+ /**
+ * Gets the class loader which should be used for loading classes
+ * and resources. When this class loader provider is disabled, the
+ * system default class loader will be returned by default.
+ * <p>
+ * Applications <b>MUST NOT</b> maintain persistent references to
+ * the class loader as it can change at run-time.
+ *
+ * @return Returns the class loader which should be used for loading
+ * classes and resources.
+ */
+ public synchronized ClassLoader getClassLoader() {
+ if (loader != null) {
+ return loader;
+ } else {
+ return ClassLoader.getSystemClassLoader();
+ }
+ }
+
+
+
+ /**
+ * Indicates whether this class loader provider is enabled.
+ *
+ * @return Returns <code>true</code> if this class loader provider
+ * is enabled.
+ */
+ public synchronized boolean isEnabled() {
+ return loader != null;
+ }
+
+
+
+ /**
+ * Add the named extensions to this class loader.
+ *
+ * @param extensions
+ * The names of the extensions to be loaded.
+ * @throws InitializationException
+ * If one of the extensions could not be loaded and
+ * initialized.
+ */
+ private synchronized void addExtension(File... extensions)
+ throws InitializationException {
+ // First add the Jar files to the class loader.
+ List<JarFile> jars = new LinkedList<JarFile>();
+ for (File extension : extensions) {
+ if (jarFiles.contains(extension)) {
+ // Skip this file as it is already loaded.
+ continue;
+ }
+
+ // Attempt to load it.
+ jars.add(loadJarFile(extension));
+
+ // Register the Jar file with the class loader.
+ try {
+ loader.addJarFile(extension);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_OPEN_JAR_FILE;
+ String message = getMessage(msgID, extension.getName(),
+ extension.getParent(), stackTraceToSingleLineString(e));
+
+ throw new InitializationException(msgID, message);
+ }
+ jarFiles.add(extension);
+ }
+
+ // Now forcefully load the configuration definition classes.
+ for (JarFile jar : jars) {
+ initializeExtension(jar);
+ }
+ }
+
+
+
+ /**
+ * Put extensions jars into the class loader and load all
+ * configuration definition classes in that they contain.
+ *
+ * @throws InitializationException
+ * If the extensions folder could not be accessed or if a
+ * extension jar file could not be accessed or if one of
+ * the configuration definition classes could not be
+ * initialized.
+ */
+ private void initializeAllExtensions()
+ throws InitializationException {
+ File libPath = new File(DirectoryServer.getServerRoot(), LIB_DIR);
+ File extensionsPath = new File(libPath, EXTENSIONS_DIR);
+
+ try {
+ if (!extensionsPath.exists()) {
+ // The extensions directory does not exist. This is not a
+ // critical problem.
+ int msgID = MSGID_ADMIN_NO_EXTENSIONS_DIR;
+ String message = getMessage(msgID, extensionsPath);
+
+ logError(ErrorLogCategory.EXTENSIONS,
+ ErrorLogSeverity.MILD_ERROR, message, msgID);
+ return;
+ }
+
+ if (!extensionsPath.isDirectory()) {
+ // The extensions directory is not a directory. This is more
+ // critical.
+ int msgID = MSGID_ADMIN_EXTENSIONS_DIR_NOT_DIRECTORY;
+ String message = getMessage(msgID, extensionsPath);
+
+ throw new InitializationException(msgID, message);
+ }
+
+ // Get each extension file name.
+ FileFilter filter = new FileFilter() {
+
+ /**
+ * Must be a Jar file.
+ */
+ public boolean accept(File pathname) {
+ if (!pathname.isFile()) {
+ return false;
+ }
+
+ String name = pathname.getName();
+ return name.endsWith(".jar");
+ }
+
+ };
+
+ // Add and initialize the extensions.
+ addExtension(extensionsPath.listFiles(filter));
+ } catch (InitializationException e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ throw e;
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_EXTENSIONS_CANNOT_LIST_FILES;
+ String message = getMessage(msgID, extensionsPath,
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
+ }
+
+
+
+ /**
+ * Make sure all core configuration definitions are loaded.
+ *
+ * @throws InitializationException
+ * If the core manifest file could not be read or if one
+ * of the configuration definition classes could not be
+ * initialized.
+ */
+ private void initializeCoreComponents()
+ throws InitializationException {
+ InputStream is = RootCfgDefn.class.getResourceAsStream("/admin/"
+ + CORE_MANIFEST);
+
+ if (is == null) {
+ int msgID = MSGID_ADMIN_CANNOT_FIND_CORE_MANIFEST;
+ String message = getMessage(msgID, CORE_MANIFEST);
+ throw new InitializationException(msgID, message);
+ }
+
+ try {
+ loadDefinitionClasses(is);
+ } catch (IOException e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_READ_CORE_MANIFEST;
+ String message = getMessage(msgID, CORE_MANIFEST,
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_CORE_MANIFEST;
+ String message = getMessage(msgID, CORE_MANIFEST,
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ }
+ }
+
+
+
+ /**
+ * Make sure all the configuration definition classes in a extension
+ * are loaded.
+ *
+ * @param jarFile
+ * The extension's Jar file.
+ * @throws InitializationException
+ * If the extension jar file could not be accessed or if
+ * one of the configuration definition classes could not
+ * be initialized.
+ */
+ private void initializeExtension(JarFile jarFile)
+ throws InitializationException {
+ JarEntry entry = jarFile.getJarEntry("admin/"
+ + EXTENSION_MANIFEST);
+ if (entry != null) {
+ InputStream is;
+ try {
+ is = jarFile.getInputStream(entry);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_READ_EXTENSION_MANIFEST;
+ String message = getMessage(msgID, EXTENSION_MANIFEST,
+ jarFile.getName(), stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ }
+
+ try {
+ loadDefinitionClasses(is);
+ } catch (IOException e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_READ_EXTENSION_MANIFEST;
+ String message = getMessage(msgID, EXTENSION_MANIFEST,
+ jarFile.getName(), stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_EXTENSION_MANIFEST;
+ String message = getMessage(msgID, EXTENSION_MANIFEST,
+ jarFile.getName(), stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message);
+ }
+ }
+ }
+
+
+
+ /**
+ * Forcefully load configuration definition classes named in a
+ * manifest file.
+ *
+ * @param is
+ * The manifest file input stream.
+ * @throws IOException
+ * If an IO error occurred whilst reading the manifest
+ * file.
+ * @throws ClassNotFoundException
+ * If an IO error occurred whilst reading the manifest
+ * file.
+ * @throws LinkageError
+ * If the linkage fails.
+ * @throws ExceptionInInitializerError
+ * If the initialization provoked by this method fails.
+ */
+ private void loadDefinitionClasses(InputStream is)
+ throws IOException, ClassNotFoundException, LinkageError,
+ ExceptionInInitializerError {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ is));
+ while (true) {
+ String className = reader.readLine();
+
+ // Break out when the end of the manifest is reached.
+ if (className == null) {
+ break;
+ }
+
+ // Skip blank lines.
+ className = className.trim();
+ if (className.length() == 0) {
+ continue;
+ }
+
+ // Skip lines beginning with #.
+ if (className.startsWith("#")) {
+ continue;
+ }
+
+ debugMessage(DebugLogLevel.INFO, "Loading class " + className);
+
+ // Use the underlying loader.
+ Class.forName(className, true, loader);
+ }
+ }
+
+
+
+ /**
+ * Load the named Jar file.
+ *
+ * @param jar
+ * The name of the Jar file to load.
+ * @return Returns the loaded Jar file.
+ * @throws InitializationException
+ * If the Jar file could not be loaded.
+ */
+ private JarFile loadJarFile(File jar)
+ throws InitializationException {
+ JarFile jarFile;
+
+ try {
+ // Load the extension jar file.
+ jarFile = new JarFile(jar);
+ } catch (Exception e) {
+ if (debugEnabled()) {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_ADMIN_CANNOT_OPEN_JAR_FILE;
+ String message = getMessage(msgID, jar.getName(), jar
+ .getParent(), stackTraceToSingleLineString(e));
+
+ throw new InitializationException(msgID, message);
+ }
+ return jarFile;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/ClassPropertyDefinition.java b/opends/src/server/org/opends/server/admin/ClassPropertyDefinition.java
new file mode 100644
index 0000000..0cd011e
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ClassPropertyDefinition.java
@@ -0,0 +1,370 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+
+
+
+/**
+ * Class property definition.
+ * <p>
+ * A class property definition defines a property whose values
+ * represent a Java class. It is possible to restrict the type of java
+ * class by specifying "instance of" constraints.
+ * <p>
+ * Note that in a client/server environment, the client is probably
+ * not capable of validating the Java class (e.g. it will not be able
+ * to load it nor have access to the interfaces it is supposed to
+ * implement). For this reason, it is possible to switch off
+ * validation in the client by calling the static method
+ * {@link #setAllowClassValidation(boolean)}.
+ */
+public final class ClassPropertyDefinition extends
+ AbstractPropertyDefinition<String> {
+
+ /**
+ * An interface for incrementally constructing class property
+ * definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<String, ClassPropertyDefinition> {
+
+ // List of interfaces which property values must implement.
+ private List<String> instanceOfInterfaces;
+
+
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+
+ this.instanceOfInterfaces = new LinkedList<String>();
+ }
+
+
+
+ /**
+ * Add an class name which property values must implement.
+ *
+ * @param className
+ * The name of a class which property values must
+ * implement.
+ */
+ public final void addInstanceOf(String className) {
+ ensureNotNull(className);
+
+ // Do some basic checks to make sure the string representation
+ // is valid.
+ String value = className.trim();
+ if (!value.matches(CLASS_RE)) {
+ throw new IllegalArgumentException("\"" + value
+ + "\" is not a valid Java class name");
+ }
+
+ // If possible try and load the class in order to perform
+ // additional
+ // validation.
+ if (isAllowClassValidation()) {
+ // Check that the class can be loaded so that validation can
+ // be
+ // performed.
+ try {
+ loadClass(value);
+ } catch (ClassNotFoundException e) {
+ // TODO: can we do something better here?
+ throw new RuntimeException(e);
+ }
+ }
+
+ instanceOfInterfaces.add(value);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ClassPropertyDefinition buildInstance(
+ String propertyName, EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<String> defaultBehavior) {
+ return new ClassPropertyDefinition(propertyName, options,
+ defaultBehavior, instanceOfInterfaces);
+ }
+
+ }
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -7775867133238274392L;
+
+ // Regular expression for validating class names.
+ private static final String CLASS_RE =
+ "^([A-Za-z]+[A-Za-z0-9_]*)*(\\.[A-Za-z]+[A-Za-z0-9_]*)"
+ + "*([\\$][A-Za-z0-9_]+)*$";
+
+ // Flag indicating whether class property values should be
+ // validated.
+ private static boolean allowClassValidation = true;
+
+
+
+ /**
+ * Create a class property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new class property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ /**
+ * Determine whether or not class property definitions should
+ * validate class name property values. Validation involves checking
+ * that the class exists and that it implements the required
+ * interfaces.
+ *
+ * @return Returns <code>true</code> if class property definitions
+ * should validate class name property values.
+ */
+ public static boolean isAllowClassValidation() {
+ return allowClassValidation;
+ }
+
+
+
+ /**
+ * Specify whether or not class property definitions should validate
+ * class name property values. Validation involves checking that the
+ * class exists and that it implements the required interfaces.
+ * <p>
+ * By default validation is switched on.
+ *
+ * @param value
+ * <code>true</code> if class property definitions should
+ * validate class name property values.
+ */
+ public static void setAllowClassValidation(boolean value) {
+ allowClassValidation = value;
+ }
+
+
+
+ // Load a named class.
+ private static Class<?> loadClass(String className)
+ throws ClassNotFoundException, LinkageError {
+ return Class.forName(className, true, ClassLoaderProvider
+ .getInstance().getClassLoader());
+ }
+
+ // List of interfaces which property values must implement.
+ private final List<String> instanceOfInterfaces;
+
+
+
+ // Private constructor.
+ private ClassPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<String> defaultBehavior,
+ List<String> instanceOfInterfaces) {
+ super(String.class, propertyName, options, defaultBehavior);
+
+ this.instanceOfInterfaces = Collections
+ .unmodifiableList(new LinkedList<String>(instanceOfInterfaces));
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitClass(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ try {
+ validateValue(value);
+ } catch (IllegalPropertyValueException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ return value;
+ }
+
+
+
+ /**
+ * Get an unmodifiable list of classes which values of this property
+ * must implement.
+ *
+ * @return Returns an unmodifiable list of classes which values of
+ * this property must implement.
+ */
+ public List<String> getInstanceOfInterface() {
+ return instanceOfInterfaces;
+ }
+
+
+
+ /**
+ * Validate and load the named class, and cast it to a subclass of
+ * the specified class.
+ *
+ * @param <T>
+ * The requested type.
+ * @param className
+ * The name of the class to validate and load.
+ * @param instanceOf
+ * The class representing the requested type.
+ * @return Returns the named class cast to a subclass of the
+ * specified class.
+ * @throws IllegalPropertyValueException
+ * If the named class was invalid, could not be loaded, or
+ * did not implement the required interfaces.
+ * @throws ClassCastException
+ * If the referenced class does not implement the
+ * requested type.
+ */
+ public <T> Class<? extends T> loadClass(String className,
+ Class<T> instanceOf) throws IllegalPropertyValueException,
+ ClassCastException {
+ ensureNotNull(className, instanceOf);
+
+ // Make sure that the named class is valid.
+ validateClassName(className);
+ Class<?> theClass = validateClassInterfaces(className);
+
+ // Cast it to the required type.
+ return theClass.asSubclass(instanceOf);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String normalizeValue(String value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ return value.trim();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(String value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // Always make sure the name is a valid class name.
+ validateClassName(value);
+
+ // If additional validation is enabled then attempt to load the
+ // class and
+ // check the interfaces that it implements/extends.
+ if (allowClassValidation) {
+ validateClassInterfaces(value);
+ }
+ }
+
+
+
+ // Make sure that named class implements the interfaces named by
+ // this
+ // definition.
+ private Class<?> validateClassInterfaces(String className)
+ throws IllegalPropertyValueException {
+ String nvalue = className.trim();
+
+ Class<?> theClass;
+ try {
+ theClass = loadClass(nvalue);
+ } catch (Exception e) {
+ // If the class cannot be loaded then it is an invalid value.
+ throw new IllegalPropertyValueException(this, className);
+ }
+
+ for (String i : instanceOfInterfaces) {
+ try {
+ Class<?> instanceOfClass = loadClass(i);
+
+ if (!instanceOfClass.isAssignableFrom(theClass)) {
+ throw new IllegalPropertyValueException(this, className);
+ }
+ } catch (Exception e) {
+ // Should not happen because the class was validated when the
+ // property
+ // definition was constructed.
+ throw new IllegalPropertyValueException(this, className);
+ }
+ }
+
+ return theClass;
+ }
+
+
+
+ // Do some basic checks to make sure the string representation is
+ // valid.
+ private void validateClassName(String className)
+ throws IllegalPropertyValueException {
+ String nvalue = className.trim();
+ if (!nvalue.matches(CLASS_RE)) {
+ throw new IllegalPropertyValueException(this, className);
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/Configuration.java b/opends/src/server/org/opends/server/admin/Configuration.java
new file mode 100644
index 0000000..564618d
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/Configuration.java
@@ -0,0 +1,70 @@
+/*
+ * 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.admin;
+
+
+
+import org.opends.server.types.DN;
+
+
+
+/**
+ * A common base interface for all server managed object
+ * configurations.
+ */
+public interface Configuration {
+
+ /**
+ * Get the DN of the LDAP entry associated with this configuration.
+ *
+ * @return Returns the DN of the LDAP entry associated with this
+ * configuration.
+ */
+ DN dn();
+
+
+
+ /**
+ * Get the configuration definition associated with this
+ * configuration.
+ *
+ * @return Returns the configuration definition associated with this
+ * configuration.
+ */
+ ManagedObjectDefinition<? extends ConfigurationClient,
+ ? extends Configuration> definition();
+
+
+
+ /**
+ * Get a property provider view of this configuration.
+ *
+ * @return Returns a property provider view of this configuration.
+ */
+ PropertyProvider properties();
+}
diff --git a/opends/src/server/org/opends/server/admin/ConfigurationClient.java b/opends/src/server/org/opends/server/admin/ConfigurationClient.java
new file mode 100644
index 0000000..f84e67b
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ConfigurationClient.java
@@ -0,0 +1,69 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A common base interface for all managed object configuration
+ * clients.
+ */
+public interface ConfigurationClient {
+
+ /**
+ * Get the configuration definition associated with this
+ * configuration.
+ *
+ * @return Returns the configuration definition associated with this
+ * configuration.
+ */
+ ManagedObjectDefinition<? extends ConfigurationClient,
+ ? extends Configuration> definition();
+
+
+
+ /**
+ * Get a property provider view of this configuration.
+ *
+ * @return Returns a property provider view of this configuration.
+ */
+ PropertyProvider properties();
+
+
+
+ /**
+ * Commit any changes made to this configuration client.
+ *
+ * @throws OperationsException
+ * If the changes to this configuration client could not
+ * be committed due to some underlying communication
+ * problem.
+ */
+ void commit() throws OperationsException;
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DNPropertyDefinition.java b/opends/src/server/org/opends/server/admin/DNPropertyDefinition.java
new file mode 100644
index 0000000..dada623
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DNPropertyDefinition.java
@@ -0,0 +1,227 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+
+
+
+/**
+ * DN property definition.
+ */
+public final class DNPropertyDefinition extends
+ AbstractPropertyDefinition<DN> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -380704355977504890L;
+
+ // Optional base DN which all valid values must be immediately
+ // subordinate to.
+ private final DN baseDN;
+
+
+
+ /**
+ * An interface for incrementally constructing DN property
+ * definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<DN, DNPropertyDefinition> {
+
+ // Optional base DN which all valid values must be immediately
+ // subordinate to.
+ private DN baseDN = null;
+
+
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * Set the base DN which all valid values must be immediately
+ * subordinate to. By default there is no based DN.
+ *
+ * @param baseDN
+ * The string representation of the base DN.
+ * @throws IllegalArgumentException
+ * If the provided string is not a valid DN string
+ * representation.
+ */
+ public void setBaseDN(String baseDN)
+ throws IllegalArgumentException {
+ if (baseDN == null) {
+ setBaseDN((DN) null);
+ } else {
+ try {
+ setBaseDN(DN.decode(baseDN));
+ } catch (DirectoryException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ }
+
+
+
+ /**
+ * Set the base DN which all valid values must be immediately
+ * subordinate to. By default there is no based DN.
+ *
+ * @param baseDN
+ * The base DN.
+ */
+ public void setBaseDN(DN baseDN) {
+ this.baseDN = baseDN;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected DNPropertyDefinition buildInstance(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<DN> defaultBehavior) {
+ return new DNPropertyDefinition(propertyName, options,
+ defaultBehavior, baseDN);
+ }
+ }
+
+
+
+ /**
+ * Create a DN property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new boolean property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private DNPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<DN> defaultBehavior, DN baseDN) {
+ super(DN.class, propertyName, options, defaultBehavior);
+ this.baseDN = baseDN;
+ }
+
+
+
+ /**
+ * Get the base DN which all valid values must be immediately
+ * subordinate to, or <code>null</code> if there is no based DN.
+ *
+ * @return Returns the base DN which all valid values must be
+ * immediately subordinate to.
+ */
+ public DN getBaseDN() {
+ return baseDN;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(DN value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ if (baseDN != null) {
+ DN parent = value.getParent();
+
+ if (parent == null) {
+ parent = DN.nullDN();
+ }
+
+ if (!parent.equals(baseDN)) {
+ throw new IllegalPropertyValueException(this, value);
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DN decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ try {
+ DN dn = DN.decode(value);
+ validateValue(dn);
+ return dn;
+ } catch (DirectoryException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ } catch (IllegalPropertyValueException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitDN(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(DN o1, DN o2) {
+ return o1.compareTo(o2);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/DecodingException.java b/opends/src/server/org/opends/server/admin/DecodingException.java
new file mode 100644
index 0000000..f6cfe85
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DecodingException.java
@@ -0,0 +1,52 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * The requested managed object was found but it could not be decoded.
+ */
+public abstract class DecodingException extends OperationsException {
+
+ /**
+ * Create a decoding exception.
+ */
+ protected DecodingException() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public abstract String getMessage();
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DefaultBehaviorPropertyValueException.java b/opends/src/server/org/opends/server/admin/DefaultBehaviorPropertyValueException.java
new file mode 100644
index 0000000..c06c24e
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DefaultBehaviorPropertyValueException.java
@@ -0,0 +1,93 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown to indicate that a property's default values were invalid.
+ */
+public class DefaultBehaviorPropertyValueException extends PropertyException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 8653244240567431537L;
+
+ // The underlying property exception that caused this exception
+ private final PropertyException cause;
+
+
+
+ /**
+ * Create a new default behavior property value exception.
+ *
+ * @param d
+ * The property definition.
+ * @param cause
+ * The property exception that caused this exception.
+ */
+ public DefaultBehaviorPropertyValueException(PropertyDefinition d,
+ PropertyException cause) {
+ super(d);
+ this.cause = cause;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Throwable getCause() {
+ return cause;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "The default values could not be determined "
+ + "for the property \"" + getPropertyDefinition().getName() + "\"";
+ }
+
+
+
+ /**
+ * Get the property exception that caused this exception.
+ *
+ * @return Returns the property exception that caused this exception.
+ */
+ public final PropertyException getPropertyException() {
+ return cause;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DefaultBehaviorProvider.java b/opends/src/server/org/opends/server/admin/DefaultBehaviorProvider.java
new file mode 100644
index 0000000..565f7d1
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DefaultBehaviorProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * An interface for determining the default behavior of a property. A property
+ * exhibits default behavior when it has no values defined. There are four
+ * different types of default behavior:
+ * <ol>
+ * <li>there is no default behavior - e.g. leaving a "description" unset has
+ * no side-effects. This default behavior is represented using the
+ * {@link UndefinedDefaultBehaviorProvider} implementation
+ * <li>the property defaults to one or more real values of the property. This
+ * default behavior is represented using the
+ * {@link DefinedDefaultBehaviorProvider} implementation
+ * <li>the property defaults to some special behavior that cannot be
+ * represented using real property values. This default behavior is represented
+ * using the {@link AliasDefaultBehaviorProvider} implementation
+ * <li>the property inherits its values from property held in another managed
+ * object (e.g. the parent managed object). This default behavior is
+ * represented using the {@link AbsoluteInheritedDefaultBehaviorProvider} and
+ * {@link RelativeInheritedDefaultBehaviorProvider} implementations.
+ * </ol>
+ * An application can perform actions based on the type of the default behavior
+ * by implementing the {@link DefaultBehaviorProviderVisitor} interface.
+ *
+ * @param <T>
+ * The type of values represented by this provider.
+ */
+public interface DefaultBehaviorProvider<T> {
+
+ /**
+ * Apply a visitor to this default behavior provider.
+ *
+ * @param <R>
+ * The return type of the visitor's methods.
+ * @param <P>
+ * The type of the additional parameters to the visitor's methods.
+ * @param v
+ * The default behavior visitor.
+ * @param p
+ * Optional additional visitor parameter.
+ * @return Returns a result as specified by the visitor.
+ */
+ <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p);
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DefaultBehaviorProviderVisitor.java b/opends/src/server/org/opends/server/admin/DefaultBehaviorProviderVisitor.java
new file mode 100644
index 0000000..075d986
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DefaultBehaviorProviderVisitor.java
@@ -0,0 +1,116 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A visitor of default behavior providers, in the style of the visitor design
+ * pattern. Classes implementing this interface can query default behavior
+ * providers in a type-safe manner when the kind of default behavior provider
+ * is unknown at compile time. When a visitor is passed to a default behavior
+ * provider's accept method, the corresponding visit method most applicable to
+ * that default behavior provider is invoked.
+ *
+ * @param <T>
+ * The type of values represented by the default value provider.
+ * @param <R>
+ * The return type of this visitor's methods. Use
+ * {@link java.lang.Void} for visitors that do not need to return
+ * results.
+ * @param <P>
+ * The type of the additional parameter to this visitor's methods. Use
+ * {@link java.lang.Void} for visitors that do not need an additional
+ * parameter.
+ */
+public interface DefaultBehaviorProviderVisitor<T, R, P> {
+
+ /**
+ * Visit an absolute inherited default behavior provider.
+ *
+ * @param d
+ * The absolute inherited default behavior provider to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider<T> d, P p);
+
+
+
+ /**
+ * Visit an alias default behavior provider.
+ *
+ * @param d
+ * The alias default behavior provider to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitAlias(AliasDefaultBehaviorProvider<T> d, P p);
+
+
+
+ /**
+ * Visit an defined default behavior provider.
+ *
+ * @param d
+ * The defined default behavior provider to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitDefined(DefinedDefaultBehaviorProvider<T> d, P p);
+
+
+
+ /**
+ * Visit a relative inherited default behavior provider.
+ *
+ * @param d
+ * The relative inherited default behavior provider to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider<T> d, P p);
+
+
+
+ /**
+ * Visit an undefined default behavior provider.
+ *
+ * @param d
+ * The undefined default behavior provider to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitUndefined(UndefinedDefaultBehaviorProvider<T> d, P p);
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DefinedDefaultBehaviorProvider.java b/opends/src/server/org/opends/server/admin/DefinedDefaultBehaviorProvider.java
new file mode 100644
index 0000000..a55be34
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DefinedDefaultBehaviorProvider.java
@@ -0,0 +1,93 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+
+
+/**
+ * A default behavior provider which represents a well-defined set of default
+ * values. It should be used by properties which have default value(s) which are
+ * valid value(s) according to the constraints of the property's definition.
+ *
+ * @param <T>
+ * The type of values represented by this provider.
+ */
+public final class DefinedDefaultBehaviorProvider<T> implements
+ DefaultBehaviorProvider<T> {
+
+ // The collection of default values.
+ private final Collection<String> values;
+
+
+
+ /**
+ * Create a new defined default behavior provider associated with the
+ * specified list of values.
+ *
+ * @param values
+ * The list of values (must be non-<code>null</code> and not
+ * empty) in their string representation.
+ * @throws IllegalArgumentException
+ * If the list of values was <code>null</code> or empty.
+ */
+ public DefinedDefaultBehaviorProvider(String... values)
+ throws IllegalArgumentException {
+ if (values == null || values.length == 0) {
+ throw new IllegalArgumentException(
+ "Null or empty list of default values");
+ }
+ this.values = Arrays.asList(values);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
+ return v.visitDefined(this, p);
+ }
+
+
+
+ /**
+ * Get a copy of the default values.
+ *
+ * @return Returns a newly allocated collection containing a copy of the
+ * default values.
+ */
+ public Collection<String> getDefaultValues() {
+ return new ArrayList<String>(values);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DefinitionDecodingException.java b/opends/src/server/org/opends/server/admin/DefinitionDecodingException.java
new file mode 100644
index 0000000..d5f49ae
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DefinitionDecodingException.java
@@ -0,0 +1,125 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * The requested managed object was found but its type could not be
+ * determined.
+ */
+public class DefinitionDecodingException extends DecodingException {
+
+ /**
+ * Version ID required by serializable classes.
+ */
+ private static final long serialVersionUID = 3459033551415663416L;
+
+
+
+ /**
+ * An enumeration defining the reasons why the definition could not be
+ * resolved.
+ */
+ public static enum Reason {
+ /**
+ * The managed object could be found but did not contain any type
+ * information (eg missing object classes in LDAP).
+ */
+ NO_TYPE_INFORMATION(
+ "The managed object could be found but did not contain any"
+ + " type information (e.g. missing object classes in LDAP)."),
+
+ /**
+ * The managed object could be found but did not contain the expected type
+ * information (eg incorrect object classes in LDAP).
+ */
+ WRONG_TYPE_INFORMATION(
+ "The managed object could be found but did not contain the"
+ + " expected type information (e.g. incorrect object"
+ + " classes in LDAP)."),
+
+ /**
+ * The managed object could be found but its type resolved to an abstract
+ * managed object definition.
+ */
+ ABSTRACT_TYPE_INFORMATION(
+ "The managed object could be found but its type resolved to an"
+ + " abstract managed object definition.");
+
+ // Simple description of this reason for debugging.
+ private String msg;
+
+
+
+ // Private constructor.
+ private Reason(String msg) {
+ this.msg = msg;
+ }
+
+ }
+
+
+
+ // The reason why the definition could not be determined.
+ private final Reason reason;
+
+
+
+ /**
+ * Create a new definition decoding exception.
+ *
+ * @param reason
+ * The reason why the definition could not be determined.
+ */
+ public DefinitionDecodingException(Reason reason) {
+ this.reason = reason;
+ }
+
+
+
+ /**
+ * Get the reason why the definition could not be determined.
+ *
+ * @return Returns the reason why the definition could not be determined.
+ */
+ public Reason getReason() {
+ return reason;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return reason.msg;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DefinitionResolver.java b/opends/src/server/org/opends/server/admin/DefinitionResolver.java
new file mode 100644
index 0000000..9b795f4
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DefinitionResolver.java
@@ -0,0 +1,72 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * This interface is used to determine the "best match" managed object
+ * definition in a definition hierarchy.
+ * <p>
+ * Managed object definitions, like Java classes, are arranged in an
+ * inheritance hierarchy. When managed objects are decoded (e.g. from
+ * LDAP entries), the driver implementation is provided with an
+ * "expected managed object definition". However, the actual decoded
+ * managed object is often an instance of a sub-type of this
+ * definition. For example, when decoding a connection handler managed
+ * object, the actual type can never be a connection handler because
+ * it is an abstract managed object type. Instead, the decoded managed
+ * object must be a "concrete" sub-type: an LDAP connection handler or
+ * JMX connection handler.
+ * <p>
+ * This resolution process is coordinated by the
+ * <code>resolveManagedObjectDefinition</code> method in managed
+ * object definitions, where it is passed a
+ * <code>DefinitionResolver</code> implementation. The
+ * <code>resolveManagedObjectDefinition</code> method takes care of
+ * recursively descending through the definition hierarchy and invokes
+ * the {@link #matches(AbstractManagedObjectDefinition)} method
+ * against each potential sub-type. It is the job of the resolver to
+ * indicate whether the provided managed object definition is a
+ * candidate definition. For example, the LDAP driver provides a
+ * definition resolver which uses the decoded LDAP entry's object
+ * classes to determine the final appropriate managed object
+ * definition.
+ */
+public interface DefinitionResolver {
+
+ /**
+ * Determines whether or not the provided managed object definition matches
+ * this resolver's criteria.
+ *
+ * @param d
+ * The managed object definition.
+ * @return Returns <code>true</code> if the the provided managed object
+ * definition matches this resolver's criteria.
+ */
+ boolean matches(AbstractManagedObjectDefinition<?, ?> d);
+}
diff --git a/opends/src/server/org/opends/server/admin/DurationPropertyDefinition.java b/opends/src/server/org/opends/server/admin/DurationPropertyDefinition.java
new file mode 100644
index 0000000..b8b77db
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DurationPropertyDefinition.java
@@ -0,0 +1,579 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+
+/**
+ * Duration property definition.
+ * <p>
+ * A duration property definition comprises of:
+ * <ul>
+ * <li>a <i>base unit</i> - specifies the minimum granularity which
+ * can be used to specify duration property values. For example, if
+ * the base unit is in seconds then values represented in milliseconds
+ * will not be permitted. The default base unit is seconds
+ * <li>an optional <i>maximum unit</i> - specifies the biggest
+ * duration unit which can be used to specify duration property
+ * values. Values presented in units greater than this unit will not
+ * be permitted. There is no default maximum unit
+ * <li><i>lower limit</i> - specifies the smallest duration
+ * permitted by the property. The default lower limit is 0 and can
+ * never be less than 0
+ * <li>an optional <i>upper limit</i> - specifies the biggest
+ * duration permitted by the property. By default, there is no upper
+ * limit
+ * <li>support for <i>unlimited</i> durations - when permitted users
+ * can specify "unlimited" durations. These are represented using the
+ * decoded value, -1, or the encoded string value "unlimited". By
+ * default, unlimited durations are not permitted. In addition, it is
+ * not possible to define an upper limit and support unlimited values.
+ * </ul>
+ * Decoded values are represented using <code>long</code> values in
+ * the base unit defined for the duration property definition.
+ */
+public final class DurationPropertyDefinition extends
+ AbstractPropertyDefinition<Long> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -1491050690542547075L;
+
+ // String used to represent unlimited durations.
+ private static final String UNLIMITED = "unlimited";
+
+ // The base unit for this property definition (values including
+ // limits are specified in this unit).
+ private final DurationUnit baseUnit;
+
+ // The optional maximum unit for this property definition.
+ private final DurationUnit maximumUnit;
+
+ // The lower limit of the property value.
+ private final long lowerLimit;
+
+ // The optional upper limit of the property value.
+ private final Long upperLimit;
+
+ // Indicates whether this property allows the use of the "unlimited"
+ // duration value (represented using a -1L or the string
+ // "unlimited").
+ private final boolean allowUnlimited;
+
+
+
+ /**
+ * An interface for incrementally constructing duration property
+ * definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<Long, DurationPropertyDefinition> {
+
+ // The base unit for this property definition (values including
+ // limits are specified in this unit).
+ private DurationUnit baseUnit = DurationUnit.SECONDS;
+
+ // The optional maximum unit for this property definition.
+ private DurationUnit maximumUnit = null;
+
+ // The lower limit of the property value.
+ private long lowerLimit = 0L;
+
+ // The optional upper limit of the property value.
+ private Long upperLimit = null;
+
+ // Indicates whether this property allows the use of the
+ // "unlimited" duration value (represented using a -1L or the
+ // string "unlimited").
+ private boolean allowUnlimited = false;
+
+
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * Set the base unit for this property definition (values
+ * including limits are specified in this unit). By default a
+ * duration property definition uses seconds.
+ *
+ * @param unit
+ * The string representation of the base unit (must not
+ * be <code>null</code>).
+ * @throws IllegalArgumentException
+ * If the provided unit name did not correspond to a
+ * known duration unit, or if the base unit is bigger
+ * than the maximum unit.
+ */
+ public final void setBaseUnit(String unit)
+ throws IllegalArgumentException {
+ ensureNotNull(unit);
+
+ setBaseUnit(DurationUnit.getUnit(unit));
+ }
+
+
+
+ /**
+ * Set the base unit for this property definition (values
+ * including limits are specified in this unit). By default a
+ * duration property definition uses seconds.
+ *
+ * @param unit
+ * The base unit (must not be <code>null</code>).
+ * @throws IllegalArgumentException
+ * If the provided base unit is bigger than the maximum
+ * unit.
+ */
+ public final void setBaseUnit(DurationUnit unit)
+ throws IllegalArgumentException {
+ ensureNotNull(unit);
+
+ // Make sure that the base unit is not bigger than the maximum
+ // unit.
+ if (maximumUnit != null) {
+ if (unit.getDuration() > maximumUnit.getDuration()) {
+ throw new IllegalArgumentException(
+ "Base unit greater than maximum unit");
+ }
+ }
+
+ this.baseUnit = unit;
+ }
+
+
+
+ /**
+ * Set the maximum unit for this property definition. By default
+ * there is no maximum unit.
+ *
+ * @param unit
+ * The string representation of the maximum unit, or
+ * <code>null</code> if there should not be a maximum
+ * unit.
+ * @throws IllegalArgumentException
+ * If the provided unit name did not correspond to a
+ * known duration unit, or if the maximum unit is
+ * smaller than the base unit.
+ */
+ public final void setMaximumUnit(String unit)
+ throws IllegalArgumentException {
+ if (unit == null) {
+ setMaximumUnit((DurationUnit) null);
+ } else {
+ setMaximumUnit(DurationUnit.getUnit(unit));
+ }
+ }
+
+
+
+ /**
+ * Set the maximum unit for this property definition. By default
+ * there is no maximum unit.
+ *
+ * @param unit
+ * The maximum unit, or <code>null</code> if there
+ * should not be a maximum unit.
+ * @throws IllegalArgumentException
+ * If the provided maximum unit is smaller than the base
+ * unit.
+ */
+ public final void setMaximumUnit(DurationUnit unit)
+ throws IllegalArgumentException {
+ if (unit != null) {
+ // Make sure that the maximum unit is not smaller than the
+ // base unit.
+ if (unit.getDuration() < baseUnit.getDuration()) {
+ throw new IllegalArgumentException(
+ "Maximum unit smaller than base unit");
+ }
+ }
+
+ this.maximumUnit = unit;
+ }
+
+
+
+ /**
+ * Set the lower limit.
+ *
+ * @param lowerLimit
+ * The new lower limit (must be >= 0).
+ * @throws IllegalArgumentException
+ * If a negative lower limit was specified, or the lower
+ * limit is greater than the upper limit.
+ */
+ public final void setLowerLimit(long lowerLimit)
+ throws IllegalArgumentException {
+ if (lowerLimit < 0) {
+ throw new IllegalArgumentException("Negative lower limit");
+ }
+
+ if (upperLimit != null && lowerLimit > upperLimit) {
+ throw new IllegalArgumentException(
+ "Lower limit greater than upper limit");
+ }
+
+ this.lowerLimit = lowerLimit;
+ }
+
+
+
+ /**
+ * Set the upper limit.
+ *
+ * @param upperLimit
+ * The new upper limit or <code>null</code> if there is
+ * no upper limit.
+ * @throws IllegalArgumentException
+ * If a negative upper limit was specified, or the lower
+ * limit is greater than the upper limit or unlimited
+ * durations are permitted.
+ */
+ public final void setUpperLimit(Long upperLimit)
+ throws IllegalArgumentException {
+ if (upperLimit != null) {
+ if (upperLimit < 0) {
+ throw new IllegalArgumentException("Negative upper limit");
+ }
+
+ if (lowerLimit > upperLimit) {
+ throw new IllegalArgumentException(
+ "Lower limit greater than upper limit");
+ }
+
+ if (allowUnlimited) {
+ throw new IllegalArgumentException(
+ "Upper limit specified when unlimited durations are permitted");
+ }
+ }
+
+ this.upperLimit = upperLimit;
+ }
+
+
+
+ /**
+ * Specify whether or not this property definition will allow
+ * unlimited values (default is false).
+ *
+ * @param allowUnlimited
+ * <code>true</code> if the property will allow
+ * unlimited values, or <code>false</code> otherwise.
+ * @throws IllegalArgumentException
+ * If unlimited values are to be permitted but there is
+ * an upper limit specified.
+ */
+ public final void setAllowUnlimited(boolean allowUnlimited)
+ throws IllegalArgumentException {
+ if (allowUnlimited && upperLimit != null) {
+ throw new IllegalArgumentException(
+ "Upper limit specified when unlimited durations are permitted");
+ }
+
+ this.allowUnlimited = allowUnlimited;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected DurationPropertyDefinition buildInstance(
+ String propertyName, EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Long> defaultBehavior) {
+ return new DurationPropertyDefinition(propertyName, options,
+ defaultBehavior, baseUnit, maximumUnit, lowerLimit,
+ upperLimit, allowUnlimited);
+ }
+ }
+
+
+
+ /**
+ * Create a duration property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new integer property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private DurationPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Long> defaultBehavior,
+ DurationUnit baseUnit, DurationUnit maximumUnit,
+ Long lowerLimit, Long upperLimit, boolean allowUnlimited) {
+ super(Long.class, propertyName, options, defaultBehavior);
+ this.baseUnit = baseUnit;
+ this.maximumUnit = maximumUnit;
+ this.lowerLimit = lowerLimit;
+ this.upperLimit = upperLimit;
+ this.allowUnlimited = allowUnlimited;
+ }
+
+
+
+ /**
+ * Get the base unit for this property definition (values including
+ * limits are specified in this unit).
+ *
+ * @return Returns the base unit for this property definition
+ * (values including limits are specified in this unit).
+ */
+ public DurationUnit getBaseUnit() {
+ return baseUnit;
+ }
+
+
+
+ /**
+ * Get the maximum unit for this property definition if specified.
+ *
+ * @return Returns the maximum unit for this property definition, or
+ * <code>null</code> if there is no maximum unit.
+ */
+ public DurationUnit getMaximumUnit() {
+ return maximumUnit;
+ }
+
+
+
+ /**
+ * Get the lower limit.
+ *
+ * @return Returns the lower limit.
+ */
+ public long getLowerLimit() {
+ return lowerLimit;
+ }
+
+
+
+ /**
+ * Get the upper limit.
+ *
+ * @return Returns the upper limit or <code>null</code> if there
+ * is no upper limit.
+ */
+ public Long getUpperLimit() {
+ return upperLimit;
+ }
+
+
+
+ /**
+ * Determine whether this property allows unlimited durations.
+ *
+ * @return Returns <code>true</code> if this this property allows
+ * unlimited durations.
+ */
+ public boolean isAllowUnlimited() {
+ return allowUnlimited;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(Long value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ if (!allowUnlimited && value < lowerLimit) {
+ throw new IllegalPropertyValueException(this, value);
+
+ // unlimited allowed
+ } else if (value >= 0 && value < lowerLimit) {
+ throw new IllegalPropertyValueException(this, value);
+ }
+
+ if ((upperLimit != null) && (value > upperLimit)) {
+ throw new IllegalPropertyValueException(this, value);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encodeValue(Long value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // Make sure that we correctly encode negative values as
+ // "unlimited".
+ if (allowUnlimited) {
+ if (value < 0) {
+ return UNLIMITED;
+ }
+ }
+
+ // Encode the size value using the base unit.
+ StringBuilder builder = new StringBuilder();
+ builder.append(value);
+ builder.append(baseUnit.toString());
+ return builder.toString();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Long decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ // First check for the special "unlimited" value when necessary.
+ if (allowUnlimited) {
+ if (value.trim().equalsIgnoreCase(UNLIMITED)) {
+ return -1L;
+ }
+ }
+
+ // Value must be a floating point number followed by a unit.
+ Pattern p = Pattern
+ .compile("^\\s*(\\d+(\\.\\d*)?)\\s*(\\w+)\\s*$");
+ Matcher m = p.matcher(value);
+
+ if (!m.matches()) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ // Group 1 is the float.
+ double d;
+ try {
+ d = Double.valueOf(m.group(1));
+ } catch (NumberFormatException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ // Group 3 is the unit.
+ DurationUnit u;
+ try {
+ u = DurationUnit.getUnit(m.group(3));
+ } catch (IllegalArgumentException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ // Check the unit is in range.
+ if (u.getDuration() < baseUnit.getDuration()) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ if (maximumUnit != null) {
+ if (u.getDuration() > maximumUnit.getDuration()) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ }
+
+ // Convert the value a long in the property's required unit.
+ Long i = (long) u.getDuration(d, baseUnit);
+ try {
+ validateValue(i);
+ } catch (IllegalPropertyValueException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ return i;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitDuration(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void toString(StringBuilder builder) {
+ super.toString(builder);
+
+ builder.append(" baseUnit=");
+ builder.append(baseUnit);
+
+ if (maximumUnit != null) {
+ builder.append(" maximumUnit=");
+ builder.append(maximumUnit);
+ }
+
+ builder.append(" lowerLimit=");
+ builder.append(lowerLimit);
+
+ if (upperLimit != null) {
+ builder.append(" upperLimit=");
+ builder.append(upperLimit);
+ }
+
+ builder.append(" allowUnlimited=");
+ builder.append(allowUnlimited);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(Long o1, Long o2) {
+ return o1.compareTo(o2);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/DurationUnit.java b/opends/src/server/org/opends/server/admin/DurationUnit.java
new file mode 100644
index 0000000..2fa0c5a
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/DurationUnit.java
@@ -0,0 +1,218 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+
+/**
+ * This enumeration defines various duration units.
+ */
+public enum DurationUnit {
+
+ /**
+ * A millisecond unit.
+ */
+ MILLI_SECONDS(1L, "ms", "milliseconds"),
+
+ /**
+ * A second unit.
+ */
+ SECONDS(1000L, "s", "seconds"),
+
+ /**
+ * A minute unit.
+ */
+ MINUTES((long) 60 * 1000, "m", "minutes"),
+
+ /**
+ * An hour unit.
+ */
+ HOURS((long) 60 * 60 * 1000, "h", "hours"),
+
+ /**
+ * A day unit.
+ */
+ DAYS((long) 24 * 60 * 60 * 1000, "d", "days"),
+
+ /**
+ * A week unit.
+ */
+ WEEKS((long) 7 * 24 * 60 * 60 * 1000, "w", "weeks");
+
+ // A lookup table for resolving a unit from its name.
+ private static final Map<String, DurationUnit> nameToUnit;
+ static {
+ nameToUnit = new HashMap<String, DurationUnit>();
+
+ for (DurationUnit unit : DurationUnit.values()) {
+ nameToUnit.put(unit.shortName, unit);
+ nameToUnit.put(unit.longName, unit);
+ }
+ }
+
+ // The size of the unit in milli-seconds.
+ private final long sz;
+
+ // The abbreviation of the unit.
+ private final String shortName;
+
+ // The long name of the unit.
+ private final String longName;
+
+
+
+ // Private constructor.
+ private DurationUnit(long sz, String shortName, String longName) {
+ this.sz = sz;
+ this.shortName = shortName;
+ this.longName = longName;
+ }
+
+
+
+ /**
+ * Get the unit corresponding to the provided unit name.
+ *
+ * @param s
+ * The name of the unit. Can be the abbreviated or long name and can
+ * contain white space and mixed case characters.
+ * @return Returns the unit corresponding to the provided unit name.
+ * @throws IllegalArgumentException
+ * If the provided name did not correspond to a known duration unit.
+ */
+ public static DurationUnit getUnit(String s) throws IllegalArgumentException {
+ DurationUnit unit = nameToUnit.get(s.trim().toLowerCase());
+ if (unit == null) {
+ throw new IllegalArgumentException("Illegal duration unit \"" + s + "\"");
+ }
+ return unit;
+ }
+
+
+
+ /**
+ * Get the abbreviated name of this unit.
+ *
+ * @return Returns the abbreviated name of this unit.
+ */
+ public String getShortName() {
+ return shortName;
+ }
+
+
+
+ /**
+ * Get the long name of this unit.
+ *
+ * @return Returns the long name of this unit.
+ */
+ public String getLongName() {
+ return longName;
+ }
+
+
+
+ /**
+ * Get the number of milli-seconds that this unit represents.
+ *
+ * @return Returns the number of milli-seconds that this unit represents.
+ */
+ public long getDuration() {
+ return sz;
+ }
+
+
+
+ /**
+ * Converts the specified duration in this unit to milli-seconds.
+ *
+ * @param duration
+ * The duration.
+ * @return Returns the number of milli-seconds that the duration represents.
+ */
+ public long getDuration(double duration) {
+ return (long) (sz * duration);
+ }
+
+
+
+ /**
+ * Converts a duration in this unit to the specified unit.
+ *
+ * @param duration
+ * The duration.
+ * @param unit
+ * The required unit.
+ * @return Returns a value representing the duration in the specified unit.
+ */
+ public double getDuration(double duration, DurationUnit unit) {
+ return (sz * duration) / unit.sz;
+ }
+
+
+
+ /**
+ * Get the best-fit unit for the specified duration in this unit. For example,
+ * if this unit is minutes and the duration 120 is provided, then the best fit
+ * unit is hours: 2h. Similarly, if the duration is 0.5, then the best fit
+ * unit will by seconds: 30s.
+ *
+ * @param duration
+ * The duration.
+ * @return Returns the best-fit unit for the specified duration in this unit.
+ */
+ public DurationUnit getBestFitUnit(double duration) {
+ for (DurationUnit unit :
+ new DurationUnit[]{WEEKS, DAYS, HOURS, MINUTES, SECONDS}) {
+ double v = getDuration(duration, unit);
+ if (Double.isInfinite(v) || Double.isNaN(v) || v == 0) {
+ return this;
+ }
+ if (v >= 1 && Math.floor(v) == Math.ceil(v)) {
+ return unit;
+ }
+ }
+ return MILLI_SECONDS;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation returns the abbreviated name of this duration unit.
+ */
+ @Override
+ public String toString() {
+ return shortName;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/EnumPropertyDefinition.java b/opends/src/server/org/opends/server/admin/EnumPropertyDefinition.java
new file mode 100644
index 0000000..375e25a
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/EnumPropertyDefinition.java
@@ -0,0 +1,216 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+
+
+/**
+ * Enumeration property definition.
+ *
+ * @param <E>
+ * The enumeration that should be used for values of this
+ * property definition.
+ */
+public final class EnumPropertyDefinition<E extends Enum<E>> extends
+ AbstractPropertyDefinition<E> {
+
+ /**
+ * An interface for incrementally constructing enumeration property
+ * definitions.
+ *
+ * @param <E>
+ * The enumeration that should be used for values of this
+ * property definition.
+ */
+ public static class Builder<E extends Enum<E>> extends
+ AbstractBuilder<E, EnumPropertyDefinition<E>> {
+
+ // The enumeration class.
+ private Class<E> enumClass;
+
+
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ this.enumClass = null;
+ }
+
+
+
+ /**
+ * Set the enumeration class which should be used for values of
+ * this property definition.
+ *
+ * @param enumClass
+ * The enumeration class which should be used for values
+ * of this property definition.
+ */
+ public final void setEnumClass(Class<E> enumClass) {
+ this.enumClass = enumClass;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected EnumPropertyDefinition<E> buildInstance(
+ String propertyName, EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<E> defaultBehavior) {
+ // Make sure that the enumeration class has been defined.
+ if (enumClass == null) {
+ throw new IllegalStateException("Enumeration class undefined");
+ }
+
+ return new EnumPropertyDefinition<E>(propertyName, options,
+ defaultBehavior, enumClass);
+ }
+ }
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 338458138694686844L;
+
+
+
+ /**
+ * Create an enumeration property definition builder.
+ *
+ * @param <E>
+ * The enumeration that should be used for values of this
+ * property definition.
+ * @param propertyName
+ * The property name.
+ * @return Returns the new enumeration property definition builder.
+ */
+ public static <E extends Enum<E>> Builder<E> createBuilder(
+ String propertyName) {
+ return new Builder<E>(propertyName);
+ }
+
+ // The enumeration class.
+ private final Class<E> enumClass;
+
+ // Map used for decoding values.
+ private final Map<String, E> decodeMap;
+
+
+
+ // Private constructor.
+ private EnumPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<E> defaultBehavior, Class<E> enumClass) {
+ super(enumClass, propertyName, options, defaultBehavior);
+ this.enumClass = enumClass;
+
+ // Initialize the decoding map.
+ this.decodeMap = new HashMap<String, E>();
+ for (E value : EnumSet.<E> allOf(enumClass)) {
+ String s = value.toString().trim().toLowerCase();
+ this.decodeMap.put(s, value);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitEnum(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public E decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ String nvalue = value.trim().toLowerCase();
+ E eValue = decodeMap.get(nvalue);
+ if (eValue == null) {
+ throw new IllegalPropertyValueStringException(this, value);
+ } else {
+ return eValue;
+ }
+ }
+
+
+
+ /**
+ * Get the enumeration class used for values of this property.
+ *
+ * @return Returns the enumeration class used for values of this
+ * property.
+ */
+ public Class<E> getEnumClass() {
+ return enumClass;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String normalizeValue(E value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ return value.toString().trim().toLowerCase();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(E value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // No additional validation required.
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/IPAddressMaskPropertyDefinition.java b/opends/src/server/org/opends/server/admin/IPAddressMaskPropertyDefinition.java
new file mode 100644
index 0000000..1be571e
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/IPAddressMaskPropertyDefinition.java
@@ -0,0 +1,153 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.AddressMask;
+
+
+
+/**
+ * IP address mask property definition.
+ */
+public final class IPAddressMaskPropertyDefinition extends
+ AbstractPropertyDefinition<AddressMask> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -6641292526738863824L;
+
+
+
+ /**
+ * An interface for incrementally constructing IP address mask property
+ * definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<AddressMask, IPAddressMaskPropertyDefinition> {
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected IPAddressMaskPropertyDefinition buildInstance(
+ String propertyName, EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<AddressMask> defaultBehavior) {
+ return new IPAddressMaskPropertyDefinition(propertyName, options,
+ defaultBehavior);
+ }
+
+ }
+
+
+
+ /**
+ * Create a IP address mask property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new IP address mask property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private IPAddressMaskPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<AddressMask> defaultBehavior) {
+ super(AddressMask.class, propertyName, options, defaultBehavior);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(AddressMask value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // No additional validation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AddressMask decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ try {
+ return AddressMask.decode(value);
+ } catch (ConfigException e) {
+ // TODO: it would be nice to throw the cause.
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitIPAddressMask(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(AddressMask o1, AddressMask o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/IPAddressPropertyDefinition.java b/opends/src/server/org/opends/server/admin/IPAddressPropertyDefinition.java
new file mode 100644
index 0000000..4d55dcb
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/IPAddressPropertyDefinition.java
@@ -0,0 +1,152 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.EnumSet;
+
+
+
+/**
+ * IP address property definition.
+ */
+public final class IPAddressPropertyDefinition extends
+ AbstractPropertyDefinition<InetAddress> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -6641292526738863824L;
+
+
+
+ /**
+ * An interface for incrementally constructing IP address property
+ * definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<InetAddress, IPAddressPropertyDefinition> {
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected IPAddressPropertyDefinition buildInstance(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<InetAddress> defaultBehavior) {
+ return new IPAddressPropertyDefinition(propertyName, options,
+ defaultBehavior);
+ }
+
+ }
+
+
+
+ /**
+ * Create a IP address property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new IP address property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private IPAddressPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<InetAddress> defaultBehavior) {
+ super(InetAddress.class, propertyName, options, defaultBehavior);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(InetAddress value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // No additional validation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public InetAddress decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ try {
+ return InetAddress.getByName(value);
+ } catch (UnknownHostException e) {
+ // TODO: it would be nice to throw the cause.
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitIPAddress(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(InetAddress o1, InetAddress o2) {
+ return o1.getHostAddress().compareTo(o2.getHostAddress());
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/IllegalPropertyValueException.java b/opends/src/server/org/opends/server/admin/IllegalPropertyValueException.java
new file mode 100644
index 0000000..9deb91a8
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/IllegalPropertyValueException.java
@@ -0,0 +1,84 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown to indicate that a property value was invalid according to its
+ * associated property definition.
+ */
+public class IllegalPropertyValueException extends PropertyException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -3145632074909281823L;
+
+ // The illegal property value.
+ private final Object value;
+
+
+
+ /**
+ * Create a new illegal property value exception.
+ *
+ * @param d
+ * The property definition.
+ * @param value
+ * The illegal property value.
+ */
+ public IllegalPropertyValueException(PropertyDefinition d, Object value) {
+ super(d);
+ this.value = value;
+ }
+
+
+
+ /**
+ * Get the illegal property value that caused the exception.
+ *
+ * @return Returns the illegal property value.
+ */
+ public final Object getIllegalValue() {
+ return value;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "The value \"" + String.valueOf(value)
+ + "\" is not a valid value for the property \""
+ + getPropertyDefinition().getName() + "\"";
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/IllegalPropertyValueStringException.java b/opends/src/server/org/opends/server/admin/IllegalPropertyValueStringException.java
new file mode 100644
index 0000000..5f7aaaa
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/IllegalPropertyValueStringException.java
@@ -0,0 +1,85 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown to indicate that a property value string was invalid according to its
+ * associated property definition.
+ */
+public class IllegalPropertyValueStringException extends PropertyException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -3145632074909281823L;
+
+ // The illegal property value string.
+ private final String value;
+
+
+
+ /**
+ * Create a new illegal property value string exception.
+ *
+ * @param d
+ * The property definition.
+ * @param value
+ * The illegal property value string.
+ */
+ public IllegalPropertyValueStringException(PropertyDefinition d,
+ String value) {
+ super(d);
+ this.value = value;
+ }
+
+
+
+ /**
+ * Get the illegal property value string that caused the exception.
+ *
+ * @return Returns the illegal property value string.
+ */
+ public final String getIllegalValueString() {
+ return value;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "The string value \"" + String.valueOf(value)
+ + "\" is not a valid value for the property \""
+ + getPropertyDefinition().getName() + "\"";
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/InheritedDefaultValueException.java b/opends/src/server/org/opends/server/admin/InheritedDefaultValueException.java
new file mode 100644
index 0000000..1793271
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/InheritedDefaultValueException.java
@@ -0,0 +1,97 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown to indicate that a property's inherited default values could not be
+ * determined due to some underlying operations exception which occurred when
+ * attempting to retrieve them.
+ */
+public class InheritedDefaultValueException extends PropertyException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 7228186032995472371L;
+
+ // The operations exception that caused default value look up to fail.
+ private final OperationsException cause;
+
+
+
+ /**
+ * Create a new inherited default value exception.
+ *
+ * @param d
+ * The property definition.
+ * @param cause
+ * The operations exception that caused default value look up to
+ * fail.
+ */
+ public InheritedDefaultValueException(PropertyDefinition d,
+ OperationsException cause) {
+ super(d);
+ this.cause = cause;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Throwable getCause() {
+ return cause;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "The inherited default values could not be determined "
+ + "for the property \"" + getPropertyDefinition().getName() + "\"";
+ }
+
+
+
+ /**
+ * Get the operations exception that caused default value look up to fail.
+ *
+ * @return Returns the operations exception that caused default value look up
+ * to fail.
+ */
+ public final OperationsException getOperationsException() {
+ return cause;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/InheritedDefaultValueProvider.java b/opends/src/server/org/opends/server/admin/InheritedDefaultValueProvider.java
new file mode 100644
index 0000000..75e5a25
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/InheritedDefaultValueProvider.java
@@ -0,0 +1,71 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.Collection;
+
+
+
+/**
+ * An interface for retrieving inherited default property values.
+ */
+public interface InheritedDefaultValueProvider {
+
+ /**
+ * Get the path of the managed object which should be used as the base for
+ * determining parent managed objects.
+ *
+ * @return Returns the path of the managed object which should be used as the
+ * base for determining parent managed objects.
+ */
+ ManagedObjectPath getManagedObjectPath();
+
+
+
+ /**
+ * Retrieves the values of a property from a managed object at the specified
+ * location.
+ *
+ * @param path
+ * The location of the managed object containing the property.
+ * @param propertyName
+ * The name of the property containing the default values.
+ * @return Returns the values of a property from a managed object at the
+ * specified location.
+ * @throws OperationsException
+ * If the managed object could not be read due to some underlying
+ * communication problem.
+ * @throws PropertyNotFoundException
+ * If the property name was not recognized.
+ */
+ Collection<?> getDefaultPropertyValues(ManagedObjectPath path,
+ String propertyName) throws OperationsException,
+ PropertyNotFoundException;
+}
diff --git a/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java b/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
new file mode 100644
index 0000000..64c42c0
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/InstantiableRelationDefinition.java
@@ -0,0 +1,107 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A managed object composite relationship definition which represents
+ * a composition of zero or more managed objects.
+ *
+ * @param <C>
+ * The type of client managed object configuration that this
+ * relation definition refers to.
+ * @param <S>
+ * The type of server managed object configuration that this
+ * relation definition refers to.
+ */
+public final class InstantiableRelationDefinition
+ <C extends ConfigurationClient, S extends Configuration>
+ extends RelationDefinition<C, S> {
+
+ // The plural name of the relation.
+ private final String pluralName;
+
+
+
+ /**
+ * Create a new instantiable managed object relation definition.
+ *
+ * @param pd
+ * The parent managed object definition.
+ * @param name
+ * The name of the relation.
+ * @param pluralName
+ * The plural name of the relation.
+ * @param cd
+ * The child managed object definition.
+ */
+ public InstantiableRelationDefinition(
+ AbstractManagedObjectDefinition<?, ?> pd, String name, String pluralName,
+ AbstractManagedObjectDefinition<C, S> cd) {
+ super(pd, name, cd);
+ this.pluralName = pluralName;
+ }
+
+
+
+ /**
+ * Get the plural name of the relation.
+ *
+ * @return Returns the plural name of the relation.
+ */
+ public final String getPluralName() {
+ return pluralName;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void toString(StringBuilder builder) {
+ builder.append("name=");
+ builder.append(getName());
+ builder.append(" type=composition parent=");
+ builder.append(getParentDefinition().getName());
+ builder.append(" child=");
+ builder.append(getChildDefinition().getName());
+ builder.append(" minOccurs=0");
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
+ return v.visitInstantiable(this, p);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/IntegerPropertyDefinition.java b/opends/src/server/org/opends/server/admin/IntegerPropertyDefinition.java
new file mode 100644
index 0000000..06a6aab
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/IntegerPropertyDefinition.java
@@ -0,0 +1,338 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+
+
+
+/**
+ * Integer property definition.
+ * <p>
+ * All values must be zero or positive and within the lower/upper limit
+ * constraints. Support is provided for "unlimited" values. These are
+ * represented using a negative value or using the string "unlimited".
+ */
+public final class IntegerPropertyDefinition extends
+ AbstractPropertyDefinition<Integer> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 2819904868308720588L;
+
+ // String used to represent unlimited.
+ private static final String UNLIMITED = "unlimited";
+
+ // The lower limit of the property value.
+ private final int lowerLimit;
+
+ // The optional upper limit of the property value.
+ private final Integer upperLimit;
+
+ // Indicates whether this property allows the use of the "unlimited" value
+ // (represented using a -1 or the string "unlimited").
+ private final boolean allowUnlimited;
+
+
+
+ /**
+ * An interface for incrementally constructing integer property definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<Integer, IntegerPropertyDefinition> {
+
+ // The lower limit of the property value.
+ private int lowerLimit = 0;
+
+ // The optional upper limit of the property value.
+ private Integer upperLimit = null;
+
+ // Indicates whether this property allows the use of the "unlimited" value
+ // (represented using a -1 or the string "unlimited").
+ private boolean allowUnlimited = false;
+
+
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * Set the lower limit.
+ *
+ * @param lowerLimit
+ * The new lower limit (must be >= 0).
+ * @throws IllegalArgumentException
+ * If a negative lower limit was specified or the lower limit is
+ * greater than the upper limit.
+ */
+ public final void setLowerLimit(int lowerLimit)
+ throws IllegalArgumentException {
+ if (lowerLimit < 0) {
+ throw new IllegalArgumentException("Negative lower limit");
+ }
+ if (upperLimit != null && lowerLimit > upperLimit) {
+ throw new IllegalArgumentException(
+ "Lower limit greater than upper limit");
+ }
+ this.lowerLimit = lowerLimit;
+ }
+
+
+
+ /**
+ * Set the upper limit.
+ *
+ * @param upperLimit
+ * The new upper limit or <code>null</code> if there is no upper
+ * limit.
+ */
+ public final void setUpperLimit(Integer upperLimit) {
+ if (upperLimit != null) {
+ if (upperLimit < 0) {
+ throw new IllegalArgumentException("Negative lower limit");
+ }
+ if (lowerLimit > upperLimit) {
+ throw new IllegalArgumentException(
+ "Lower limit greater than upper limit");
+ }
+ }
+ this.upperLimit = upperLimit;
+ }
+
+
+
+ /**
+ * Specify whether or not this property definition will allow unlimited
+ * values (default is false).
+ *
+ * @param allowUnlimited
+ * <code>true</code> if the property will allow unlimited values,
+ * or <code>false</code> otherwise.
+ */
+ public final void setAllowUnlimited(boolean allowUnlimited) {
+ this.allowUnlimited = allowUnlimited;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected IntegerPropertyDefinition buildInstance(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Integer> defaultBehavior) {
+ return new IntegerPropertyDefinition(propertyName, options,
+ defaultBehavior, lowerLimit, upperLimit, allowUnlimited);
+ }
+
+ }
+
+
+
+ /**
+ * Create an integer property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new integer property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private IntegerPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Integer> defaultBehavior, int lowerLimit,
+ Integer upperLimit, boolean allowUnlimited) {
+ super(Integer.class, propertyName, options, defaultBehavior);
+ this.lowerLimit = lowerLimit;
+ this.upperLimit = upperLimit;
+ this.allowUnlimited = allowUnlimited;
+ }
+
+
+
+ /**
+ * Get the lower limit.
+ *
+ * @return Returns the lower limit.
+ */
+ public int getLowerLimit() {
+ return lowerLimit;
+ }
+
+
+
+ /**
+ * Get the upper limit.
+ *
+ * @return Returns the upper limit or <code>null</code> if there is no upper
+ * limit.
+ */
+ public Integer getUpperLimit() {
+ return upperLimit;
+ }
+
+
+
+ /**
+ * Determine whether this property allows unlimited values.
+ *
+ * @return Returns <code>true</code> if this this property allows unlimited
+ * values.
+ */
+ public boolean isAllowUnlimited() {
+ return allowUnlimited;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(Integer value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ if (!allowUnlimited && value < lowerLimit) {
+ throw new IllegalPropertyValueException(this, value);
+
+ // unlimited allowed
+ } else if (value >= 0 && value < lowerLimit) {
+ throw new IllegalPropertyValueException(this, value);
+ }
+
+ if ((upperLimit != null) && (value > upperLimit)) {
+ throw new IllegalPropertyValueException(this, value);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encodeValue(Integer value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // Make sure that we correctly encode negative values as "unlimited".
+ if (allowUnlimited) {
+ if (value < 0) {
+ return UNLIMITED;
+ }
+ }
+
+ return value.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Integer decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ if (allowUnlimited) {
+ if (value.trim().equalsIgnoreCase(UNLIMITED)) {
+ return -1;
+ }
+ }
+
+ Integer i;
+ try {
+ i = Integer.valueOf(value);
+ } catch (NumberFormatException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ try {
+ validateValue(i);
+ } catch (IllegalPropertyValueException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ return i;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitInteger(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void toString(StringBuilder builder) {
+ super.toString(builder);
+
+ builder.append(" lowerLimit=");
+ builder.append(lowerLimit);
+
+ if (upperLimit != null) {
+ builder.append(" upperLimit=");
+ builder.append(upperLimit);
+ }
+
+ builder.append(" allowUnlimited=");
+ builder.append(allowUnlimited);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(Integer o1, Integer o2) {
+ return o1.compareTo(o2);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/LDAPProfile.java b/opends/src/server/org/opends/server/admin/LDAPProfile.java
new file mode 100644
index 0000000..e74c361
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/LDAPProfile.java
@@ -0,0 +1,200 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+
+
+/**
+ * This class is used to map configuration elements to their LDAP schema names.
+ */
+public final class LDAPProfile {
+
+ // The singleton instance.
+ private static final LDAPProfile INSTANCE = new LDAPProfile();
+
+ // The LDAP profile property table.
+ private final ManagedObjectDefinitionResource resource;
+
+
+
+ /**
+ * Get the global LDAP profile instance.
+ *
+ * @return Returns the global LDAP profile instance.
+ */
+ public static LDAPProfile getInstance() {
+ return INSTANCE;
+ }
+
+
+
+ // Private constructor.
+ private LDAPProfile() {
+ this.resource = ManagedObjectDefinitionResource.createForProfile("ldap");
+ }
+
+
+
+ /**
+ * Gets the LDAP RDN attribute type for child entries of an instantiable
+ * relation.
+ *
+ * @param r
+ * The instantiable relation.
+ * @return Returns the LDAP RDN attribute type for child entries of an
+ * instantiable relation.
+ */
+ public String getInstantiableRelationChildRDNType(
+ InstantiableRelationDefinition<?, ?> r) {
+ // For now, assume always "cn".
+ return "cn";
+ }
+
+
+
+ /**
+ * Gets the LDAP object classes associated with an instantiable relation
+ * branch. The branch is the parent entry of child managed objects.
+ *
+ * @param r
+ * The instantiable relation.
+ * @return Returns the LDAP object classes associated with an instantiable
+ * relation branch.
+ */
+ public List<String> getInstantiableRelationObjectClasses(
+ InstantiableRelationDefinition<?, ?> r) {
+ return Arrays.asList(new String[] { "top", "ds-cfg-branch" });
+ }
+
+
+
+ /**
+ * Get an LDAP RDN sequence associatied with a relation.
+ *
+ * @param r
+ * The relation.
+ * @return Returns the LDAP RDN sequence associatied with a relation.
+ */
+ public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
+ return resource.getString(r.getParentDefinition(), "rdn." + r.getName());
+ }
+
+
+
+ /**
+ * Get an LDAP filter string which can be used to search for entries matching
+ * the specified definition.
+ *
+ * @param d
+ * The managed object definition.
+ * @return Returns the LDAP filter.
+ */
+ public String getFilter(AbstractManagedObjectDefinition<?, ?> d) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("(ObjectClass=");
+ builder.append(getObjectClass(d));
+ builder.append(')');
+ return builder.toString();
+ }
+
+
+
+ /**
+ * Get the principle object class associated with the specified definition.
+ *
+ * @param d
+ * The managed object definition.
+ * @return Returns the principle object class associated with the specified
+ * definition.
+ */
+ public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d) {
+ return resource.getString(d, "objectclass");
+ }
+
+
+
+ /**
+ * Get all the object classes associated with the specified definition.
+ * <p>
+ * The returned list is ordered such that the uppermost object classes appear
+ * first (e.g. top).
+ *
+ * @param d
+ * The managed object definition.
+ * @return Returns all the object classes associated with the specified
+ * definition.
+ */
+ public List<String> getObjectClasses(
+ AbstractManagedObjectDefinition<?, ?> d) {
+ LinkedList<String> objectClasses = new LinkedList<String>();
+ Set<String> s = new HashSet<String>();
+
+ // Add the object classes from the parent hierarchy.
+ while (d != null) {
+ String oc = getObjectClass(d);
+ if (!s.contains(oc)) {
+ objectClasses.addFirst(oc);
+ s.add(oc);
+ }
+ d = d.getParent();
+ }
+
+ // Make sure that we have top.
+ if (!s.contains("top")) {
+ objectClasses.addFirst("top");
+ }
+
+ return objectClasses;
+ }
+
+
+
+ /**
+ * Get the name of the LDAP attribute associated with the specified property
+ * definition.
+ *
+ * @param d
+ * The managed object definition.
+ * @param pd
+ * The property definition.
+ * @return Returns the name of the LDAP attribute associated with the
+ * specified property definition.
+ */
+ public String getAttributeName(ManagedObjectDefinition<?, ?> d,
+ PropertyDefinition<?> pd) {
+ return resource.getString(d, "attribute." + pd.getName());
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectAlreadyExistsException.java b/opends/src/server/org/opends/server/admin/ManagedObjectAlreadyExistsException.java
new file mode 100644
index 0000000..08ca020
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectAlreadyExistsException.java
@@ -0,0 +1,75 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A managed object could not be created because there is an existing managed
+ * object with the same name.
+ */
+public final class ManagedObjectAlreadyExistsException extends
+ OperationsException {
+
+ /**
+ * Version ID required by serializable classes.
+ */
+ private static final long serialVersionUID = -2344653674171609366L;
+
+ // Simple description of this exception for debugging.
+ private static final String MSG = "A managed object could not be created"
+ + " because there is an existing managed object with the same name";
+
+ // The name of the managed object that could not be created.
+ private final String name;
+
+
+
+ /**
+ * Create a managed object already exists exception with the duplicate name.
+ *
+ * @param name
+ * The name of the managed object that could not be created.
+ */
+ public ManagedObjectAlreadyExistsException(String name) {
+ super(MSG);
+
+ this.name = name;
+ }
+
+
+
+ /**
+ * Get the name of the managed object that could not be created.
+ *
+ * @return Returns the name of the managed object that could not be created.
+ */
+ public String getName() {
+ return name;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectDefinition.java b/opends/src/server/org/opends/server/admin/ManagedObjectDefinition.java
new file mode 100644
index 0000000..fca41be
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectDefinition.java
@@ -0,0 +1,105 @@
+/*
+ * 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.admin;
+
+
+
+import org.opends.server.admin.client.ManagedObject;
+import org.opends.server.admin.server.ServerManagedObject;
+
+
+
+/**
+ * Defines the structure of a managed object which can be
+ * instantiated.
+ *
+ * @param <C>
+ * The type of client managed object configuration that this
+ * definition represents.
+ * @param <S>
+ * The type of server managed object configuration that this
+ * definition represents.
+ */
+public abstract class ManagedObjectDefinition
+ <C extends ConfigurationClient, S extends Configuration>
+ extends AbstractManagedObjectDefinition<C, S> {
+
+ /**
+ * Create a new managed object definition.
+ *
+ * @param name
+ * The name of the definition.
+ * @param parent
+ * The parent definition, or <code>null</code> if there
+ * is no parent.
+ */
+ protected ManagedObjectDefinition(String name,
+ AbstractManagedObjectDefinition<? super C, ? super S> parent) {
+ super(name, parent);
+ }
+
+
+
+ /**
+ * Creates a client configuration view of the provided managed
+ * object. Modifications made to the underlying managed object will
+ * be reflected in the client configuration view and vice versa.
+ *
+ * @param managedObject
+ * The managed object.
+ * @return Returns a client configuration view of the provided
+ * managed object.
+ */
+ public abstract C createClientConfiguration(
+ ManagedObject<? extends C> managedObject);
+
+
+
+ /**
+ * Creates a server configuration view of the provided server
+ * managed object.
+ *
+ * @param managedObject
+ * The server managed object.
+ * @return Returns a server configuration view of the provided
+ * server managed object.
+ */
+ public abstract S createServerConfiguration(
+ ServerManagedObject<? extends S> managedObject);
+
+
+
+ /**
+ * Gets the server configuration class instance associated with this
+ * managed object definition.
+ *
+ * @return Returns the server configuration class instance
+ * associated with this managed object definition.
+ */
+ public abstract Class<S> getServerConfigurationClass();
+}
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java b/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java
new file mode 100644
index 0000000..862631f
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java
@@ -0,0 +1,211 @@
+/*
+ * 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.admin;
+
+
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+
+
+/**
+ * A class for retrieving internationalized resource properties
+ * associated with a managed object definition.
+ */
+public final class ManagedObjectDefinitionI18NResource {
+
+ // Mapping from definition to resource bundle.
+ private final Map<AbstractManagedObjectDefinition, ResourceBundle> resources;
+
+ // The resource name prefix.
+ private final String prefix;
+
+
+
+ /**
+ * Creates a new internationalized resource instance which can be
+ * used to retrieve the localized descriptions for the managed
+ * objects and their associated properties and relations.
+ *
+ * @return Returns the I18N resource instance.
+ */
+ public static ManagedObjectDefinitionI18NResource create() {
+ return new ManagedObjectDefinitionI18NResource("admin.messages");
+ }
+
+
+
+ /**
+ * Creates a new internationalized resource instance for the named
+ * profile.
+ *
+ * @param profile
+ * The name of the profile.
+ * @return Returns the I18N resource instance for the named profile.
+ */
+ public static ManagedObjectDefinitionI18NResource createForProfile(
+ String profile) {
+ return new ManagedObjectDefinitionI18NResource("admin.profiles."
+ + profile);
+ }
+
+
+
+ // Private constructor.
+ private ManagedObjectDefinitionI18NResource(String prefix) {
+ this.resources =
+ new HashMap<AbstractManagedObjectDefinition, ResourceBundle>();
+ this.prefix = prefix;
+ }
+
+
+
+ /**
+ * Get the internationalized message associated with the specified
+ * key in the default locale.
+ *
+ * @param d
+ * The managed object definition.
+ * @param key
+ * The resource key.
+ * @return Returns the internationalized message associated with the
+ * specified key in the default locale.
+ * @throws MissingResourceException
+ * If the key was not found.
+ */
+ public String getMessage(AbstractManagedObjectDefinition d,
+ String key) throws MissingResourceException {
+ return getMessage(d, key, Locale.getDefault(), (String[]) null);
+ }
+
+
+
+ /**
+ * Get the parameterized internationalized message associated with
+ * the specified key in the default locale.
+ *
+ * @param d
+ * The managed object definition.
+ * @param key
+ * The resource key.
+ * @param args
+ * Arguments that should be inserted into the retrieved
+ * message.
+ * @return Returns the internationalized message associated with the
+ * specified key in the default locale.
+ * @throws MissingResourceException
+ * If the key was not found.
+ */
+ public String getMessage(AbstractManagedObjectDefinition d,
+ String key, String... args) throws MissingResourceException {
+ return getMessage(d, key, Locale.getDefault(), args);
+ }
+
+
+
+ /**
+ * Get the internationalized message associated with the specified
+ * key and locale.
+ *
+ * @param d
+ * The managed object definition.
+ * @param key
+ * The resource key.
+ * @param locale
+ * The locale.
+ * @return Returns the internationalized message associated with the
+ * specified key and locale.
+ * @throws MissingResourceException
+ * If the key was not found.
+ */
+ public String getMessage(AbstractManagedObjectDefinition d,
+ String key, Locale locale) throws MissingResourceException {
+ return getMessage(d, key, locale, (String[]) null);
+ }
+
+
+
+ /**
+ * Get the parameterized internationalized message associated with
+ * the specified key and locale.
+ *
+ * @param d
+ * The managed object definition.
+ * @param key
+ * The resource key.
+ * @param locale
+ * The locale.
+ * @param args
+ * Arguments that should be inserted into the retrieved
+ * message.
+ * @return Returns the internationalized message associated with the
+ * specified key and locale.
+ * @throws MissingResourceException
+ * If the key was not found.
+ */
+ public String getMessage(AbstractManagedObjectDefinition d,
+ String key, Locale locale, String... args)
+ throws MissingResourceException {
+ ResourceBundle resource = getResourceBundle(d, locale);
+
+ if (args == null) {
+ return resource.getString(key);
+ } else {
+ MessageFormat mf = new MessageFormat(resource.getString(key));
+ return mf.format(args);
+ }
+ }
+
+
+
+ // Retrieve the resource bundle associated with a managed object and
+ // locale,
+ // lazily loading it if necessary.
+ private synchronized ResourceBundle getResourceBundle(
+ AbstractManagedObjectDefinition d, Locale locale)
+ throws MissingResourceException {
+ ResourceBundle r = resources.get(d);
+
+ if (r == null) {
+ // Load the resource file.
+ String baseName = prefix + "." + d.getClass().getName();
+ r = ResourceBundle.getBundle(baseName, locale,
+ ClassLoaderProvider.getInstance().getClassLoader());
+
+ // Cache the resource.
+ resources.put(d, r);
+ }
+
+ return r;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionResource.java b/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionResource.java
new file mode 100644
index 0000000..8beb696
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectDefinitionResource.java
@@ -0,0 +1,145 @@
+/*
+ * 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.admin;
+
+
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+
+
+
+/**
+ * A class for retrieving non-internationalized resource properties
+ * associated with a managed object definition.
+ */
+public final class ManagedObjectDefinitionResource {
+
+ // Mapping from definition to property tables.
+ private final Map<AbstractManagedObjectDefinition, Properties> properties;
+
+ // The resource name prefix.
+ private final String prefix;
+
+
+
+ /**
+ * Creates a new resource instance for the named profile.
+ *
+ * @param profile
+ * The name of the profile.
+ * @return Returns the resource instance for the named profile.
+ */
+ public static ManagedObjectDefinitionResource createForProfile(
+ String profile) {
+ return new ManagedObjectDefinitionResource("admin.profiles."
+ + profile);
+ }
+
+
+
+ // Private constructor.
+ private ManagedObjectDefinitionResource(String prefix) {
+ this.properties =
+ new HashMap<AbstractManagedObjectDefinition, Properties>();
+ this.prefix = prefix;
+ }
+
+
+
+ /**
+ * Get the resource value associated with the specified key.
+ *
+ * @param d
+ * The managed object definition.
+ * @param key
+ * The resource key.
+ * @return Returns the resource value associated with the specified
+ * key.
+ * @throws MissingResourceException
+ * If the key was not found.
+ */
+ public String getString(AbstractManagedObjectDefinition d,
+ String key) throws MissingResourceException {
+ Properties p = getProperties(d);
+ String result = p.getProperty(key);
+
+ if (result == null) {
+ String baseName = prefix + "." + d.getClass().getName();
+ String path = baseName.replace('.', '/') + ".properties";
+
+ throw new MissingResourceException("Can't find resource "
+ + path + ", key " + key, baseName, key);
+ }
+
+ return result;
+ }
+
+
+
+ // Retrieve the properties table associated with a managed object,
+ // lazily
+ // loading it if necessary.
+ private synchronized Properties getProperties(
+ AbstractManagedObjectDefinition d)
+ throws MissingResourceException {
+ Properties p = properties.get(d);
+
+ if (p == null) {
+ // Load the resource file.
+ String baseName = prefix + "." + d.getClass().getName();
+ String path = baseName.replace('.', '/') + ".properties";
+ InputStream stream = ClassLoaderProvider.getInstance()
+ .getClassLoader().getResourceAsStream(path);
+
+ if (stream == null) {
+ throw new MissingResourceException("Can't find resource "
+ + path, baseName, "");
+ }
+
+ p = new Properties();
+ try {
+ p.load(new BufferedInputStream(stream));
+ } catch (IOException e) {
+ throw new MissingResourceException("Can't load resource "
+ + path + " due to IO exception: " + e.getMessage(),
+ baseName, "");
+ }
+
+ // Cache the resource.
+ properties.put(d, p);
+ }
+
+ return p;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectNotFoundException.java b/opends/src/server/org/opends/server/admin/ManagedObjectNotFoundException.java
new file mode 100644
index 0000000..23a4730
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectNotFoundException.java
@@ -0,0 +1,66 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * The requested managed object could not be located.
+ */
+public class ManagedObjectNotFoundException extends OperationsException {
+
+ /**
+ * Version ID required by serializable classes.
+ */
+ private static final long serialVersionUID = -477551786551892978L;
+
+ // Simple description of this exception for debugging.
+ private static final String MSG =
+ "The requested managed object could not be found";
+
+
+
+ /**
+ * Create a managed object not found exception.
+ */
+ public ManagedObjectNotFoundException() {
+ super(MSG);
+ }
+
+
+
+ /**
+ * Create a managed object not found exception with the specified cause.
+ *
+ * @param cause
+ * The cause of this exception.
+ */
+ public ManagedObjectNotFoundException(Throwable cause) {
+ super(MSG, cause);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectPath.java b/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
new file mode 100644
index 0000000..5e3639a
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
@@ -0,0 +1,484 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.server.admin.std.meta.RootCfgDefn;
+
+
+
+/**
+ * A path which can be used to determine the location of a managed
+ * object instance.
+ */
+public final class ManagedObjectPath {
+
+ /**
+ * Abstract path element.
+ */
+ private static abstract class Element {
+
+ /**
+ * Protected constructor.
+ */
+ protected Element() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Get the relation definition associated with this element.
+ *
+ * @return Returns the relation definition associated with this
+ * element.
+ */
+ public abstract RelationDefinition<?, ?> getRelation();
+
+
+
+ /**
+ * Serialize this path element using the provided serialization
+ * strategy.
+ *
+ * @param serializer
+ * The managed object path serialization strategy.
+ */
+ public abstract void serialize(
+ ManagedObjectPathSerializer serializer);
+ }
+
+
+
+ /**
+ * A path element representing an instantiable managed object.
+ */
+ private static final class InstantiableElement extends Element {
+
+ // The instantiable relation.
+ private final InstantiableRelationDefinition<?, ?> r;
+
+ // The name of the managed object.
+ private final String name;
+
+
+
+ // Private constructor.
+ private InstantiableElement(
+ InstantiableRelationDefinition<?, ?> r, String name) {
+ this.r = r;
+ this.name = name;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public RelationDefinition<?, ?> getRelation() {
+ return r;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void serialize(ManagedObjectPathSerializer serializer) {
+ serializer.appendManagedObjectPathElement(r, name);
+ }
+
+ }
+
+
+
+ /**
+ * A path element representing an optional managed object.
+ */
+ private static final class OptionalElement extends Element {
+
+ // The optional relation.
+ private final OptionalRelationDefinition<?, ?> r;
+
+
+
+ // Private constructor.
+ private OptionalElement(OptionalRelationDefinition<?, ?> r) {
+ this.r = r;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public RelationDefinition<?, ?> getRelation() {
+ return r;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void serialize(ManagedObjectPathSerializer serializer) {
+ serializer.appendManagedObjectPathElement(r);
+ }
+ }
+
+
+
+ /**
+ * A path element representing a singleton managed object.
+ */
+ private static final class SingletonElement extends Element {
+
+ // The singleton relation.
+ private final SingletonRelationDefinition<?, ?> r;
+
+
+
+ // Private constructor.
+ private SingletonElement(SingletonRelationDefinition<?, ?> r) {
+ this.r = r;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public RelationDefinition<?, ?> getRelation() {
+ return r;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void serialize(ManagedObjectPathSerializer serializer) {
+ serializer.appendManagedObjectPathElement(r);
+ }
+ }
+
+ // Single instance of a root path.
+ private static final ManagedObjectPath EMPTY_PATH = new ManagedObjectPath(
+ new LinkedList<Element>());
+
+
+
+ /**
+ * Creates a new managed object path representing the configuration
+ * root.
+ *
+ * @return Returns a new managed object path representing the
+ * configuration root.
+ */
+ public static ManagedObjectPath emptyPath() {
+ return EMPTY_PATH;
+ }
+
+
+ /**
+ * Returns a managed object path holding the value of the specified
+ * string.
+ *
+ * @param s
+ * The string to be parsed.
+ * @return Returns a managed object path holding the value of the
+ * specified string.
+ * @throws IllegalArgumentException
+ * If the string could not be parsed.
+ */
+ public static ManagedObjectPath valueOf(String s)
+ throws IllegalArgumentException {
+ return null;
+ }
+
+
+
+ // The list of path elements in this path.
+ private final List<Element> elements;
+
+
+
+ // Private constructor.
+ private ManagedObjectPath(LinkedList<Element> elements) {
+ this.elements = Collections.unmodifiableList(elements);
+ }
+
+
+
+ /**
+ * Creates a new child managed object path beneath the provided
+ * parent path.
+ *
+ * @param r
+ * The instantiable relation referencing the child.
+ * @param name
+ * The relative name of the child managed object.
+ * @return Returns a new child managed object path beneath the
+ * provided parent path.
+ */
+ public ManagedObjectPath child(
+ InstantiableRelationDefinition<?, ?> r, String name) {
+ LinkedList<Element> celements = new LinkedList<Element>(elements);
+ celements.add(new InstantiableElement(r, name));
+ return new ManagedObjectPath(celements);
+ }
+
+
+
+ /**
+ * Creates a new child managed object path beneath the provided
+ * parent path.
+ *
+ * @param r
+ * The optional relation referencing the child.
+ * @return Returns a new child managed object path beneath the
+ * provided parent path.
+ */
+ public ManagedObjectPath child(OptionalRelationDefinition<?, ?> r) {
+ LinkedList<Element> celements = new LinkedList<Element>(elements);
+ celements.add(new OptionalElement(r));
+ return new ManagedObjectPath(celements);
+ }
+
+
+
+ /**
+ * Creates a new child managed object path beneath the provided
+ * parent path.
+ *
+ * @param r
+ * The singleton relation referencing the child.
+ * @return Returns a new child managed object path beneath the
+ * provided parent path.
+ */
+ public ManagedObjectPath child(SingletonRelationDefinition<?, ?> r) {
+ LinkedList<Element> celements = new LinkedList<Element>(elements);
+ celements.add(new SingletonElement(r));
+ return new ManagedObjectPath(celements);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof ManagedObjectPath) {
+ ManagedObjectPath other = (ManagedObjectPath) obj;
+ return toString().equals(other.toString());
+ } else {
+ return false;
+ }
+ }
+
+
+
+ /**
+ * Get the definition of the managed object referred to by this
+ * path.
+ * <p>
+ * When the path is empty, the {@link RootCfgDefn}
+ * is returned.
+ *
+ * @return Returns the definition of the managed object referred to
+ * by this path, or the {@link RootCfgDefn}
+ * if the path is empty.
+ */
+ public AbstractManagedObjectDefinition<?, ?> getManagedObjectDefinition() {
+ if (elements.isEmpty()) {
+ return RootCfgDefn.getInstance();
+ } else {
+ Element e = elements.get(elements.size() - 1);
+ return e.getRelation().getChildDefinition();
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+
+
+ /**
+ * Determine whether or not this path contains any path elements.
+ *
+ * @return Returns <code>true</code> if this path does not contain
+ * any path elements.
+ */
+ public boolean isEmpty() {
+ return elements.isEmpty();
+ }
+
+
+
+ /**
+ * Creates a new parent managed object path the specified number of
+ * path elements above this path.
+ *
+ * @param offset
+ * The number of path elements (0 - means no offset, 1
+ * means the parent, and 2 means the grand-parent).
+ * @return Returns a new parent managed object path the specified
+ * number of path elements above this path.
+ * @throws IllegalArgumentException
+ * If the offset is less than 0, or greater than the
+ * number of path elements in this path.
+ */
+ public ManagedObjectPath parent(int offset)
+ throws IllegalArgumentException {
+ if (offset < 0) {
+ throw new IllegalArgumentException("Negative offset");
+ }
+
+ if (offset > elements.size()) {
+ throw new IllegalArgumentException(
+ "Offset is greater than the number of path elements");
+ }
+
+ // An offset of 0 leaves the path unchanged.
+ if (offset == 0) {
+ return this;
+ }
+
+ LinkedList<Element> celements = new LinkedList<Element>(elements
+ .subList(0, elements.size() - offset));
+ return new ManagedObjectPath(celements);
+ }
+
+
+
+ /**
+ * Serialize this managed object path using the provided
+ * serialization strategy.
+ * <p>
+ * The path elements will be passed to the serializer in big-endian
+ * order: starting from the root element and proceeding down to the
+ * leaf.
+ *
+ * @param serializer
+ * The managed object path serialization strategy.
+ */
+ public void serialize(ManagedObjectPathSerializer serializer) {
+ for (Element element : elements) {
+ element.serialize(serializer);
+ }
+ }
+
+
+
+ /**
+ * Get the number of path elements in this managed object path.
+ *
+ * @return Returns the number of path elements (0 - means no offset,
+ * 1 means the parent, and 2 means the grand-parent).
+ */
+ public int size() {
+ return elements.size();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ toString(builder);
+ return builder.toString();
+ }
+
+
+
+ /**
+ * Appends a string representation of this managed object path to
+ * the provided string builder.
+ *
+ * @param builder
+ * Append the string representation to this builder.
+ * @see #toString()
+ */
+ public void toString(final StringBuilder builder) {
+ // Use a simple serializer to create the contents.
+ ManagedObjectPathSerializer serializer = new ManagedObjectPathSerializer() {
+
+ public void appendManagedObjectPathElement(
+ InstantiableRelationDefinition<?, ?> r, String name) {
+ builder.append('/');
+ builder.append(r.getName());
+ builder.append('/');
+ builder.append(name);
+ }
+
+
+
+ public void appendManagedObjectPathElement(
+ OptionalRelationDefinition<?, ?> r) {
+ builder.append('/');
+ builder.append(r.getName());
+ }
+
+
+
+ public void appendManagedObjectPathElement(
+ SingletonRelationDefinition<?, ?> r) {
+ builder.append('/');
+ builder.append(r.getName());
+ }
+
+ };
+
+ serialize(serializer);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectPathSerializer.java b/opends/src/server/org/opends/server/admin/ManagedObjectPathSerializer.java
new file mode 100644
index 0000000..3c4cd55
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectPathSerializer.java
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.admin;
+
+
+
+/**
+ * A strategy for serializing managed object paths.
+ * <p>
+ * This interface provides a generic means for serializing managed object paths
+ * into application specific forms. For example, a JNDI client would use this
+ * interface to construct <code>LdapName</code> objects from a path.
+ * Similarly, on the server side, a serialization strategy is used to construct
+ * <code>DN</code> instances from a path.
+ * <p>
+ * During serialization the serializer is invoked for each element in the
+ * managed object path in big-endian order, starting from the root and
+ * proceeding down to the leaf element.
+ */
+public interface ManagedObjectPathSerializer {
+
+ /**
+ * Append a managed object path element identified by an instantiable relation
+ * and an instance name.
+ *
+ * @param r
+ * The instantiable relation.
+ * @param name
+ * The instance name.
+ */
+ void appendManagedObjectPathElement(InstantiableRelationDefinition<?, ?> r,
+ String name);
+
+
+
+ /**
+ * Append a managed object path element identified by a optional relation.
+ *
+ * @param r
+ * The optional relation.
+ */
+ void appendManagedObjectPathElement(OptionalRelationDefinition<?, ?> r);
+
+
+
+ /**
+ * Append a managed object path element identified by a singleton relation.
+ *
+ * @param r
+ * The singleton relation.
+ */
+ void appendManagedObjectPathElement(SingletonRelationDefinition<?, ?> r);
+
+}
diff --git a/opends/src/server/org/opends/server/admin/OperationsException.java b/opends/src/server/org/opends/server/admin/OperationsException.java
new file mode 100644
index 0000000..4d362c7
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/OperationsException.java
@@ -0,0 +1,89 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Exceptions thrown as a result of errors that occurred when reading, listing,
+ * and modifying managed objects.
+ */
+public class OperationsException extends AdminException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 6329910102360262187L;
+
+
+
+ /**
+ * Create an operations exception.
+ */
+ public OperationsException() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Create an operations exception with a cause.
+ *
+ * @param cause
+ * The cause.
+ */
+ public OperationsException(Throwable cause) {
+ super(cause);
+ }
+
+
+
+ /**
+ * Create an operations exception with a message and cause.
+ *
+ * @param message
+ * The message.
+ * @param cause
+ * The cause.
+ */
+ public OperationsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+
+
+ /**
+ * Create an operations exception with a message.
+ *
+ * @param message
+ * The message.
+ */
+ public OperationsException(String message) {
+ super(message);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java b/opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java
new file mode 100644
index 0000000..7212e35
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/OptionalRelationDefinition.java
@@ -0,0 +1,90 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A managed object composite relationship definition which represents
+ * a composition of an optional single managed object (i.e. the
+ * referenced managed object may or may not be present).
+ *
+ * @param <C>
+ * The type of client managed object configuration that this
+ * relation definition refers to.
+ * @param <S>
+ * The type of server managed object configuration that this
+ * relation definition refers to.
+ */
+public final class OptionalRelationDefinition
+ <C extends ConfigurationClient, S extends Configuration>
+ extends RelationDefinition<C, S> {
+
+ /**
+ * Create a new optional managed object relation definition.
+ *
+ * @param pd
+ * The parent managed object definition.
+ * @param name
+ * The name of the relation.
+ * @param cd
+ * The child managed object definition.
+ */
+ public OptionalRelationDefinition(
+ AbstractManagedObjectDefinition<?, ?> pd, String name,
+ AbstractManagedObjectDefinition<C, S> cd) {
+ super(pd, name, cd);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void toString(StringBuilder builder) {
+ builder.append("name=");
+ builder.append(getName());
+ builder.append(" type=composition parent=");
+ builder.append(getParentDefinition().getName());
+ builder.append(" child=");
+ builder.append(getChildDefinition().getName());
+ builder.append(" minOccurs=0 maxOccurs=1");
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
+ return v.visitOptional(this, p);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyDefinition.java b/opends/src/server/org/opends/server/admin/PropertyDefinition.java
new file mode 100644
index 0000000..f55f64b
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyDefinition.java
@@ -0,0 +1,252 @@
+/*
+ * 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.admin;
+
+
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+
+
+/**
+ * An interface for querying generic property definition features.
+ * <p>
+ * Property definitions are analogous to ConfigAttributes in the current model
+ * and will play a similar role. Eventually these will replace them.
+ * <p>
+ * Implementations <b>must</b> take care to implement the various comparison
+ * methods.
+ * <p>
+ * Implementations of this interface must be serializable. This is required so
+ * that management applications can query property meta-information remotely.
+ * <p>
+ * TODO: define other call-backs (e.g. initial values).
+ *
+ * @param <T>
+ * The data-type of values of the property.
+ */
+public interface PropertyDefinition<T> extends Comparator<T>,
+ Comparable<PropertyDefinition<?>>, Serializable {
+
+ /**
+ * Apply a visitor to this property definition.
+ *
+ * @param <R>
+ * The return type of the visitor's methods.
+ * @param <P>
+ * The type of the additional parameters to the visitor's methods.
+ * @param v
+ * The property definition visitor.
+ * @param p
+ * Optional additional visitor parameter.
+ * @return Returns a result as specified by the visitor.
+ */
+ <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p);
+
+
+
+ /**
+ * Cast the provided value to the type associated with this property
+ * definition.
+ * <p>
+ * This method only casts the object to the required type; it does not
+ * validate the value once it has been cast. Subsequent validation should be
+ * performed using the method {@link #validateValue(Object)}.
+ * <p>
+ * This method guarantees the following expression is always
+ * <code>true</code>:
+ *
+ * <pre>
+ * PropertyDefinition d;
+ * x == d.cast(x);
+ * </pre>
+ *
+ * @param object
+ * The property value to be cast (can be <code>null</code>).
+ * @return Returns the property value cast to the correct type.
+ * @throws ClassCastException
+ * If the provided property value did not have the correct type.
+ */
+ T castValue(Object object) throws ClassCastException;
+
+
+
+ /**
+ * Compares this property definition with the specified property definition
+ * for order. Returns a negative integer, zero, or a positive integer if this
+ * property definition is less than, equal to, or greater than the specified
+ * property definition.
+ * <p>
+ * The ordering must be determined first from the property name and then base
+ * on the underlying value type.
+ *
+ * @param o
+ * The reference property definition with which to compare.
+ * @return Returns a negative integer, zero, or a positive integer if this
+ * property definition is less than, equal to, or greater than the
+ * specified property definition.
+ */
+ int compareTo(PropertyDefinition<?> o);
+
+
+
+ /**
+ * Parse and validate a string representation of a property value.
+ *
+ * @param value
+ * The property string value (must not be <code>null</code>).
+ * @return Returns the decoded property value.
+ * @throws IllegalPropertyValueStringException
+ * If the property value string is invalid.
+ */
+ T decodeValue(String value) throws IllegalPropertyValueStringException;
+
+
+
+ /**
+ * Encode the provided property value into its string representation.
+ * <p>
+ * TODO: change name to avoid confusion with toString()?
+ *
+ * @param value
+ * The property value (must not be <code>null</code>).
+ * @return Returns the encoded property string value.
+ * @throws IllegalPropertyValueException
+ * If the property value is invalid.
+ */
+ String encodeValue(T value) throws IllegalPropertyValueException;
+
+
+
+ /**
+ * Indicates whether some other object is "equal to" this property
+ * definition. This method must obey the general contract of
+ * <tt>Object.equals(Object)</tt>. Additionally, this method can return
+ * <tt>true</tt> <i>only</i> if the specified Object is also a property
+ * definition and it has the same name, as returned by {@link #getName()},
+ * and also is deemed to be "compatible" with this property
+ * definition. Compatibility means that the two property definitions share the
+ * same underlying value type and provide similar comparator implementations.
+ *
+ * @param o
+ * The reference object with which to compare.
+ * @return Returns <code>true</code> only if the specified object is also a
+ * property definition and it has the same name and is compatible with
+ * this property definition.
+ * @see java.lang.Object#equals(java.lang.Object)
+ * @see java.lang.Object#hashCode()
+ */
+ boolean equals(Object o);
+
+
+
+ /**
+ * Get the default behavior provider associated with this property
+ * definition.
+ *
+ * @return Returns the default behavior provider associated with this
+ * property definition.
+ */
+ DefaultBehaviorProvider<T> getDefaultBehaviorProvider();
+
+
+
+ /**
+ * Get the name of the property.
+ *
+ * @return Returns the name of the property.
+ */
+ String getName();
+
+
+
+ /**
+ * Returns a hash code value for this property definition. The hash code
+ * should be derived from the property name.
+ *
+ * @return Returns the hash code value for this property definition.
+ */
+ int hashCode();
+
+
+
+ /**
+ * Check if the specified option is set for this property definition.
+ *
+ * @param option
+ * The option to test.
+ * @return Returns <code>true</code> if the option is set, or
+ * <code>false</code> otherwise.
+ */
+ boolean hasOption(PropertyOption option);
+
+
+
+ /**
+ * Get a normalized string representation of a property value. This can then
+ * be used for comparisons and for generating hash-codes.
+ * <p>
+ * This method may throw an exception if the provided value is invalid.
+ * However, applications should not assume that implementations of this method
+ * will always validate a value. This task is the responsibility of
+ * {@link #validateValue(Object)}.
+ *
+ * @param value
+ * The property value to be normalized.
+ * @return Returns the normalized property value.
+ * @throws IllegalPropertyValueException
+ * If the property value is invalid.
+ */
+ String normalizeValue(T value) throws IllegalPropertyValueException;
+
+
+
+ /**
+ * Append a string representation of the property definition to the provided
+ * string builder.
+ *
+ * @param builder
+ * The string builder where the string representation should be
+ * appended.
+ */
+ void toString(StringBuilder builder);
+
+
+
+ /**
+ * Determine if the provided property value is valid according to this
+ * property definition.
+ *
+ * @param value
+ * The property value (must not be <code>null</code>).
+ * @throws IllegalPropertyValueException
+ * If the property value is invalid.
+ */
+ void validateValue(T value) throws IllegalPropertyValueException;
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java b/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
new file mode 100644
index 0000000..b0cfdf1
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyDefinitionVisitor.java
@@ -0,0 +1,212 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A visitor of property definitions, in the style of the visitor
+ * design pattern. Classes implementing this interface can query
+ * property definitions in a type-safe manner when the kind of
+ * property definition is unknown at compile time. When a visitor is
+ * passed to a property definition's accept method, the corresponding
+ * visit method most applicable to that property definition is
+ * invoked.
+ *
+ * @param <R>
+ * The return type of this visitor's methods. Use
+ * {@link java.lang.Void} for visitors that do not need to
+ * return results.
+ * @param <P>
+ * The type of the additional parameter to this visitor's
+ * methods. Use {@link java.lang.Void} for visitors that do
+ * not need an additional parameter.
+ */
+public interface PropertyDefinitionVisitor<R, P> {
+
+ /**
+ * Visit an attribute type property definition.
+ *
+ * @param d
+ * The attribute type property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitAttributeType(AttributeTypePropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a boolean property definition.
+ *
+ * @param d
+ * The boolean property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitBoolean(BooleanPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a class property definition.
+ *
+ * @param d
+ * The class property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitClass(ClassPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a DN property definition.
+ *
+ * @param d
+ * The DN property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitDN(DNPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a duration property definition.
+ *
+ * @param d
+ * The duration property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitDuration(DurationPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit an integer property definition.
+ *
+ * @param d
+ * The integer property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitInteger(IntegerPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a IP address property definition.
+ *
+ * @param d
+ * The IP address property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitIPAddress(IPAddressPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a IP address mask property definition.
+ *
+ * @param d
+ * The IP address mask property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitIPAddressMask(IPAddressMaskPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a size property definition.
+ *
+ * @param d
+ * The size property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitSize(SizePropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit a string property definition.
+ *
+ * @param d
+ * The string property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitString(StringPropertyDefinition d, P p);
+
+
+
+ /**
+ * Visit an unknown type of property definition. Implementations of
+ * this method can provide default behavior for unknown property
+ * definition types.
+ *
+ * @param d
+ * The property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ * @throws UnknownPropertyDefinitionException
+ * Visitor implementations may optionally throw this
+ * exception.
+ */
+ R visitUnknown(PropertyDefinition d, P p)
+ throws UnknownPropertyDefinitionException;
+
+
+
+ /**
+ * Visit an enumeration property definition.
+ *
+ * @param d
+ * The enumeration property definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitEnum(EnumPropertyDefinition<?> d, P p);
+
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyException.java b/opends/src/server/org/opends/server/admin/PropertyException.java
new file mode 100644
index 0000000..beb5246
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyException.java
@@ -0,0 +1,81 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Exceptions thrown as a result of errors that occurred when decoding and
+ * modifying property values.
+ */
+public abstract class PropertyException extends AdminRuntimeException {
+
+ /**
+ * Version ID required by serializable classes.
+ */
+ private static final long serialVersionUID = -8465109598081914482L;
+
+ // The property definition associated with the property that caused the
+ // exception.
+ private final PropertyDefinition<?> definition;
+
+
+
+ /**
+ * Create an operations exception with a cause.
+ *
+ * @param definition
+ * The property definition associated with the property that caused
+ * the exception.
+ */
+ protected PropertyException(PropertyDefinition<?> definition) {
+ this.definition = definition;
+ }
+
+
+
+ /**
+ * Get the property definition associated with the property that caused the
+ * exception.
+ *
+ * @return Returns the property definition associated with the property that
+ * caused the exception.
+ */
+ public final PropertyDefinition<?> getPropertyDefinition() {
+ return definition;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public abstract String getMessage();
+
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyIsMandatoryException.java b/opends/src/server/org/opends/server/admin/PropertyIsMandatoryException.java
new file mode 100644
index 0000000..153ff23
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyIsMandatoryException.java
@@ -0,0 +1,65 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown when an attempt is made to remove a mandatory property.
+ */
+public class PropertyIsMandatoryException extends PropertyException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 5328211711156565625L;
+
+
+
+ /**
+ * Create a new property is mandatory exception.
+ *
+ * @param d
+ * The property definition.
+ */
+ public PropertyIsMandatoryException(PropertyDefinition d) {
+ super(d);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "The property \"" + getPropertyDefinition().getName()
+ + "\" must not be removed as it is mandatory";
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyIsReadOnlyException.java b/opends/src/server/org/opends/server/admin/PropertyIsReadOnlyException.java
new file mode 100644
index 0000000..530e07a
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyIsReadOnlyException.java
@@ -0,0 +1,65 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown when an attempt is made to modify a read-only property.
+ */
+public class PropertyIsReadOnlyException extends PropertyException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 5315348044141024459L;
+
+
+
+ /**
+ * Create a new property is read-only exception.
+ *
+ * @param d
+ * The property definition.
+ */
+ public PropertyIsReadOnlyException(PropertyDefinition d) {
+ super(d);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "The property \"" + getPropertyDefinition().getName()
+ + "\" must not be modified as it is read-only";
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyIsSingleValuedException.java b/opends/src/server/org/opends/server/admin/PropertyIsSingleValuedException.java
new file mode 100644
index 0000000..283d3f3
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyIsSingleValuedException.java
@@ -0,0 +1,66 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown when an attempt is made to add more than value to a single-valued
+ * property.
+ */
+public class PropertyIsSingleValuedException extends PropertyException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -8056602690887917027L;
+
+
+
+ /**
+ * Create a new property is single valued exception.
+ *
+ * @param d
+ * The property definition.
+ */
+ public PropertyIsSingleValuedException(PropertyDefinition d) {
+ super(d);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "The property \"" + getPropertyDefinition().getName()
+ + "\" must not contain more than one value";
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyNotFoundException.java b/opends/src/server/org/opends/server/admin/PropertyNotFoundException.java
new file mode 100644
index 0000000..e0e29a9
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyNotFoundException.java
@@ -0,0 +1,73 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Thrown when an attempt is made to retrieve a property using its name but the
+ * name was not recognized.
+ * <p>
+ * This exception can occur when attempt is made to retrieve inherited default
+ * values from a managed object.
+ */
+public class PropertyNotFoundException extends OperationsException {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -895548482881819610L;
+
+ // The name of the property that could not be found.
+ private final String propertyName;
+
+
+
+ /**
+ * Create a new property not found exception.
+ *
+ * @param propertyName
+ * The name of the property that could not be found.
+ */
+ public PropertyNotFoundException(String propertyName) {
+ super("The property \"" + propertyName + "\" was not recognized");
+ this.propertyName = propertyName;
+ }
+
+
+
+ /**
+ * Get the name of the property that could not be found.
+ *
+ * @return Returns the name of the property that could not be found.
+ */
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyOption.java b/opends/src/server/org/opends/server/admin/PropertyOption.java
new file mode 100644
index 0000000..2d4341e
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyOption.java
@@ -0,0 +1,64 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * This enumeration contains various options that can be associated with
+ * property definitions.
+ */
+public enum PropertyOption {
+ /**
+ * Use this option to identify properties which must not be directly exposed
+ * in client applications.
+ */
+ HIDDEN,
+
+ /**
+ * Use this option to identify properties which must have a value.
+ */
+ MANDATORY,
+
+ /**
+ * Use this option to identify properties which are multi-valued.
+ */
+ MULTI_VALUED,
+
+ /**
+ * Use this option to identify properties which cannot be modified.
+ */
+ READ_ONLY,
+
+ /**
+ * Use this option to identify properties which, when modified, will require
+ * some additiona administrator action in order for the changes to take
+ * effect.
+ */
+ REQUIRES_ADMIN_ACTION
+}
diff --git a/opends/src/server/org/opends/server/admin/PropertyProvider.java b/opends/src/server/org/opends/server/admin/PropertyProvider.java
new file mode 100644
index 0000000..5b4eed8
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/PropertyProvider.java
@@ -0,0 +1,89 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.Collection;
+import java.util.Collections;
+
+
+
+/**
+ * An interface which can be used to initialize the contents of a managed
+ * object.
+ */
+public interface PropertyProvider {
+
+ /**
+ * A property provider which always returns empty property values, indicating
+ * default behavior.
+ */
+ public static final PropertyProvider DEFAULT_PROVIDER =
+ new PropertyProvider() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> Collection<T> getPropertyValues(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ return Collections.<T> emptySet();
+ }
+
+ };
+
+
+
+ /**
+ * Get the property values associated with the specified property definition.
+ * <p>
+ * Implementations are not required to validate the values that they provide.
+ * Specifically:
+ * <ul>
+ * <li>they do not need to guarantee that the provided values are valid
+ * according to the property's syntax
+ * <li>they do not need to provide values for mandatory properties
+ * <li>they do not need to ensure that single-valued properties do contain at
+ * most one value.
+ * </ul>
+ * The returned set of values is allowed to contain duplicates.
+ *
+ * @param <T>
+ * The underlying type of the property.
+ * @param d
+ * The Property definition.
+ * @return Returns a newly allocated set containing a copy of the property's
+ * values. An empty set indicates that the property has no values
+ * defined and any default behavior is applicable.
+ * @throws IllegalArgumentException
+ * If this property provider does not recognise the requested
+ * property definition.
+ */
+ <T> Collection<T> getPropertyValues(PropertyDefinition<T> d)
+ throws IllegalArgumentException;
+}
diff --git a/opends/src/server/org/opends/server/admin/RelationDefinition.java b/opends/src/server/org/opends/server/admin/RelationDefinition.java
new file mode 100644
index 0000000..11cef9e
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/RelationDefinition.java
@@ -0,0 +1,181 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Relation definitions define relationships between types of managed
+ * objects. In addition they define the ownership model:
+ * <ul>
+ * <li>composition - referenced managed objects are owned by the
+ * parent managed object and are deleted when the parent is deleted
+ * <li>aggregation - referenced managed objects are not owned by the
+ * parent managed object. Instead they are shared by other managed
+ * objects.
+ * </ul>
+ * Relations define how clients interact with the configuration. For
+ * example, clients manage aggregated managed objects in a shared
+ * location and attach them to parent managed objects. Composed
+ * managed objects, on the other hand, would be created directly
+ * beneath the parent managed object and destroyed with it too.
+ * <p>
+ * Within the server, listeners can choose to request notification of
+ * managed objects being added or removed from relations.
+ * <p>
+ * In LDAP, compositions are represented as follows:
+ * <ul>
+ * <li>singleton relations (one to one): a referenced managed object
+ * is represented using a child entry directly beneath the parent
+ * <li>optional relations (one to zero or one): a referenced managed
+ * object is represented using a child entry directly beneath the
+ * parent
+ * <li>instantiable relations (one to many): the relation is
+ * represented using a child entry directly beneath the parent.
+ * Referenced managed objects are represented using child entries of
+ * this "relation entry".
+ * </ul>
+ * Whereas, aggregations are represented by storing the DNs of the
+ * referenced managed objects in an attribute of the aggregating
+ * managed object.
+ *
+ * @param <C>
+ * The type of client managed object configuration that this
+ * relation definition refers to.
+ * @param <S>
+ * The type of server managed object configuration that this
+ * relation definition refers to.
+ */
+public abstract class RelationDefinition
+ <C extends ConfigurationClient, S extends Configuration> {
+
+ // The name of the relation.
+ private final String name;
+
+ // The definition of the parent managed object.
+ private final AbstractManagedObjectDefinition<?, ?> pd;
+
+ // The definition of the child managed object.
+ private final AbstractManagedObjectDefinition<C, S> cd;
+
+
+
+ /**
+ * Create a new managed object relation definition with the specified name and
+ * referenced managed object definition.
+ *
+ * @param pd
+ * The parent managed object definition.
+ * @param name
+ * The name of the relation.
+ * @param cd
+ * The child managed object definition.
+ */
+ protected RelationDefinition(AbstractManagedObjectDefinition<?, ?> pd,
+ String name, AbstractManagedObjectDefinition<C, S> cd) {
+ this.name = name;
+ this.pd = pd;
+ this.cd = cd;
+ }
+
+
+
+ /**
+ * Get the name of the relation.
+ *
+ * @return Returns the name of the relation.
+ */
+ public final String getName() {
+ return name;
+ }
+
+
+
+ /**
+ * Get the definition of the parent managed object.
+ *
+ * @return Returns the definition of the parent managed object.
+ */
+ public final AbstractManagedObjectDefinition<?, ?> getParentDefinition() {
+ return pd;
+ }
+
+
+
+ /**
+ * Get the definition of the child managed object.
+ *
+ * @return Returns the definition of the child managed object.
+ */
+ public final AbstractManagedObjectDefinition<C, S> getChildDefinition() {
+ return cd;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final String toString() {
+ StringBuilder builder = new StringBuilder();
+ toString(builder);
+ return builder.toString();
+ }
+
+
+
+ /**
+ * Append a string representation of the managed object relation to the
+ * provided string builder.
+ *
+ * @param builder
+ * The string builder where the string representation should be
+ * appended.
+ */
+ public abstract void toString(StringBuilder builder);
+
+
+
+ /**
+ * Apply a visitor to this relation definition.
+ *
+ * @param <R>
+ * The return type of the visitor's methods.
+ * @param <P>
+ * The type of the additional parameters to the visitor's
+ * methods.
+ * @param v
+ * The relation definition visitor.
+ * @param p
+ * Optional additional visitor parameter.
+ * @return Returns a result as specified by the visitor.
+ */
+ public abstract <R, P> R accept(RelationDefinitionVisitor<R, P> v,
+ P p);
+}
diff --git a/opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java b/opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java
new file mode 100644
index 0000000..22d3d3d
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/RelationDefinitionVisitor.java
@@ -0,0 +1,102 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A visitor of relation definitions, in the style of the visitor
+ * design pattern. Classes implementing this interface can query
+ * relation definitions in a type-safe manner when the kind of
+ * relation definition is unknown at compile time. When a visitor is
+ * passed to a relation definition's accept method, the corresponding
+ * visit method most applicable to that relation definition is
+ * invoked.
+ *
+ * @param <R>
+ * The return type of this visitor's methods. Use
+ * {@link java.lang.Void} for visitors that do not need to
+ * return results.
+ * @param <P>
+ * The type of the additional parameter to this visitor's
+ * methods. Use {@link java.lang.Void} for visitors that do
+ * not need an additional parameter.
+ */
+public interface RelationDefinitionVisitor<R, P> {
+
+ /**
+ * Visit an aggregation relation definition.
+ *
+ * @param d
+ * The aggregation relation definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitAggregation(AggregationRelationDefinition<?, ?> d, P p);
+
+
+
+ /**
+ * Visit an instantiable relation definition.
+ *
+ * @param d
+ * The instantiable relation definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitInstantiable(InstantiableRelationDefinition<?, ?> d, P p);
+
+
+
+ /**
+ * Visit an optional relation definition.
+ *
+ * @param d
+ * The optional relation definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitOptional(OptionalRelationDefinition<?, ?> d, P p);
+
+
+
+ /**
+ * Visit a singleton relation definition.
+ *
+ * @param d
+ * The singleton relation definition to visit.
+ * @param p
+ * A visitor specified parameter.
+ * @return Returns a visitor specified result.
+ */
+ R visitSingleton(SingletonRelationDefinition<?, ?> d, P p);
+
+}
diff --git a/opends/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java b/opends/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java
new file mode 100644
index 0000000..49c52e9
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java
@@ -0,0 +1,123 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A default behavior provider which retrieves default values from a parent
+ * managed object. It should be used by properties which inherit their default
+ * value(s) from properties held in an other managed object.
+ *
+ * @param <T>
+ * The type of values represented by this provider.
+ */
+public final class RelativeInheritedDefaultBehaviorProvider<T> implements
+ DefaultBehaviorProvider<T> {
+
+ // The relative offset (where 1 = parent, 2 = grandparent) of the managed
+ // object containing the property.
+ private final int offset;
+
+ // The name of the property containing the inherited default values.
+ private final String propertyName;
+
+
+
+ /**
+ * Create a relative inherited default behavior provider associated with a
+ * parent managed object.
+ *
+ * @param offset
+ * The relative location of the parent managed object (where 0 is the
+ * managed object itself, 1 is the parent, and 2 is the
+ * grand-parent).
+ * @param propertyName
+ * The name of the property containing the inherited default values.
+ * @throws IllegalArgumentException
+ * If the offset is less than 0.
+ */
+ public RelativeInheritedDefaultBehaviorProvider(int offset,
+ String propertyName) throws IllegalArgumentException {
+ if (offset < 0) {
+ throw new IllegalArgumentException("Negative offset");
+ }
+ this.propertyName = propertyName;
+ this.offset = offset;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
+ return v.visitRelativeInherited(this, p);
+ }
+
+
+
+ /**
+ * Get the absolute path of the managed object containing the property which
+ * has the default values.
+ *
+ * @param path
+ * The path of the current managed object from which the relative
+ * path should be determined.
+ * @return Returns the absolute path of the managed object containing the
+ * property which has the default values.
+ */
+ public ManagedObjectPath getManagedObjectPath(ManagedObjectPath path) {
+ return path.parent(offset);
+ }
+
+
+
+ /**
+ * Get the name of the property containing the inherited default values.
+ *
+ * @return Returns the name of the property containing the inherited default
+ * values.
+ */
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+
+
+ /**
+ * Get the relative location of the parent managed object.
+ *
+ * @return Returns the relative location of the parent managed object (where 0
+ * is the managed object itself, 1 is the parent, and 2 is the
+ * grand-parent).
+ */
+ public int getRelativeOffset() {
+ return offset;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java b/opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java
new file mode 100644
index 0000000..c0638bc
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/SingletonRelationDefinition.java
@@ -0,0 +1,89 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A managed object composite relationship definition which represents
+ * a compososition of a single managed object (i.e. the managed object
+ * must be present).
+ *
+ * @param <C>
+ * The type of client managed object configuration that this
+ * relation definition refers to.
+ * @param <S>
+ * The type of server managed object configuration that this
+ * relation definition refers to.
+ */
+public final class SingletonRelationDefinition
+ <C extends ConfigurationClient, S extends Configuration>
+ extends RelationDefinition<C, S> {
+
+ /**
+ * Create a new singleton managed object relation definition.
+ *
+ * @param pd
+ * The parent managed object definition.
+ * @param name
+ * The name of the relation.
+ * @param cd
+ * The child managed object definition.
+ */
+ public SingletonRelationDefinition(AbstractManagedObjectDefinition<?, ?> pd,
+ String name, AbstractManagedObjectDefinition<C, S> cd) {
+ super(pd, name, cd);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final void toString(StringBuilder builder) {
+ builder.append("name=");
+ builder.append(getName());
+ builder.append(" type=composition parent=");
+ builder.append(getParentDefinition().getName());
+ builder.append(" child=");
+ builder.append(getChildDefinition().getName());
+ builder.append(" minOccurs=1 maxOccurs=1");
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
+ return v.visitSingleton(this, p);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java b/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java
new file mode 100644
index 0000000..e1fafff
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/SizePropertyDefinition.java
@@ -0,0 +1,395 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+
+
+
+/**
+ * Memory size property definition.
+ * <p>
+ * All memory size property values are represented in bytes using longs.
+ * <p>
+ * All values must be zero or positive and within the lower/upper limit
+ * constraints. Support is provided for "unlimited" memory sizes. These are
+ * represented using a negative memory size value or using the string
+ * "unlimited".
+ */
+public final class SizePropertyDefinition extends
+ AbstractPropertyDefinition<Long> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = 2263747274588279580L;
+
+ // String used to represent unlimited memory sizes.
+ private static final String UNLIMITED = "unlimited";
+
+ // The lower limit of the property value in bytes.
+ private final long lowerLimit;
+
+ // The optional upper limit of the property value in bytes.
+ private final Long upperLimit;
+
+ // Indicates whether this property allows the use of the "unlimited" memory
+ // size value (represented using a -1L or the string "unlimited").
+ private final boolean allowUnlimited;
+
+
+
+ /**
+ * An interface for incrementally constructing memory size property
+ * definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<Long, SizePropertyDefinition> {
+
+ // The lower limit of the property value in bytes.
+ private long lowerLimit = 0L;
+
+ // The optional upper limit of the property value in bytes.
+ private Long upperLimit = null;
+
+ // Indicates whether this property allows the use of the "unlimited" memory
+ // size value (represented using a -1L or the string "unlimited").
+ private boolean allowUnlimited = false;
+
+
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * Set the lower limit in bytes.
+ *
+ * @param lowerLimit
+ * The new lower limit (must be >= 0) in bytes.
+ * @throws IllegalArgumentException
+ * If a negative lower limit was specified, or if the lower limit
+ * is greater than the upper limit.
+ */
+ public final void setLowerLimit(long lowerLimit)
+ throws IllegalArgumentException {
+ if (lowerLimit < 0) {
+ throw new IllegalArgumentException("Negative lower limit");
+ }
+ if (upperLimit != null && lowerLimit > upperLimit) {
+ throw new IllegalArgumentException(
+ "Lower limit greater than upper limit");
+ }
+ this.lowerLimit = lowerLimit;
+ }
+
+
+
+ /**
+ * Set the lower limit using a string representation of the limit.
+ *
+ * @param lowerLimit
+ * The string representation of the new lower limit.
+ * @throws IllegalArgumentException
+ * If the lower limit could not be parsed, or if a negative lower
+ * limit was specified, or the lower limit is greater than the
+ * upper limit.
+ */
+ public final void setLowerLimit(String lowerLimit)
+ throws IllegalArgumentException {
+ setLowerLimit(SizeUnit.parseValue(lowerLimit));
+ }
+
+
+
+ /**
+ * Set the upper limit in bytes.
+ *
+ * @param upperLimit
+ * The new upper limit in bytes or <code>null</code> if there is
+ * no upper limit.
+ * @throws IllegalArgumentException
+ * If the lower limit is greater than the upper limit.
+ */
+ public final void setUpperLimit(Long upperLimit)
+ throws IllegalArgumentException {
+ if (upperLimit != null) {
+ if (upperLimit < 0) {
+ throw new IllegalArgumentException("Negative upper limit");
+ }
+ if (lowerLimit > upperLimit) {
+ throw new IllegalArgumentException(
+ "Lower limit greater than upper limit");
+ }
+ }
+ this.upperLimit = upperLimit;
+ }
+
+
+
+ /**
+ * Set the upper limit using a string representation of the limit.
+ *
+ * @param upperLimit
+ * The string representation of the new upper limit, or
+ * <code>null</code> if there is no upper limit.
+ * @throws IllegalArgumentException
+ * If the upper limit could not be parsed, or if the lower limit
+ * is greater than the upper limit.
+ */
+ public final void setUpperLimit(String upperLimit)
+ throws IllegalArgumentException {
+ if (upperLimit == null) {
+ setUpperLimit((Long) null);
+ } else {
+ setUpperLimit(SizeUnit.parseValue(upperLimit));
+ }
+ }
+
+
+
+ /**
+ * Specify whether or not this property definition will allow unlimited
+ * values (default is false).
+ *
+ * @param allowUnlimited
+ * <code>true</code> if the property will allow unlimited values,
+ * or <code>false</code> otherwise.
+ */
+ public final void setAllowUnlimited(boolean allowUnlimited) {
+ this.allowUnlimited = allowUnlimited;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected SizePropertyDefinition buildInstance(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Long> defaultBehavior) {
+ return new SizePropertyDefinition(propertyName, options,
+ defaultBehavior, lowerLimit, upperLimit, allowUnlimited);
+ }
+
+ }
+
+
+
+ /**
+ * Create an memory size property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new integer property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private SizePropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<Long> defaultBehavior, Long lowerLimit,
+ Long upperLimit, boolean allowUnlimited) {
+ super(Long.class, propertyName, options, defaultBehavior);
+ this.lowerLimit = lowerLimit;
+ this.upperLimit = upperLimit;
+ this.allowUnlimited = allowUnlimited;
+ }
+
+
+
+ /**
+ * Get the lower limit in bytes.
+ *
+ * @return Returns the lower limit in bytes.
+ */
+ public long getLowerLimit() {
+ return lowerLimit;
+ }
+
+
+
+ /**
+ * Get the upper limit in bytes.
+ *
+ * @return Returns the upper limit in bytes or <code>null</code> if there is
+ * no upper limit.
+ */
+ public Long getUpperLimit() {
+ return upperLimit;
+ }
+
+
+
+ /**
+ * Determine whether this property allows unlimited memory sizes.
+ *
+ * @return Returns <code>true</code> if this this property allows unlimited
+ * memory sizes.
+ */
+ public boolean isAllowUnlimited() {
+ return allowUnlimited;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(Long value) throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ if (!allowUnlimited && value < lowerLimit) {
+ throw new IllegalPropertyValueException(this, value);
+
+ // unlimited allowed
+ } else if (value >= 0 && value < lowerLimit) {
+ throw new IllegalPropertyValueException(this, value);
+ }
+
+ if ((upperLimit != null) && (value > upperLimit)) {
+ throw new IllegalPropertyValueException(this, value);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encodeValue(Long value) throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // Make sure that we correctly encode negative values as "unlimited".
+ if (allowUnlimited) {
+ if (value < 0) {
+ return UNLIMITED;
+ }
+ }
+ // Encode the size value using the best-fit unit.
+ StringBuilder builder = new StringBuilder();
+ SizeUnit unit = SizeUnit.BYTES.getBestFitUnit(value);
+
+ // Cast to a long to remove fractional part (which should not be there
+ // anyway as the best-fit unit should result in an exact conversion).
+ builder.append((long) unit.fromBytes(value));
+
+ builder.append(unit.toString());
+ return builder.toString();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Long decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ // First check for the special "unlimited" value when necessary.
+ if (allowUnlimited) {
+ if (value.trim().equalsIgnoreCase(UNLIMITED)) {
+ return -1L;
+ }
+ }
+
+ // Decode the value.
+ Long i;
+ try {
+ i = SizeUnit.parseValue(value);
+ } catch (NumberFormatException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+
+ try {
+ validateValue(i);
+ } catch (IllegalPropertyValueException e) {
+ throw new IllegalPropertyValueStringException(this, value);
+ }
+ return i;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitSize(this, p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void toString(StringBuilder builder) {
+ super.toString(builder);
+
+ builder.append(" lowerLimit=");
+ builder.append(lowerLimit);
+
+ if (upperLimit != null) {
+ builder.append(" upperLimit=");
+ builder.append(upperLimit);
+ }
+
+ builder.append(" allowUnlimited=");
+ builder.append(allowUnlimited);
+
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compare(Long o1, Long o2) {
+ return o1.compareTo(o2);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/SizeUnit.java b/opends/src/server/org/opends/server/admin/SizeUnit.java
new file mode 100644
index 0000000..e4d4913
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/SizeUnit.java
@@ -0,0 +1,277 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+
+/**
+ * This enumeration defines various memory size units.
+ */
+public enum SizeUnit {
+
+ /**
+ * A byte unit.
+ */
+ BYTES(1L, "b", "bytes"),
+
+ /**
+ * A kilo-byte unit.
+ */
+ KILO_BYTES(1000L, "kb", "kilobytes"),
+
+ /**
+ * A kibi-byte unit.
+ */
+ KIBI_BYTES(1024L, "kib", "kibibytes"),
+
+ /**
+ * A mega-byte unit.
+ */
+ MEGA_BYTES((long) 1000 * 1000, "mb", "megabytes"),
+
+ /**
+ * A mebi-byte unit.
+ */
+ MEBI_BYTES((long) 1024 * 1024, "mib", "mebibytes"),
+
+ /**
+ * A giga-byte unit.
+ */
+ GIGA_BYTES((long) 1000 * 1000 * 1000, "gb", "gigabytes"),
+
+ /**
+ * A gibi-byte unit.
+ */
+ GIBI_BYTES((long) 1024 * 1024 * 1024, "gib", "gibibytes"),
+
+ /**
+ * A tera-byte unit.
+ */
+ TERA_BYTES((long) 1000 * 1000 * 1000 * 1000, "tb", "terabytes"),
+
+ /**
+ * A tebi-byte unit.
+ */
+ TEBI_BYTES((long) 1024 * 1024 * 1024 * 1024, "tib", "tebibytes");
+
+ // A lookup table for resolving a unit from its name.
+ private static final Map<String, SizeUnit> nameToUnit;
+ static {
+ nameToUnit = new HashMap<String, SizeUnit>();
+
+ for (SizeUnit unit : SizeUnit.values()) {
+ nameToUnit.put(unit.shortName, unit);
+ nameToUnit.put(unit.longName, unit);
+ }
+ }
+
+
+
+ /**
+ * Get the unit corresponding to the provided unit name.
+ *
+ * @param s
+ * The name of the unit. Can be the abbreviated or long name and can
+ * contain white space and mixed case characters.
+ * @return Returns the unit corresponding to the provided unit name.
+ * @throws IllegalArgumentException
+ * If the provided name did not correspond to a known memory size
+ * unit.
+ */
+ public static SizeUnit getUnit(String s) throws IllegalArgumentException {
+ SizeUnit unit = nameToUnit.get(s.trim().toLowerCase());
+ if (unit == null) {
+ throw new IllegalArgumentException("Illegal memory size unit \"" + s
+ + "\"");
+ }
+ return unit;
+ }
+
+
+
+ /**
+ * Parse the provided size string and return its equivalent size in bytes.
+ *
+ * @param s
+ * The size string to be parsed.
+ * @return Returns the parsed size in bytes.
+ * @throws NumberFormatException
+ * If the provided size string could not be parsed.
+ */
+ public static long parseValue(String s) throws NumberFormatException {
+ // Value must be a floating point number followed by a unit.
+ Pattern p = Pattern.compile("^\\s*(\\d+(\\.\\d+)?)\\s*(\\w+)\\s*$");
+ Matcher m = p.matcher(s);
+
+ if (!m.matches()) {
+ throw new NumberFormatException("Invalid size value \"" + s + "\"");
+ }
+
+ // Group 1 is the float.
+ double d;
+ try {
+ d = Double.valueOf(m.group(1));
+ } catch (NumberFormatException e) {
+ throw new NumberFormatException("Invalid size value \"" + s + "\"");
+ }
+
+ // Group 3 is the unit.
+ try {
+ SizeUnit u = getUnit(m.group(3));
+ return u.toBytes(d);
+ } catch (IllegalArgumentException e) {
+ throw new NumberFormatException("Invalid size value \"" + s + "\"");
+ }
+ }
+
+ // The size of the unit in bytes.
+ private final long sz;
+
+ // The abbreviation of the unit.
+ private final String shortName;
+
+ // The long name of the unit.
+ private final String longName;
+
+
+
+ // Private constructor.
+ private SizeUnit(long sz, String shortName, String longName) {
+ this.sz = sz;
+ this.shortName = shortName;
+ this.longName = longName;
+ }
+
+
+
+ /**
+ * Converts the specified size in bytes to this unit.
+ *
+ * @param amount
+ * The size in bytes.
+ * @return Returns size in this unit.
+ */
+ public double fromBytes(long amount) {
+ return ((double) amount / sz);
+ }
+
+
+
+ /**
+ * Get the best-fit unit for the specified amount in this unit. The returned
+ * unit will be able to represent the amount using an integral value (i.e. no
+ * fractional part).For example, if this unit is kilo-bytes and the amount
+ * 2000 is provided, then the best fit unit is mega-bytes: 2mb. Similarly, if
+ * the amount is 0.5, then the best fit unit will by bytes: 500b.
+ * <p>
+ * Only non-binary units are considered (i.e. kilo, mega, etc).
+ *
+ * @param amount
+ * The amount of this unit.
+ * @return Returns the best-fit unit for the specified amount in this unit.
+ */
+ public SizeUnit getBestFitUnit(double amount) {
+ long bytes = toBytes(amount);
+ if (bytes == 0) {
+ return this;
+ } else if (bytes > 0) {
+ // use array of SizeUnits; EnumSet iterates in natural order
+ for (SizeUnit unit : new SizeUnit[]{TERA_BYTES, GIGA_BYTES, MEGA_BYTES,
+ KILO_BYTES }) {
+ if ((bytes % unit.sz) == 0) {
+ return unit;
+ }
+ }
+ }
+ return BYTES;
+ }
+
+
+
+ /**
+ * Get the long name of this unit.
+ *
+ * @return Returns the long name of this unit.
+ */
+ public String getLongName() {
+ return longName;
+ }
+
+
+
+ /**
+ * Get the abbreviated name of this unit.
+ *
+ * @return Returns the abbreviated name of this unit.
+ */
+ public String getShortName() {
+ return shortName;
+ }
+
+
+
+ /**
+ * Get the number of bytes that this unit represents.
+ *
+ * @return Returns the number of bytes that this unit represents.
+ */
+ public long getSize() {
+ return sz;
+ }
+
+
+
+ /**
+ * Converts the specified size in this unit to bytes.
+ *
+ * @param amount
+ * The size as a quantity of this unit.
+ * @return Returns the number of bytes that the size represents.
+ */
+ public long toBytes(double amount) {
+ return (long) (sz * amount);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation returns the abbreviated name of this size unit.
+ */
+ @Override
+ public String toString() {
+ return shortName;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/StringPropertyDefinition.java b/opends/src/server/org/opends/server/admin/StringPropertyDefinition.java
new file mode 100644
index 0000000..f46d618
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/StringPropertyDefinition.java
@@ -0,0 +1,191 @@
+/*
+ * 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.admin;
+
+
+
+import static org.opends.server.util.Validator.ensureNotNull;
+
+import java.util.EnumSet;
+
+
+
+/**
+ * String property definition.
+ * <p>
+ * TODO: pattern matching.
+ */
+public final class StringPropertyDefinition extends
+ AbstractPropertyDefinition<String> {
+
+ /**
+ * Serialization ID.
+ */
+ private static final long serialVersionUID = -2739105900274621416L;
+
+ // Flag indicating whether values of this property are
+ // case-insensitive.
+ private final boolean isCaseInsensitive;
+
+
+
+ /**
+ * An interface for incrementally constructing string property definitions.
+ */
+ public static class Builder extends
+ AbstractBuilder<String, StringPropertyDefinition> {
+
+ // Flag indicating whether values of this property are
+ // case-insensitive.
+ private boolean isCaseInsensitive = true;
+
+
+
+ // Private constructor
+ private Builder(String propertyName) {
+ super(propertyName);
+ }
+
+
+
+ /**
+ * Set a flag indicating whether values of this property are
+ * case-insensitive.
+ *
+ * @param value
+ * <code>true</code> if values are case-insensitive, or
+ * <code>false</code> otherwise.
+ */
+ public final void setCaseInsensitive(boolean value) {
+ isCaseInsensitive = value;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected StringPropertyDefinition buildInstance(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<String> defaultBehavior) {
+ return new StringPropertyDefinition(propertyName, options,
+ defaultBehavior, isCaseInsensitive);
+ }
+
+ }
+
+
+
+ /**
+ * Create a string property definition builder.
+ *
+ * @param propertyName
+ * The property name.
+ * @return Returns the new string property definition builder.
+ */
+ public static Builder createBuilder(String propertyName) {
+ return new Builder(propertyName);
+ }
+
+
+
+ // Private constructor.
+ private StringPropertyDefinition(String propertyName,
+ EnumSet<PropertyOption> options,
+ DefaultBehaviorProvider<String> defaultBehavior,
+ boolean isCaseInsensitive) {
+ super(String.class, propertyName, options, defaultBehavior);
+ this.isCaseInsensitive = isCaseInsensitive;
+ }
+
+
+
+ /**
+ * Query whether values of this property are case-insensitive.
+ *
+ * @return Returns <code>true</code> if values are case-insensitive, or
+ * <code>false</code> otherwise.
+ */
+ public boolean isCaseInsensitive() {
+ return isCaseInsensitive;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String normalizeValue(String value)
+ throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ if (isCaseInsensitive()) {
+ return value.trim().toLowerCase();
+ } else {
+ return value.trim();
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateValue(String value) throws IllegalPropertyValueException {
+ ensureNotNull(value);
+
+ // No additional validation required for now (might do pattern
+ // matching in future).
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String decodeValue(String value)
+ throws IllegalPropertyValueStringException {
+ ensureNotNull(value);
+
+ return value;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+ return v.visitString(this, p);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/StringPropertyProvider.java b/opends/src/server/org/opends/server/admin/StringPropertyProvider.java
new file mode 100644
index 0000000..6597197
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/StringPropertyProvider.java
@@ -0,0 +1,88 @@
+/*
+ * 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.admin;
+
+
+
+import java.util.Collection;
+import java.util.Collections;
+
+
+
+/**
+ * An interface which can be used to initialize the contents of a managed object
+ * using the string representation of property values.
+ */
+public interface StringPropertyProvider {
+
+ /**
+ * A property provider which always returns empty property values, indicating
+ * default behavior.
+ */
+ public static final StringPropertyProvider DEFAULT_PROVIDER =
+ new StringPropertyProvider() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<String> getPropertyValues(PropertyDefinition<?> d)
+ throws IllegalArgumentException {
+ return Collections.<String> emptySet();
+ }
+
+ };
+
+
+
+ /**
+ * Get the property string values associated with the specified property
+ * definition.
+ * <p>
+ * Implementations are not required to validate the values that they provide.
+ * Specifically:
+ * <ul>
+ * <li>they do not need to guarantee that the provided values are valid
+ * according to the property's syntax
+ * <li>they do not need to provide values for mandatory properties
+ * <li>they do not need to ensure that single-valued properties do contain at
+ * most one value.
+ * </ul>
+ * The returned set of values is allowed to contain duplicates.
+ *
+ * @param d
+ * The Property definition.
+ * @return Returns a newly allocated set containing a copy of the property's
+ * string values. An empty set indicates that the property has no
+ * values defined and any default behavior is applicable.
+ * @throws IllegalArgumentException
+ * If this property provider does not recognise the requested
+ * property definition.
+ */
+ Collection<String> getPropertyValues(PropertyDefinition<?> d)
+ throws IllegalArgumentException;
+}
diff --git a/opends/src/server/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java b/opends/src/server/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java
new file mode 100644
index 0000000..0235c99
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * A default behavior provider which indicates undefined behavior. It should
+ * be used by properties which have no default values or behavior as such. For
+ * example, a description property, when left unset, has no default value and no
+ * side-effects.
+ *
+ * @param <T>
+ * The type of values represented by this provider.
+ */
+public final class UndefinedDefaultBehaviorProvider<T> implements
+ DefaultBehaviorProvider<T> {
+
+ /**
+ * Create an undefined default behavior provider.
+ */
+ public UndefinedDefaultBehaviorProvider() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
+ return v.visitUndefined(this, p);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/UnknownPropertyDefinitionException.java b/opends/src/server/org/opends/server/admin/UnknownPropertyDefinitionException.java
new file mode 100644
index 0000000..e1bc233
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/UnknownPropertyDefinitionException.java
@@ -0,0 +1,82 @@
+/*
+ * 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.admin;
+
+
+
+/**
+ * Indicates that an unknown type of property definition was encountered. This
+ * can occur as the management prototype develops and new kinds of property
+ * definitions are added.
+ */
+public final class UnknownPropertyDefinitionException
+ extends PropertyException {
+
+ // Generated serialization ID.
+ private static final long serialVersionUID = 7042646409131322385L;
+
+ // The visitor parameter if there was one.
+ private Object parameter;
+
+
+
+ /**
+ * Creates a new unknown property definition exception.
+ *
+ * @param d
+ * The unknown property definition.
+ * @param p
+ * The visitor parameter if there was one.
+ */
+ public UnknownPropertyDefinitionException(PropertyDefinition d, Object p) {
+ super(d);
+ this.parameter = p;
+ }
+
+
+
+ /**
+ * Get the visitor parameter if there was one.
+ *
+ * @return Returns the visitor parameter if there was one.
+ */
+ public Object getParameter() {
+ return parameter;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return "Unhandled property definition type encountered \""
+ + getPropertyDefinition().getClass().getName() + "\"";
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ExampleClient.java b/opends/src/server/org/opends/server/admin/client/ExampleClient.java
new file mode 100644
index 0000000..bf9d69b
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ExampleClient.java
@@ -0,0 +1,193 @@
+/*
+ * 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 2006-2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.admin.client;
+
+
+
+import static org.opends.server.loggers.Error.removeAllErrorLoggers;
+import static org.opends.server.util.ServerConstants.PROPERTY_SERVER_ROOT;
+
+import java.io.File;
+
+import org.opends.server.admin.ClassLoaderProvider;
+import org.opends.server.admin.AttributeTypePropertyDefinition;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.client.ldap.LDAPManagementContext;
+import org.opends.server.admin.std.client.ConnectionHandlerCfgClient;
+import org.opends.server.admin.std.client.GlobalCfgClient;
+import org.opends.server.admin.std.client.LDAPConnectionHandlerCfgClient;
+import org.opends.server.admin.std.client.RootCfgClient;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.extensions.ConfigFileHandler;
+import org.opends.server.types.InitializationException;
+
+
+
+/**
+ * Sample client code.
+ * <p>
+ * FIXME: should the configuration client managed object interfaces
+ * expose a commit() method?
+ * <p>
+ * FIXME: should the commit() method take a context parameter or
+ * should it be stored inside the managed object.
+ * <p>
+ * FIXME: should managed objects store their name internally?
+ */
+public final class ExampleClient {
+
+ /**
+ * Private constructor.
+ */
+ private ExampleClient() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Boot strap config and schema.
+ *
+ * @throws InitializationException
+ * If the directory server infrastructure could not be
+ * initialized.
+ * @throws ConfigException
+ * If a configuration problem was encountered.
+ */
+ private void initialize() throws InitializationException,
+ ConfigException {
+ // Make sure a new instance is created.
+ //
+ // This is effectively a no-op at the moment, but may do lazy
+ // initialization at some point.
+ DirectoryServer.getInstance();
+
+ // Initialize minimal features such as key syntaxes.
+ DirectoryServer.bootstrapClient();
+
+ // Many things are dependent on JMX to register an alert
+ // generator.
+ DirectoryServer.initializeJMX();
+
+ removeAllErrorLoggers(true);
+
+ // Initialize the configuration.
+ File instanceRoot = new File("build/package/OpenDS-0.1");
+ File configResourceDirectory = new File(instanceRoot, "config");
+ System.setProperty(PROPERTY_SERVER_ROOT, instanceRoot
+ .getAbsolutePath());
+ File configFile = new File(configResourceDirectory, "config.ldif");
+
+ DirectoryServer directoryServer = DirectoryServer.getInstance();
+
+ // Bootstrap definition classes.
+ ClassLoaderProvider.getInstance().enable();
+
+ directoryServer.initializeConfiguration(ConfigFileHandler.class
+ .getName(), configFile.getAbsolutePath());
+
+ // Initialize and load the schema files.
+ DirectoryServer.getInstance().initializeSchema();
+
+ // Switch off class name validation in client.
+ ClassPropertyDefinition.setAllowClassValidation(false);
+
+ // Switch off attribute type name validation in client.
+ AttributeTypePropertyDefinition.setCheckSchema(false);
+ }
+
+
+
+ /**
+ * Perform the client operations.
+ */
+ private void run() throws Exception {
+ ManagementContext ctx = LDAPManagementContext.createLDAPContext(
+ "localhost", 1389, "cn=directory manager", "password");
+
+ RootCfgClient root = ctx.getRootConfiguration();
+
+ // Modify global server property.
+ GlobalCfgClient server = root.getGlobalConfiguration();
+ System.out.println("Server check-schema is "
+ + server.isCheckSchema());
+ System.out.println("Changing to false and re-reading...");
+ server.setCheckSchema(false);
+ server.commit();
+
+ server = root.getGlobalConfiguration();
+ System.out.println("Server check-schema is "
+ + server.isCheckSchema());
+ System.out.println("Changing to true and re-reading...");
+ server.setCheckSchema(true);
+ server.commit();
+
+ server = root.getGlobalConfiguration();
+ System.out.println("Server check-schema is "
+ + server.isCheckSchema());
+
+ // List connection handlers.
+ System.out.println("Listing connection handlers...");
+ String[] names = root.listConnectionHandlers();
+ for (String name : names) {
+ ConnectionHandlerCfgClient handler = root
+ .getConnectionHandler(name);
+
+ System.out.println("Got type=" + handler.definition().getName()
+ + ", name=" + name);
+ System.out.println("Connection handler is-enabled is "
+ + handler.isEnabled());
+
+ if (handler instanceof LDAPConnectionHandlerCfgClient) {
+ LDAPConnectionHandlerCfgClient lhandler =
+ (LDAPConnectionHandlerCfgClient) handler;
+ System.out.println("LDAP Connection handler listen-port is "
+ + lhandler.getListenPort());
+ }
+ }
+ }
+
+
+
+ /**
+ * Sample client application.
+ *
+ * @param args
+ * CLI arguments.
+ * @throws Exception
+ * If a problem occurred.
+ */
+ public static void main(String[] args) throws Exception {
+ ExampleClient client = new ExampleClient();
+
+ client.initialize();
+ client.run();
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ExampleIntrospection.java b/opends/src/server/org/opends/server/admin/client/ExampleIntrospection.java
new file mode 100644
index 0000000..a5f2276
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ExampleIntrospection.java
@@ -0,0 +1,344 @@
+/*
+ * 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.admin.client;
+
+
+
+import static org.opends.server.loggers.Error.removeAllErrorLoggers;
+import static org.opends.server.util.ServerConstants.PROPERTY_SERVER_ROOT;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.ClassLoaderProvider;
+import org.opends.server.admin.AggregationRelationDefinition;
+import org.opends.server.admin.AttributeTypePropertyDefinition;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.RelationDefinitionVisitor;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.admin.std.meta.RootCfgDefn;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.extensions.ConfigFileHandler;
+import org.opends.server.types.InitializationException;
+
+
+
+/**
+ * An example application which uses introspection to output a list of
+ * potential CLI sub-commands.
+ */
+public final class ExampleIntrospection implements
+ RelationDefinitionVisitor<Void, String> {
+
+ /**
+ * Main application.
+ *
+ * @param args
+ * The command line arguments.
+ * @throws ConfigException
+ * If there was a configuration problem.
+ * @throws InitializationException
+ * If there was an initialization problem.
+ */
+ public static void main(String[] args)
+ throws InitializationException, ConfigException {
+ ExampleIntrospection app = new ExampleIntrospection();
+
+ app.processRootConfiguration();
+ }
+
+
+
+ // Private constructor.
+ private ExampleIntrospection() throws InitializationException,
+ ConfigException {
+ // Make sure a new instance is created.
+ //
+ // This is effectively a no-op at the moment, but may do lazy
+ // initialization at some point.
+ DirectoryServer.getInstance();
+
+ // Initialize minimal features such as key syntaxes.
+ DirectoryServer.bootstrapClient();
+
+ // Many things are dependent on JMX to register an alert
+ // generator.
+ DirectoryServer.initializeJMX();
+
+ removeAllErrorLoggers(true);
+
+ // Initialize the configuration.
+ File instanceRoot = new File("build/package/OpenDS-0.1");
+ File configResourceDirectory = new File(instanceRoot, "config");
+ System.setProperty(PROPERTY_SERVER_ROOT, instanceRoot
+ .getAbsolutePath());
+ File configFile = new File(configResourceDirectory, "config.ldif");
+
+ DirectoryServer directoryServer = DirectoryServer.getInstance();
+
+ // Bootstrap definition classes.
+ ClassLoaderProvider.getInstance().enable();
+
+ directoryServer.initializeConfiguration(ConfigFileHandler.class
+ .getName(), configFile.getAbsolutePath());
+
+ // Initialize and load the schema files.
+ DirectoryServer.getInstance().initializeSchema();
+
+ // Switch off class name validation in client.
+ ClassPropertyDefinition.setAllowClassValidation(false);
+
+ // Switch off attribute type name validation in client.
+ AttributeTypePropertyDefinition.setCheckSchema(false);
+ }
+
+
+
+ /**
+ * Process the root configuration definition.
+ */
+ public void processRootConfiguration() {
+ RootCfgDefn d = RootCfgDefn.getInstance();
+
+ String operands = "";
+ for (RelationDefinition<?, ?> r : d.getRelationDefinitions()) {
+ r.accept(this, operands);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitAggregation(AggregationRelationDefinition<?, ?> d,
+ String p) {
+ System.err.println("Found aggregation \"" + d.getName()
+ + "\": aggregations are not supported yet");
+
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitInstantiable(
+ InstantiableRelationDefinition<?, ?> d, String p) {
+ String operands = p + " NAME";
+
+ List<ManagedObjectDefinition<?, ?>> types = getSubTypes(d);
+ String typesOption = getSubTypesOption(d, types);
+
+ System.out.println("create-" + d.getName() + typesOption
+ + operands + " [PROP:VALUE ...]");
+ System.out.println("delete-" + d.getName() + operands);
+ System.out.println("list-" + d.getPluralName() + p);
+ System.out.println("get-" + d.getName() + "-prop" + operands
+ + " [PROP ...]");
+ System.out.println("set-" + d.getName() + "-prop" + operands
+ + " [PROP[+|-]:VALUE ...]");
+
+ System.out.println();
+
+ // Process relations associated with the referenced definition and
+ // its sub-types.
+ processRelationDefinition(d, operands);
+
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitOptional(OptionalRelationDefinition<?, ?> d,
+ String p) {
+ String name = d.getName();
+
+ List<ManagedObjectDefinition<?, ?>> types = getSubTypes(d);
+ String typesOption = getSubTypesOption(d, types);
+
+ System.out.println("create-" + name + typesOption + p
+ + " [PROP:VALUE ...]");
+ System.out.println("delete-" + name + p);
+ System.out.println("has-" + name + p);
+ System.out.println("get-" + name + "-prop" + p + " [PROP ...]");
+ System.out.println("set-" + name + "-prop" + p
+ + " [PROP[+|-]:VALUE ...]");
+
+ System.out.println();
+
+ // Process relations associated with the referenced definition and
+ // its sub-types.
+ processRelationDefinition(d, p);
+
+ return null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Void visitSingleton(SingletonRelationDefinition<?, ?> d,
+ String p) {
+ String name = d.getName();
+
+ System.out.println("get-" + name + "-prop" + p + " [PROP ...]");
+ System.out.println("set-" + name + "-prop" + p
+ + " [PROP[+|-]:VALUE ...]");
+
+ System.out.println();
+
+ return null;
+ }
+
+
+
+ // Get all the possible types that can be associated with a
+ // relation.
+ private List<ManagedObjectDefinition<?, ?>> getSubTypes(
+ RelationDefinition<?, ?> d) {
+ List<ManagedObjectDefinition<?, ?>> types =
+ new LinkedList<ManagedObjectDefinition<?, ?>>();
+ AbstractManagedObjectDefinition<?, ?> ad = d.getChildDefinition();
+
+ getSubTypesHelp(ad, types);
+
+ return types;
+ }
+
+
+
+ // Get sub-types helper method.
+ private void getSubTypesHelp(
+ AbstractManagedObjectDefinition<?, ?> ad,
+ List<ManagedObjectDefinition<?, ?>> types) {
+ // Add this definition if it is not abstract.
+ if (ad instanceof ManagedObjectDefinition<?, ?>) {
+ ManagedObjectDefinition<?, ?> d = (ManagedObjectDefinition<?, ?>) ad;
+ types.add(d);
+ }
+
+ // Repeat for children.
+ for (AbstractManagedObjectDefinition<?, ?> d : ad.getChildren()) {
+ getSubTypesHelp(d, types);
+ }
+ }
+
+
+
+ // Convert a list of sub-types to a "-t" option usage.
+ private String getSubTypesOption(RelationDefinition<?, ?> r,
+ List<ManagedObjectDefinition<?, ?>> types) {
+ AbstractManagedObjectDefinition<?, ?> cd = r.getChildDefinition();
+ String base = "";
+ if (cd instanceof AbstractManagedObjectDefinition<?, ?>) {
+ base = cd.getName();
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.append(" -t ");
+
+ Iterator<ManagedObjectDefinition<?, ?>> i = types.iterator();
+ String suffix = "-" + base;
+ while (i.hasNext()) {
+ ManagedObjectDefinition<?, ?> d = i.next();
+
+ String name = d.getName();
+ if (name.equals(cd.getName())) {
+ // When the base type is itself instantiable use "generic".
+ name = "generic";
+ } else if (name.endsWith(suffix)) {
+ name = name.substring(0, name.length() - suffix.length());
+ }
+
+ builder.append(name);
+ if (i.hasNext()) {
+ builder.append('|');
+ }
+ }
+
+ return builder.toString();
+ }
+
+
+
+ // Process the relations associated with the managed objects
+ // referenced from the specified relation.
+ private void processRelationDefinition(RelationDefinition<?, ?> d,
+ String operands) {
+ AbstractManagedObjectDefinition<?, ?> ad = d.getChildDefinition();
+ processManagedObjectDefinition(null, ad, operands);
+ }
+
+
+
+ // Process the relations of a child managed object definition.
+ private void processManagedObjectDefinition(
+ AbstractManagedObjectDefinition<?, ?> parent,
+ AbstractManagedObjectDefinition<?, ?> child, String operands) {
+ Set<RelationDefinition<?, ?>> parentRelations;
+ Set<RelationDefinition<?, ?>> childRelations;
+
+ if (parent != null) {
+ parentRelations = new HashSet<RelationDefinition<?, ?>>(parent
+ .getRelationDefinitions());
+ } else {
+ parentRelations = Collections.emptySet();
+ }
+
+ // Only process relations not defined in parent.
+ childRelations = new HashSet<RelationDefinition<?, ?>>(child
+ .getRelationDefinitions());
+ childRelations.removeAll(parentRelations);
+
+ for (RelationDefinition<?, ?> r : childRelations) {
+ r.accept(this, operands);
+ }
+
+ // Process sub-types.
+ for (AbstractManagedObjectDefinition<?, ?> d : child
+ .getChildren()) {
+ processManagedObjectDefinition(child, d, operands);
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/client/InitialManagedObject.java b/opends/src/server/org/opends/server/admin/client/InitialManagedObject.java
new file mode 100644
index 0000000..aa478dc
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/InitialManagedObject.java
@@ -0,0 +1,352 @@
+/*
+ * 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.admin.client;
+
+
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.SortedSet;
+
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.IllegalPropertyValueException;
+import org.opends.server.admin.InheritedDefaultValueProvider;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OperationsException;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.PropertyIsMandatoryException;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.PropertyIsSingleValuedException;
+import org.opends.server.admin.PropertyNotFoundException;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.SingletonRelationDefinition;
+
+
+
+/**
+ * A managed object which is not bound to any underlying management
+ * context.
+ * <p>
+ * The purpose of this managed object implementation is to facilitate
+ * the construction of new configuration objects. Once all appropriate
+ * properties are set, the initial managed object can be used as a
+ * property provider during an invocation of
+ * <code>ManagedObject#createChild</code>.
+ * <p>
+ * Any attempt to commit, retrieve, list, remove, or add new child
+ * managed objects will result in an
+ * {@link UnsupportedOperationException}.
+ *
+ * @param <C>
+ * The type of client configuration represented by the client
+ * managed object.
+ */
+public final class InitialManagedObject<C extends ConfigurationClient>
+ implements ManagedObject<C> {
+
+ /**
+ * Internal inherited default value provider implementation.
+ * <p>
+ * FIXME: very dumb implementation which always throws a
+ * PropertyNotFoundException.
+ */
+ private static class MyInheritedDefaultValueProvider implements
+ InheritedDefaultValueProvider {
+
+ // Private constructor.
+ private MyInheritedDefaultValueProvider() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<?> getDefaultPropertyValues(
+ ManagedObjectPath path, String propertyName)
+ throws OperationsException, PropertyNotFoundException {
+ throw new PropertyNotFoundException(propertyName);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedObjectPath getManagedObjectPath() {
+ return ManagedObjectPath.emptyPath();
+ }
+ }
+
+ // The managed object definition associated with this managed
+ // object.
+ private final ManagedObjectDefinition<C, ?> definition;
+
+ // The managed object's properties.
+ private final PropertySet properties;
+
+
+
+ /**
+ * Creates a new initial managed object associated with the
+ * specified definition.
+ *
+ * @param definition
+ * The managed object definition.
+ */
+ public InitialManagedObject(ManagedObjectDefinition<C, ?> definition) {
+ this.definition = definition;
+
+ // FIXME: how will we cope with inherited default values?
+ List<PropertyException> exceptions = new LinkedList<PropertyException>();
+ this.properties = PropertySet.create(definition,
+ PropertyProvider.DEFAULT_PROVIDER,
+ new MyInheritedDefaultValueProvider(), exceptions);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public void commit() throws OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public <M extends ConfigurationClient, N extends M>
+ ManagedObject<N> createChild(
+ InstantiableRelationDefinition<M, ?> r,
+ ManagedObjectDefinition<N, ?> d, String name, PropertyProvider p)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public <M extends ConfigurationClient, N extends M>
+ ManagedObject<N> createChild(
+ OptionalRelationDefinition<M, ?> r,
+ ManagedObjectDefinition<N, ?> d, PropertyProvider p)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ InstantiableRelationDefinition<M, ?> d, String name)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ OptionalRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ SingletonRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public C getConfiguration() {
+ return definition.createClientConfiguration(this);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedObjectDefinition<C, ?> getManagedObjectDefinition() {
+ return definition;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public ManagedObjectPath getManagedObjectPath() {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> T getPropertyValue(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ return properties.getPropertyValue(d);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ return properties.getPropertyValues(d);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public boolean hasChild(OptionalRelationDefinition<?, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public String[] listChildren(InstantiableRelationDefinition<?, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public <M extends ConfigurationClient> void removeChild(
+ InstantiableRelationDefinition<M, ?> d, String name)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation throws an
+ * {@link UnsupportedOperationException}.
+ */
+ public <M extends ConfigurationClient> void removeChild(
+ OptionalRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ throw new UnsupportedOperationException();
+
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
+ throws IllegalPropertyValueException,
+ PropertyIsReadOnlyException, PropertyIsMandatoryException,
+ IllegalArgumentException {
+ properties.setPropertyValue(d, value);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> void setPropertyValues(PropertyDefinition<T> d,
+ Collection<T> values) throws IllegalPropertyValueException,
+ PropertyIsSingleValuedException, PropertyIsReadOnlyException,
+ PropertyIsMandatoryException, IllegalArgumentException {
+ properties.setPropertyValues(d, values);
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ManagedObject.java b/opends/src/server/org/opends/server/admin/client/ManagedObject.java
new file mode 100644
index 0000000..c0ebde7
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ManagedObject.java
@@ -0,0 +1,475 @@
+/*
+ * 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.admin.client;
+
+
+
+import java.util.Collection;
+import java.util.SortedSet;
+
+import org.opends.server.admin.IllegalPropertyValueException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OperationsException;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyIsMandatoryException;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.PropertyIsSingleValuedException;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.SingletonRelationDefinition;
+
+
+
+/**
+ * A generic interface for accessing client-side managed objects.
+ * <p>
+ * A managed object comprises of zero or more properties. A property
+ * has associated with it three sets of property value(s). These are:
+ * <ul>
+ * <li><i>default value(s)</i> - these value(s) represent the
+ * default behavior for the property when it has no active values.
+ * When a property inherits its default value(s) from elsewhere (i.e.
+ * a property in another managed object), the default value(s)
+ * represent the active value(s) of the inherited property at the time
+ * the managed object was retrieved
+ * <li><i>active value(s)</i> - these value(s) represent the state
+ * of the property at the time the managed object was retrieved
+ * <li><i>pending value(s)</i> - these value(s) represent any
+ * modifications made to the property's value(s) since the managed
+ * object object was retrieved and before the changes have been
+ * committed using the {@link #commit()} method, the pending values
+ * can be empty indicating that the property should be modified back
+ * to its default values.
+ * </ul>
+ * In addition, a property has an <i>effective state</i> defined by
+ * its <i>effective values</i> which are derived by evaluating the
+ * following rules in the order presented:
+ * <ul>
+ * <li>the <i>pending values</i> if defined and non-empty
+ * <li>or, the <i>default values</i> if the pending values are
+ * defined but are empty
+ * <li>or, the <i>active values</i> if defined and non-empty
+ * <li>or, the <i>default values</i> if there are no active values
+ * <li>or, an empty set of values, if there are no default values.
+ * </ul>
+ *
+ * @param <C>
+ * The type of client configuration represented by the client
+ * managed object.
+ */
+public interface ManagedObject<C extends ConfigurationClient> extends
+ PropertyProvider {
+
+ /**
+ * Get the effective value of the specified property.
+ * <p>
+ * See the class description for more information about how the
+ * effective property value is derived.
+ *
+ * @param <T>
+ * The type of the property to be retrieved.
+ * @param d
+ * The property to be retrieved.
+ * @return Returns the property's effective value, or
+ * <code>null</code> if there is no effective value
+ * defined.
+ * @throws IllegalArgumentException
+ * If the property definition is not associated with this
+ * managed object's definition.
+ */
+ public <T> T getPropertyValue(PropertyDefinition<T> d)
+ throws IllegalArgumentException;
+
+
+
+ /**
+ * Get the effective values of the specified property.
+ * <p>
+ * See the class description for more information about how the
+ * effective property values are derived.
+ *
+ * @param <T>
+ * The type of the property to be retrieved.
+ * @param d
+ * The property to be retrieved.
+ * @return Returns the property's effective values, or an empty set
+ * if there are no effective values defined.
+ * @throws IllegalArgumentException
+ * If the property definition is not associated with this
+ * managed object's definition.
+ */
+ public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d)
+ throws IllegalArgumentException;
+
+
+
+ /**
+ * Set a new pending value for the specified property.
+ * <p>
+ * See the class description for more information regarding pending
+ * values.
+ *
+ * @param <T>
+ * The type of the property to be modified.
+ * @param d
+ * The property to be modified.
+ * @param value
+ * The new pending value for the property, or
+ * <code>null</code> if the property should be reset to
+ * its default behavior.
+ * @throws IllegalPropertyValueException
+ * If the new pending value is deemed to be invalid
+ * according to the property definition.
+ * @throws PropertyIsReadOnlyException
+ * If an attempt was made to modify a read-only property.
+ * @throws PropertyIsMandatoryException
+ * If an attempt was made to remove a mandatory property.
+ * @throws IllegalArgumentException
+ * If the specified property definition is not associated
+ * with this managed object, or if the property is
+ * read-only.
+ */
+ public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
+ throws IllegalPropertyValueException,
+ PropertyIsReadOnlyException, PropertyIsMandatoryException,
+ IllegalArgumentException;
+
+
+
+ /**
+ * Set a new pending values for the specified property.
+ * <p>
+ * See the class description for more information regarding pending
+ * values.
+ *
+ * @param <T>
+ * The type of the property to be modified.
+ * @param d
+ * The property to be modified.
+ * @param values
+ * A non-<code>null</code> set of new pending values for
+ * the property (an empty set indicates that the property
+ * should be reset to its default behavior). The set will
+ * not be referenced by this managed object.
+ * @throws IllegalPropertyValueException
+ * If a new pending value is deemed to be invalid
+ * according to the property definition.
+ * @throws PropertyIsSingleValuedException
+ * If an attempt was made to add multiple pending values
+ * to a single-valued property.
+ * @throws PropertyIsReadOnlyException
+ * If an attempt was made to modify a read-only property.
+ * @throws PropertyIsMandatoryException
+ * If an attempt was made to remove a mandatory property.
+ * @throws IllegalArgumentException
+ * If the specified property definition is not associated
+ * with this managed object, or if the property is
+ * read-only.
+ */
+ public <T> void setPropertyValues(PropertyDefinition<T> d,
+ Collection<T> values) throws IllegalPropertyValueException,
+ PropertyIsSingleValuedException, PropertyIsReadOnlyException,
+ PropertyIsMandatoryException, IllegalArgumentException;
+
+
+
+ /**
+ * Commit any changes made to this managed object. Pending property
+ * values will be committed to the managed object. If successful,
+ * the pending values will become active values.
+ * <p>
+ * See the class description for more information regarding pending
+ * and active values.
+ *
+ * @throws OperationsException
+ * If the changes to this managed object could not be
+ * committed due to some underlying communication problem.
+ */
+ void commit() throws OperationsException;
+
+
+
+ /**
+ * Creates a new child managed object bound to the specified
+ * instantiable relation. The new managed object instance will be
+ * created with values taken from a property provider. The caller
+ * must make sure that the property provider provides values for
+ * mandatory properties.
+ *
+ * @param <M>
+ * The expected type of the child managed object
+ * configuration client.
+ * @param <N>
+ * The actual type of the added managed object
+ * configuration client.
+ * @param r
+ * The instantiable relation definition.
+ * @param d
+ * The definition of the managed object to be created.
+ * @param name
+ * The name of the child managed object.
+ * @param p
+ * A property provider which should be used to initialize
+ * property values of the new managed object.
+ * @return Returns a new child managed object bound to the specified
+ * instantiable relation.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed object could not be created due to some
+ * underlying communication problem.
+ */
+ <M extends ConfigurationClient, N extends M> ManagedObject<N> createChild(
+ InstantiableRelationDefinition<M, ?> r,
+ ManagedObjectDefinition<N, ?> d, String name, PropertyProvider p)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Creates a new child managed object bound to the specified
+ * optional relation. The new managed object instance will be
+ * created with values taken from a property provider. The caller
+ * must make sure that the property provider provides values for
+ * mandatory properties.
+ *
+ * @param <M>
+ * The expected type of the child managed object
+ * configuration client.
+ * @param <N>
+ * The actual type of the added managed object
+ * configuration client.
+ * @param r
+ * The optional relation definition.
+ * @param d
+ * The definition of the managed object to be created.
+ * @param p
+ * A property provider which should be used to initialize
+ * property values of the new managed object.
+ * @return Returns a new child managed object bound to the specified
+ * optional relation.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed object could not be created due to some
+ * underlying communication problem.
+ */
+ <M extends ConfigurationClient, N extends M> ManagedObject<N> createChild(
+ OptionalRelationDefinition<M, ?> r,
+ ManagedObjectDefinition<N, ?> d, PropertyProvider p)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Retrieve an instantiable child managed object.
+ *
+ * @param <M>
+ * The requested type of the child managed object
+ * configuration client.
+ * @param d
+ * The instantiable relation definition.
+ * @param name
+ * The name of the child managed object.
+ * @return Returns the instantiable child managed object.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed object could not be read due to some
+ * underlying communication problem.
+ */
+ <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ InstantiableRelationDefinition<M, ?> d, String name)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Retrieve an optional child managed object.
+ *
+ * @param <M>
+ * The requested type of the child managed object
+ * configuration client.
+ * @param d
+ * The optional relation definition.
+ * @return Returns the optional child managed object.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed object could not be read due to some
+ * underlying communication problem.
+ */
+ <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ OptionalRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Retrieve a singleton child managed object.
+ *
+ * @param <M>
+ * The requested type of the child managed object
+ * configuration client.
+ * @param d
+ * The singleton relation definition.
+ * @return Returns the singleton child managed object.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed object could not be read due to some
+ * underlying communication problem.
+ */
+ <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ SingletonRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Creates a client configuration view of this managed object.
+ * Modifications made to this managed object will be reflected in
+ * the client configuration view and vice versa.
+ *
+ * @return Returns a client configuration view of this managed
+ * object.
+ */
+ C getConfiguration();
+
+
+
+ /**
+ * Get the definition associated with this managed object.
+ *
+ * @return Returns the definition associated with this managed
+ * object.
+ */
+ ManagedObjectDefinition<C, ?> getManagedObjectDefinition();
+
+
+
+ /**
+ * Get the path of this managed object.
+ *
+ * @return Returns the path of this managed object.
+ */
+ ManagedObjectPath getManagedObjectPath();
+
+
+
+ /**
+ * Determines whether or not the optional managed object associated
+ * with the specified optional relations exists.
+ *
+ * @param d
+ * The optional relation definition.
+ * @return Returns <code>true</code> if the optional managed
+ * object exists, <code>false</code> otherwise.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the existance of the optional managed object could
+ * not be determined due to some underlying communication
+ * problem.
+ */
+ boolean hasChild(OptionalRelationDefinition<?, ?> d)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Lists the child managed objects associated with the specified
+ * instantiable relation.
+ *
+ * @param d
+ * The instantiable relation definition.
+ * @return Returns the names of the child managed objects.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed objects could not be listed due to some
+ * underlying communication problem.
+ */
+ String[] listChildren(InstantiableRelationDefinition<?, ?> d)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Removes the named instantiable child managed object.
+ *
+ * @param <M>
+ * The type of the child managed object configuration
+ * client.
+ * @param d
+ * The instantiable relation definition.
+ * @param name
+ * The name of the child managed object to be removed.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed object could not be removed due to some
+ * underlying communication problem.
+ */
+ <M extends ConfigurationClient> void removeChild(
+ InstantiableRelationDefinition<M, ?> d, String name)
+ throws IllegalArgumentException, OperationsException;
+
+
+
+ /**
+ * Removes an optional child managed object.
+ *
+ * @param <M>
+ * The type of the child managed object configuration
+ * client.
+ * @param d
+ * The optional relation definition.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws OperationsException
+ * If the managed object could not be removed due to some
+ * underlying communication problem.
+ */
+ <M extends ConfigurationClient> void removeChild(
+ OptionalRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException;
+
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ManagedObjectDecodingException.java b/opends/src/server/org/opends/server/admin/client/ManagedObjectDecodingException.java
new file mode 100644
index 0000000..a960c48
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ManagedObjectDecodingException.java
@@ -0,0 +1,119 @@
+/*
+ * 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.admin.client;
+
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import org.opends.server.admin.DecodingException;
+import org.opends.server.admin.PropertyException;
+
+
+
+/**
+ * The requested managed object was found but one or more of its properties
+ * could not be decoded successfully.
+ */
+public class ManagedObjectDecodingException extends DecodingException {
+
+ /**
+ * Version ID required by serializable classes.
+ */
+ private static final long serialVersionUID = -4268510652395945357L;
+
+ // The partially created managed object.
+ private final ManagedObject<?> partialManagedObject;
+
+ // The exception(s) that caused this decoding exception.
+ private final Collection<PropertyException> causes;
+
+
+
+ /**
+ * Create a new property decoding exception.
+ *
+ * @param partialManagedObject
+ * The partially created managed object containing properties which
+ * were successfully decoded and empty properties for those which
+ * were not (this may include empty mandatory properties).
+ * @param causes
+ * The exception(s) that caused this decoding exception.
+ */
+ public ManagedObjectDecodingException(ManagedObject<?> partialManagedObject,
+ Collection<PropertyException> causes) {
+ this.partialManagedObject = partialManagedObject;
+ this.causes = Collections
+ .unmodifiableList(new LinkedList<PropertyException>(causes));
+ }
+
+
+
+ /**
+ * Get an unmodifiable collection view of the causes of this exception.
+ *
+ * @return Returns an unmodifiable collection view of the causes of this
+ * exception.
+ */
+ public Collection<PropertyException> getCauses() {
+ return causes;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("The managed object could not be decoded due"
+ + " to the following property exceptions: ");
+ // FIXME: better formatting.
+ builder.append(causes.toString());
+ return builder.toString();
+ }
+
+
+
+ /**
+ * Get the partially created managed object containing properties which were
+ * successfully decoded and empty properties for those which were not (this
+ * may include empty mandatory properties).
+ *
+ * @return Returns the partially created managed object containing properties
+ * which were successfully decoded and empty properties for those
+ * which were not (this may include empty mandatory properties).
+ */
+ public ManagedObject<?> getPartialManagedObject() {
+ return partialManagedObject;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ManagementContext.java b/opends/src/server/org/opends/server/admin/client/ManagementContext.java
new file mode 100644
index 0000000..fe93523
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ManagementContext.java
@@ -0,0 +1,64 @@
+/*
+ * 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.admin.client;
+
+
+
+import org.opends.server.admin.std.client.RootCfgClient;
+
+
+
+/**
+ * Management connection context.
+ */
+public abstract class ManagementContext {
+
+ /**
+ * Get the root configuration managed object associated with this
+ * management context.
+ *
+ * @return Returns the root configuration managed object associated
+ * with this management context.
+ */
+ public abstract ManagedObject<RootCfgClient>
+ getRootConfigurationManagedObject();
+
+
+
+ /**
+ * Get the root configuration client associated with this management
+ * context.
+ *
+ * @return Returns the root configuration client associated with
+ * this management context.
+ */
+ public final RootCfgClient getRootConfiguration() {
+ return getRootConfigurationManagedObject().getConfiguration();
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/client/Property.java b/opends/src/server/org/opends/server/admin/client/Property.java
new file mode 100644
index 0000000..b694cb7
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/Property.java
@@ -0,0 +1,137 @@
+/*
+ * 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.admin.client;
+
+
+
+import java.util.SortedSet;
+
+import org.opends.server.admin.PropertyDefinition;
+
+
+
+/**
+ * A managed object property comprising of the property's definition and its set
+ * of values.
+ * <p>
+ * The property stores the values in a sorted set in which values are compared
+ * using the comparator defined by the property definition.
+ * <p>
+ * The property keeps track of whether or not its pending set of values differs
+ * from its active values.
+ *
+ * @param <T>
+ * The type of the property.
+ * @see ManagedObject The <code>ManagedObject</code> documentation describes
+ * the different types of property values in more detail.
+ */
+public interface Property<T> {
+
+ /**
+ * Get an immutable set view of this property's active values.
+ *
+ * @return Returns an immutable set view of this property's active values. An
+ * empty set indicates that there are no active values, and any
+ * default values are applicable.
+ */
+ SortedSet<T> getActiveValues();
+
+
+
+ /**
+ * Get an immutable set view of this property's default values.
+ *
+ * @return Returns an immutable set view of this property's default values. An
+ * empty set indicates that there are no default values.
+ */
+ SortedSet<T> getDefaultValues();
+
+
+
+ /**
+ * Get an immutable set view of this property's effective values.
+ *
+ * @return Returns an immutable set view of this property's effective values.
+ */
+ SortedSet<T> getEffectiveValues();
+
+
+
+ /**
+ * Get an immutable set view of this property's pending values.
+ * <p>
+ * Immediately after construction, the pending values matches the active
+ * values.
+ *
+ * @return Returns an immutable set view of this property's pending values. An
+ * empty set indicates that there are no pending values, and any
+ * default values are applicable.
+ */
+ SortedSet<T> getPendingValues();
+
+
+
+ /**
+ * Get the property definition associated with this property.
+ *
+ * @return Returns the property definition associated with this property.
+ */
+ PropertyDefinition<T> getPropertyDefinition();
+
+
+
+ /**
+ * Determines whether or not this property contains any pending values.
+ *
+ * @return Returns <code>true</code> if this property does not contain any
+ * pending values.
+ */
+ boolean isEmpty();
+
+
+
+ /**
+ * Determines whether or not this property has been modified since it was
+ * constructed. In other words, whether or not the set of pending values
+ * differs from the set of active values.
+ *
+ * @return Returns <code>true</code> if this property has been modified
+ * since it was constructed.
+ */
+ boolean isModified();
+
+
+
+ /**
+ * Determines whether or not this property contains any active values.
+ *
+ * @return Returns <code>true</code> if this property does not contain any
+ * active values.
+ */
+ boolean wasEmpty();
+}
diff --git a/opends/src/server/org/opends/server/admin/client/PropertySet.java b/opends/src/server/org/opends/server/admin/client/PropertySet.java
new file mode 100644
index 0000000..83272d4
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/PropertySet.java
@@ -0,0 +1,791 @@
+/*
+ * 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.admin.client;
+
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.AliasDefaultBehaviorProvider;
+import org.opends.server.admin.DefaultBehaviorPropertyValueException;
+import org.opends.server.admin.DefaultBehaviorProviderVisitor;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.IllegalPropertyValueException;
+import org.opends.server.admin.IllegalPropertyValueStringException;
+import org.opends.server.admin.InheritedDefaultValueException;
+import org.opends.server.admin.InheritedDefaultValueProvider;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OperationsException;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.PropertyIsMandatoryException;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.PropertyIsSingleValuedException;
+import org.opends.server.admin.PropertyOption;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
+import org.opends.server.admin.StringPropertyProvider;
+import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
+
+
+
+/**
+ * A set of properties. Instances of this class can be used as the core of a
+ * managed object implementation.
+ */
+public final class PropertySet implements PropertyProvider {
+
+ /**
+ * Internal property implementation.
+ *
+ * @param <T>
+ * The type of the property.
+ */
+ private static final class MyProperty<T> implements Property<T> {
+
+ // The definition associated with this property.
+ private final PropertyDefinition<T> d;
+
+ // The default set of values (read-only).
+ private final SortedSet<T> defaultValues;
+
+ // The active set of values (read-only).
+ private final SortedSet<T> activeValues;
+
+ // The pending set of values.
+ private final SortedSet<T> pendingValues;
+
+
+
+ /**
+ * Create a property with the provided sets of pre-validated default and
+ * active values.
+ * <p>
+ * This constructor takes ownership of the provided value sets.
+ *
+ * @param d
+ * The property definition.
+ * @param defaultValues
+ * The set of default values for the property.
+ * @param activeValues
+ * The set of active values for the property.
+ */
+ public MyProperty(PropertyDefinition<T> d, SortedSet<T> defaultValues,
+ SortedSet<T> activeValues) {
+ this.d = d;
+ this.defaultValues = Collections.unmodifiableSortedSet(defaultValues);
+ this.activeValues = Collections.unmodifiableSortedSet(activeValues);
+
+ // Initially the pending values is the same as the active values.
+ this.pendingValues = new TreeSet<T>(this.activeValues);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> getActiveValues() {
+ return activeValues;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> getDefaultValues() {
+ return defaultValues;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> getEffectiveValues() {
+ SortedSet<T> values = getPendingValues();
+
+ if (values.isEmpty()) {
+ values = getDefaultValues();
+ }
+
+ return values;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> getPendingValues() {
+ return Collections.unmodifiableSortedSet(pendingValues);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyDefinition<T> getPropertyDefinition() {
+ return d;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return pendingValues.isEmpty();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isModified() {
+ if (activeValues == pendingValues) {
+ return false;
+ } else if (activeValues.size() != pendingValues.size()) {
+ return true;
+ } else if (activeValues.containsAll(pendingValues)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+
+
+ /**
+ * Replace all pending values of this property with the provided values.
+ *
+ * @param c
+ * The new set of pending property values.
+ */
+ public void setPendingValues(Collection<T> c) {
+ pendingValues.clear();
+ pendingValues.addAll(c);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean wasEmpty() {
+ return activeValues.isEmpty();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return getEffectiveValues().toString();
+ }
+ }
+
+
+
+ /**
+ * Internal default behavior visitor implementation.
+ *
+ * @param <T>
+ * The type of the default property values.
+ */
+ private static final class DefaultVisitor<T> implements
+ DefaultBehaviorProviderVisitor<T, SortedSet<T>,
+ Collection<PropertyException>> {
+
+ // The property definition.
+ private final PropertyDefinition<T> pd;
+
+ // Used to retrieve inherited properties.
+ private final InheritedDefaultValueProvider provider;
+
+
+
+ // Private constructor.
+ private DefaultVisitor(PropertyDefinition<T> pd,
+ InheritedDefaultValueProvider provider) {
+ this.pd = pd;
+ this.provider = provider;
+ }
+
+
+
+ // Cast a set of objects to the required type.
+ private Collection<T> castValues(Collection<?> values,
+ Collection<PropertyException> exceptions) {
+ List<T> castValues = new LinkedList<T>();
+ for (Object value : values) {
+ try {
+ castValues.add(pd.castValue(value));
+ } catch (ClassCastException e) {
+ exceptions.add(new IllegalPropertyValueException(pd, value));
+ }
+ }
+ return castValues;
+ }
+
+
+
+ // Build set of default values and validate them.
+ private SortedSet<T> validateStrings(Collection<String> values,
+ Collection<PropertyException> exceptions) {
+ TreeSet<T> defaultValues = new TreeSet<T>(pd);
+ for (String value : values) {
+ try {
+ defaultValues.add(pd.decodeValue(value));
+ } catch (IllegalPropertyValueStringException e) {
+ exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
+ }
+ }
+
+ if (!pd.hasOption(PropertyOption.MULTI_VALUED)) {
+ if (defaultValues.size() > 1) {
+ PropertyException e = new PropertyIsSingleValuedException(pd);
+ exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
+ }
+ }
+
+ return defaultValues;
+ }
+
+
+
+ // Build set of default values and validate them.
+ private SortedSet<T> validate(Collection<T> values,
+ Collection<PropertyException> exceptions) {
+ TreeSet<T> defaultValues = new TreeSet<T>(pd);
+ for (T value : values) {
+ try {
+ pd.validateValue(value);
+ defaultValues.add(value);
+ } catch (IllegalPropertyValueException e) {
+ exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
+ }
+ }
+
+ if (!pd.hasOption(PropertyOption.MULTI_VALUED)) {
+ if (defaultValues.size() > 1) {
+ PropertyException e = new PropertyIsSingleValuedException(pd);
+ exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
+ }
+ }
+
+ return defaultValues;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> visitAbsoluteInherited(
+ AbsoluteInheritedDefaultBehaviorProvider<T> d,
+ Collection<PropertyException> p) {
+ // Get the values from the managed object at the specified path.
+ try {
+ // Get the property values/defaults.
+ ManagedObjectPath path = d.getManagedObjectPath();
+ Collection<?> values = provider.getDefaultPropertyValues(path, d
+ .getPropertyName());
+ return validate(castValues(values, p), p);
+ } catch (OperationsException e) {
+ p.add(new InheritedDefaultValueException(pd, e));
+ return new TreeSet<T>(pd);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> visitAlias(AliasDefaultBehaviorProvider<T> d,
+ Collection<PropertyException> p) {
+ // No values applicable - just return the empty set.
+ return new TreeSet<T>(pd);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> visitDefined(DefinedDefaultBehaviorProvider<T> d,
+ Collection<PropertyException> p) {
+ return validateStrings(d.getDefaultValues(), p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> visitRelativeInherited(
+ RelativeInheritedDefaultBehaviorProvider<T> d,
+ Collection<PropertyException> p) {
+ if (d.getRelativeOffset() == 0) {
+ // TODO: we're inheriting default values from another property in this
+ // property set. Logging is a good use-case: there is a general logging
+ // level for all categories and then category specific levels which can
+ // override. Should the default values be determined dynamically every
+ // time they are accessed? If dynamically, how will decoding errors be
+ // handled? Dynamically: we could return a SortedSet<T> which is lazily
+ // computed.
+ return new TreeSet<T>(pd);
+ } else {
+ // Inheriting default values from a parent managed object.
+ try {
+ ManagedObjectPath base = provider.getManagedObjectPath();
+ ManagedObjectPath path = d.getManagedObjectPath(base);
+ Collection<?> values = provider.getDefaultPropertyValues(path, d
+ .getPropertyName());
+ return validate(castValues(values, p), p);
+ } catch (OperationsException e) {
+ p.add(new InheritedDefaultValueException(pd, e));
+ return new TreeSet<T>(pd);
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public SortedSet<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
+ Collection<PropertyException> p) {
+ // No values applicable - just return the empty set.
+ return new TreeSet<T>(pd);
+ }
+ }
+
+
+
+ /**
+ * Create a new property set using a property provider to supply the active
+ * property values. This constructor takes care of validation of the property
+ * values and retrieval of any default values.
+ * <p>
+ * Any exceptions that occurred whilst processing the properties will be
+ * placed in the provided exception collection. Properties that caused the
+ * exceptions will be created with an empty set of values (note that this
+ * could mean that the resulting property set might contain empty mandatory
+ * properties).
+ *
+ * @param d
+ * The managed object definition.
+ * @param p
+ * The property provider.
+ * @param i
+ * An inherited managed object provider for retrieving inherited
+ * properties.
+ * @param exceptions
+ * A collection in which any property exceptions can be placed.
+ * @return Returns the new property set.
+ */
+ public static PropertySet create(ManagedObjectDefinition<?, ?> d,
+ PropertyProvider p, InheritedDefaultValueProvider i,
+ Collection<PropertyException> exceptions) {
+ Map<PropertyDefinition, MyProperty> properties =
+ new HashMap<PropertyDefinition, MyProperty>();
+
+ // Copy the properties from the provider.
+ for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
+ createProperty(pd, p, i, properties, exceptions);
+ }
+
+ return new PropertySet(properties);
+ }
+
+
+
+ /**
+ * Create a new property set using a string property provider to supply the
+ * active property values. This constructor takes care of validation of the
+ * property values and retrieval of any default values.
+ * <p>
+ * Any exceptions that occurred whilst processing the properties will be
+ * placed in the provided exception collection. Properties that caused the
+ * exceptions will be created with an empty set of values (note that this
+ * could mean that the resulting property set might contain empty mandatory
+ * properties).
+ *
+ * @param d
+ * The managed object definition.
+ * @param p
+ * The string property provider.
+ * @param i
+ * An inherited managed object provider for retrieving inherited
+ * properties.
+ * @param exceptions
+ * A collection in which any property exceptions can be placed.
+ * @return Returns the new property set.
+ */
+ public static PropertySet create(ManagedObjectDefinition<?, ?> d,
+ StringPropertyProvider p, InheritedDefaultValueProvider i,
+ Collection<PropertyException> exceptions) {
+ Map<PropertyDefinition, MyProperty> properties =
+ new HashMap<PropertyDefinition, MyProperty>();
+
+ // Copy the properties from the provider.
+ for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
+ createProperty(pd, p, i, properties, exceptions);
+ }
+
+ return new PropertySet(properties);
+ }
+
+
+
+ // Create new property using string values taken from a property provider.
+ private static <T> void createProperty(PropertyDefinition<T> pd,
+ StringPropertyProvider p, InheritedDefaultValueProvider i,
+ Map<PropertyDefinition, MyProperty> properties,
+ Collection<PropertyException> exceptions) {
+
+ // Get the active values for this property.
+ Collection<String> activeStringValues;
+
+ try {
+ activeStringValues = p.getPropertyValues(pd);
+ } catch (IllegalArgumentException e) {
+ // Default to empty set of values.
+ activeStringValues = Collections.<String> emptySet();
+ }
+
+ SortedSet<T> activeValues = new TreeSet<T>(pd);
+ boolean gotException = false;
+ for (String stringValue : activeStringValues) {
+ try {
+ activeValues.add(pd.decodeValue(stringValue));
+ } catch (IllegalPropertyValueStringException e) {
+ exceptions.add(e);
+ gotException = true;
+ }
+ }
+
+ if (gotException == false) {
+ if (pd.hasOption(PropertyOption.MANDATORY)) {
+ if (activeValues.isEmpty()) {
+ exceptions.add(new PropertyIsMandatoryException(pd));
+ }
+ }
+ }
+
+ createProperty(pd, activeValues, i, properties, exceptions);
+ }
+
+
+
+ // Create new property using values taken from a property provider.
+ private static <T> void createProperty(PropertyDefinition<T> pd,
+ PropertyProvider p, InheritedDefaultValueProvider i,
+ Map<PropertyDefinition, MyProperty> properties,
+ Collection<PropertyException> exceptions) {
+ // Get the active values for this property.
+ Collection<T> activeValues;
+
+ try {
+ activeValues = p.getPropertyValues(pd);
+ } catch (IllegalArgumentException e) {
+ // Default to empty set of values.
+ activeValues = Collections.<T> emptySet();
+ }
+
+ SortedSet<T> validActiveValues = new TreeSet<T>(pd);
+ boolean gotException = false;
+ for (T value : activeValues) {
+ try {
+ pd.validateValue(value);
+ validActiveValues.add(value);
+ } catch (IllegalPropertyValueException e) {
+ exceptions.add(e);
+ gotException = true;
+ }
+ }
+
+ if (gotException == false) {
+ if (pd.hasOption(PropertyOption.MANDATORY)) {
+ if (validActiveValues.isEmpty()) {
+ exceptions.add(new PropertyIsMandatoryException(pd));
+ }
+ }
+ }
+
+ createProperty(pd, validActiveValues, i, properties, exceptions);
+ }
+
+
+
+ // Create new property using the provided validated values.
+ private static <T> void createProperty(PropertyDefinition<T> pd,
+ SortedSet<T> activeValues, InheritedDefaultValueProvider i,
+ Map<PropertyDefinition, MyProperty> properties,
+ Collection<PropertyException> exceptions) {
+ // Do remaining validation of active values.
+ if (!pd.hasOption(PropertyOption.MULTI_VALUED)) {
+ if (activeValues.size() > 1) {
+ exceptions.add(new PropertyIsSingleValuedException(pd));
+ }
+ }
+
+ // Get the default values for this property.
+ DefaultVisitor<T> visitor = new DefaultVisitor<T>(pd, i);
+ SortedSet<T> defaultValues = pd.getDefaultBehaviorProvider().accept(
+ visitor, exceptions);
+
+ // Create the property.
+ properties.put(pd, new MyProperty<T>(pd, defaultValues, activeValues));
+ }
+
+ // The properties.
+ private final Map<PropertyDefinition, MyProperty> properties;
+
+
+
+ // Private constructor.
+ private PropertySet(Map<PropertyDefinition, MyProperty> properties) {
+ this.properties = properties;
+ }
+
+
+
+ /**
+ * Get the property associated with the specified property definition.
+ *
+ * @param <T>
+ * The underlying type of the property.
+ * @param d
+ * The Property definition.
+ * @return Returns the property associated with the specified property
+ * definition.
+ * @throws IllegalArgumentException
+ * If this property provider does not recognise the requested
+ * property definition.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> Property<T> getProperty(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ if (!properties.containsKey(d)) {
+ throw new IllegalArgumentException("Unknown property " + d.getName());
+ }
+
+ return properties.get(d);
+ }
+
+
+
+ /**
+ * Get the effective value of the specified property.
+ * <p>
+ * See the class description for more information about how the effective
+ * property value is derived.
+ *
+ * @param <T>
+ * The type of the property to be retrieved.
+ * @param d
+ * The property to be retrieved.
+ * @return Returns the property's effective value, or <code>null</code> if
+ * there is no effective value defined.
+ * @throws IllegalArgumentException
+ * If the property definition is not associated with this managed
+ * object's definition.
+ */
+ public <T> T getPropertyValue(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ Set<T> values = getPropertyValues(d);
+ if (values.isEmpty()) {
+ return null;
+ } else {
+ return values.iterator().next();
+ }
+ }
+
+
+
+ /**
+ * Get the effective values of the specified property.
+ * <p>
+ * See the class description for more information about how the effective
+ * property values are derived.
+ *
+ * @param <T>
+ * The type of the property to be retrieved.
+ * @param d
+ * The property to be retrieved.
+ * @return Returns the property's effective values, or an empty set if there
+ * are no effective values defined.
+ * @throws IllegalArgumentException
+ * If the property definition is not associated with this managed
+ * object's definition.
+ */
+ public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ Property<T> property = getProperty(d);
+ return new TreeSet<T>(property.getEffectiveValues());
+ }
+
+
+
+ /**
+ * Set a new pending value for the specified property.
+ * <p>
+ * See the class description for more information regarding pending values.
+ *
+ * @param <T>
+ * The type of the property to be modified.
+ * @param d
+ * The property to be modified.
+ * @param value
+ * The new pending value for the property, or <code>null</code> if
+ * the property should be reset to its default behavior.
+ * @throws IllegalPropertyValueException
+ * If the new pending value is deemed to be invalid according to the
+ * property definition.
+ * @throws PropertyIsReadOnlyException
+ * If an attempt was made to modify a read-only property.
+ * @throws PropertyIsMandatoryException
+ * If an attempt was made to remove a mandatory property.
+ * @throws IllegalArgumentException
+ * If the specified property definition is not associated with this
+ * managed object, or if the property is read-only.
+ */
+ public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
+ throws IllegalPropertyValueException, PropertyIsReadOnlyException,
+ PropertyIsMandatoryException, IllegalArgumentException {
+ if (value == null) {
+ setPropertyValues(d, Collections.<T> emptySet());
+ } else {
+ setPropertyValues(d, Collections.singleton(value));
+ }
+ }
+
+
+
+ /**
+ * Set a new pending values for the specified property.
+ * <p>
+ * See the class description for more information regarding pending values.
+ *
+ * @param <T>
+ * The type of the property to be modified.
+ * @param d
+ * The property to be modified.
+ * @param values
+ * A non-<code>null</code> set of new pending values for the
+ * property (an empty set indicates that the property should be reset
+ * to its default behavior). The set will not be referenced by this
+ * managed object.
+ * @throws IllegalPropertyValueException
+ * If a new pending value is deemed to be invalid according to the
+ * property definition.
+ * @throws PropertyIsSingleValuedException
+ * If an attempt was made to add multiple pending values to a
+ * single-valued property.
+ * @throws PropertyIsReadOnlyException
+ * If an attempt was made to modify a read-only property.
+ * @throws PropertyIsMandatoryException
+ * If an attempt was made to remove a mandatory property.
+ * @throws IllegalArgumentException
+ * If the specified property definition is not associated with this
+ * managed object, or if the property is read-only.
+ */
+ public <T> void setPropertyValues(PropertyDefinition<T> d,
+ Collection<T> values) throws IllegalPropertyValueException,
+ PropertyIsSingleValuedException, PropertyIsReadOnlyException,
+ PropertyIsMandatoryException, IllegalArgumentException {
+ MyProperty<T> property = (MyProperty<T>) getProperty(d);
+
+ if (d.hasOption(PropertyOption.READ_ONLY)) {
+ throw new PropertyIsReadOnlyException(d);
+ }
+
+ if (!d.hasOption(PropertyOption.MULTI_VALUED)) {
+ if (values.size() > 1) {
+ throw new PropertyIsSingleValuedException(d);
+ }
+ }
+
+ if (d.hasOption(PropertyOption.MANDATORY)) {
+ if (values.isEmpty()) {
+ throw new PropertyIsMandatoryException(d);
+ }
+ }
+
+ // Validate each value.
+ for (T e : values) {
+ if (e == null) {
+ throw new NullPointerException();
+ }
+
+ d.validateValue(e);
+ }
+
+ // Update the property.
+ property.setPendingValues(values);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append('{');
+ for (Map.Entry<PropertyDefinition, MyProperty> entry : properties
+ .entrySet()) {
+ builder.append(entry.getKey().getName());
+ builder.append('=');
+ builder.append(entry.getValue().toString());
+ builder.append(' ');
+ }
+ builder.append('}');
+ return builder.toString();
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPChangeBuilder.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPChangeBuilder.java
new file mode 100644
index 0000000..60f41d1
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPChangeBuilder.java
@@ -0,0 +1,183 @@
+/*
+ * 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.admin.client.ldap;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.naming.NamingException;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.ldap.LdapName;
+
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OperationsException;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.client.Property;
+
+
+
+/**
+ * An LDAP managed object change builder.
+ */
+final class LDAPChangeBuilder {
+
+ // The internal representation of the modified list.
+ private final List<ModificationItem> modList;
+
+ // The internal JNDI Dir context.
+ private final DirContext ctx;
+
+ // The managed object path.
+ private final ManagedObjectPath path;
+
+ // The managed object definition.
+ private final ManagedObjectDefinition<?, ?> definition;
+
+ // The LDAP profile to use for attribute name resolution.
+ private final LDAPProfile profile;
+
+
+
+ /**
+ * Create a new LDAP based change builder.
+ *
+ * @param ctx
+ * The LDAP connection context.
+ * @param path
+ * The managed object path.
+ * @param definition
+ * The managed object definition.
+ */
+ public LDAPChangeBuilder(DirContext ctx, ManagedObjectPath path,
+ ManagedObjectDefinition<?, ?> definition) {
+ this.modList = new LinkedList<ModificationItem>();
+ this.ctx = ctx;
+ this.path = path;
+ this.definition = definition;
+ this.profile = LDAPProfile.getInstance();
+ }
+
+
+
+ /**
+ * Update this builder with the set of changes which have been made to the
+ * provided property.
+ *
+ * @param <T>
+ * The underlying type of the property.
+ * @param property
+ * The property.
+ */
+ public <T> void addChange(Property<T> property) {
+ PropertyDefinition<T> d = property.getPropertyDefinition();
+ if (property.wasEmpty()) {
+ // Property has been added.
+ addPropertyValues(d, property.getPendingValues());
+ } else if (property.isEmpty()) {
+ // Property has been deleted.
+ deletePropertyValues(d, property.getActiveValues());
+ } else {
+ // Property has been modified.
+ modifyPropertyValues(d, property.getActiveValues(), property
+ .getPendingValues());
+ }
+ }
+
+
+
+ // A property has been added.
+ private <T> void addPropertyValues(
+ PropertyDefinition<T> d, Set<T> newValues) {
+ String attrID = profile.getAttributeName(definition, d);
+ BasicAttribute att = new BasicAttribute(attrID);
+ for (T value : newValues) {
+ att.add(d.encodeValue(value));
+ }
+ ModificationItem mod = new ModificationItem(DirContext.ADD_ATTRIBUTE, att);
+ modList.add(mod);
+ }
+
+
+
+ // Property has been modified.
+ private <T> void modifyPropertyValues(PropertyDefinition<T> d,
+ Set<T> oldValues, Set<T> newValues) {
+ // FIXME: be more sensible here. Only remove the values that need removing,
+ // and only add the values that need adding.
+ String attrID = profile.getAttributeName(definition, d);
+ BasicAttribute att = new BasicAttribute(attrID);
+ for (T value : newValues) {
+ att.add(d.encodeValue(value));
+ }
+ ModificationItem mod = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
+ att);
+ modList.add(mod);
+ }
+
+
+
+ // Property has been deleted.
+ private <T> void deletePropertyValues(PropertyDefinition<T> d,
+ Set<T> oldValues) {
+ String attrID = profile.getAttributeName(definition, d);
+ BasicAttribute att = new BasicAttribute(attrID);
+ ModificationItem mod = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
+ att);
+ modList.add(mod);
+ }
+
+
+
+ /**
+ * Commit the changes.
+ *
+ * @throws OperationsException
+ * If the changes to this managed object could not be committed due
+ * to some underlying communication problem.
+ */
+ public void commit() throws OperationsException {
+ ModificationItem[] mods = modList.toArray(new ModificationItem[modList
+ .size()]);
+ try {
+ LdapName dn = LDAPNameBuilder.create(path);
+ ctx.modifyAttributes(dn, mods);
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ throw oef.createException(e);
+ }
+ return;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
new file mode 100644
index 0000000..8f8a8a3
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -0,0 +1,807 @@
+/*
+ * 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.admin.client.ldap;
+
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.ConfigurationClient;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.DefinitionResolver;
+import org.opends.server.admin.IllegalPropertyValueException;
+import org.opends.server.admin.InheritedDefaultValueProvider;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OperationsException;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.PropertyIsMandatoryException;
+import org.opends.server.admin.PropertyIsReadOnlyException;
+import org.opends.server.admin.PropertyIsSingleValuedException;
+import org.opends.server.admin.PropertyNotFoundException;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.admin.StringPropertyProvider;
+import org.opends.server.admin.DefinitionDecodingException.Reason;
+import org.opends.server.admin.client.ManagedObject;
+import org.opends.server.admin.client.ManagedObjectDecodingException;
+import org.opends.server.admin.client.Property;
+import org.opends.server.admin.client.PropertySet;
+import org.opends.server.admin.std.client.RootCfgClient;
+import org.opends.server.admin.std.meta.RootCfgDefn;
+
+
+
+/**
+ * A managed object bound to an LDAP connection.
+ *
+ * @param <C>
+ * The type of client configuration represented by the client
+ * managed object.
+ */
+final class LDAPManagedObject<C extends ConfigurationClient>
+ implements ManagedObject<C> {
+
+ /**
+ * Internal inherited default value provider implementation.
+ */
+ private static class MyInheritedDefaultValueProvider implements
+ InheritedDefaultValueProvider {
+
+ // The base path.
+ private final ManagedObjectPath path;
+
+ // The LDAP connection context.
+ private final DirContext dirContext;
+
+
+
+ /**
+ * Create a new inherited default value provider.
+ *
+ * @param dirContext
+ * The LDAP connection context.
+ * @param path
+ * The base path.
+ */
+ public MyInheritedDefaultValueProvider(DirContext dirContext,
+ ManagedObjectPath path) {
+ this.dirContext = dirContext;
+ this.path = path;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<?> getDefaultPropertyValues(
+ ManagedObjectPath path, String propertyName)
+ throws OperationsException, PropertyNotFoundException {
+ ManagedObject<?> mo = readEntry(dirContext, path, path
+ .getManagedObjectDefinition());
+ ManagedObjectDefinition<?, ?> mod = mo
+ .getManagedObjectDefinition();
+
+ try {
+ PropertyDefinition<?> dpd = mod
+ .getPropertyDefinition(propertyName);
+ return mo.getPropertyValues(dpd);
+ } catch (IllegalArgumentException e) {
+ throw new PropertyNotFoundException(propertyName);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedObjectPath getManagedObjectPath() {
+ return path;
+ }
+ }
+
+
+
+ /**
+ * Construct a root LDAP managed object associated with the provided
+ * LDAP context.
+ *
+ * @param dirContext
+ * The LDAP directory context.
+ * @return Returns a root LDAP managed object associated with the
+ * provided LDAP context.
+ */
+ static ManagedObject<RootCfgClient> getRootManagedObject(
+ DirContext dirContext) {
+ List<PropertyException> exceptions = new LinkedList<PropertyException>();
+ InheritedDefaultValueProvider i = new MyInheritedDefaultValueProvider(
+ dirContext, ManagedObjectPath.emptyPath());
+ PropertySet properties = PropertySet.create(RootCfgDefn
+ .getInstance(), PropertyProvider.DEFAULT_PROVIDER, i,
+ exceptions);
+
+ // Should never get any exceptions.
+ if (!exceptions.isEmpty()) {
+ throw new RuntimeException(
+ "Got exceptions when creating root managed object");
+ }
+
+ return new LDAPManagedObject<RootCfgClient>(dirContext,
+ RootCfgDefn.getInstance(), ManagedObjectPath.emptyPath(),
+ properties);
+ }
+
+
+
+ // Create a new child LDAP managed object.
+ private static <M extends ConfigurationClient>
+ ManagedObject<M> createLDAPManagedObject(
+ DirContext dirContext, ManagedObjectDefinition<M, ?> d,
+ ManagedObjectPath p, PropertySet properties) {
+ return new LDAPManagedObject<M>(dirContext, d, p, properties);
+ }
+
+
+
+ // Get an array containing the list of LDAP attributes names
+ // associated with a
+ // managed object definition.
+ private static String[] getAttributeNames(
+ ManagedObjectDefinition<?, ?> d) {
+ ArrayList<String> attrIds = new ArrayList<String>();
+
+ for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
+ String attrId = LDAPProfile.getInstance().getAttributeName(d,
+ pd);
+ attrIds.add(attrId);
+ }
+
+ return attrIds.toArray(new String[attrIds.size()]);
+ }
+
+
+
+ // Determine the type of managed object associated with the named
+ // entry.
+ private static <M extends ConfigurationClient>
+ ManagedObjectDefinition<? extends M, ?> getEntryDefinition(
+ DirContext dirContext, AbstractManagedObjectDefinition<M, ?> d,
+ LdapName dn) throws OperationsException {
+ try {
+ String[] attrIds = new String[] { "objectclass" };
+ Attributes attributes = dirContext.getAttributes(dn, attrIds);
+ Attribute oc = attributes.get("objectclass");
+
+ if (oc == null) {
+ // No object classes.
+ throw new DefinitionDecodingException(
+ Reason.NO_TYPE_INFORMATION);
+ }
+
+ final Set<String> objectClasses = new HashSet<String>();
+ NamingEnumeration<?> values = oc.getAll();
+ while (values.hasMore()) {
+ Object value = values.next();
+ if (value != null) {
+ objectClasses.add(value.toString().toLowerCase().trim());
+ }
+ }
+
+ if (objectClasses.isEmpty()) {
+ // No object classes.
+ throw new DefinitionDecodingException(
+ Reason.NO_TYPE_INFORMATION);
+ }
+
+ // Resolve the appropriate sub-type based on the object classes.
+ DefinitionResolver resolver = new DefinitionResolver() {
+
+ public boolean matches(AbstractManagedObjectDefinition<?, ?> d) {
+ String objectClass = LDAPProfile.getInstance()
+ .getObjectClass(d);
+ return objectClasses.contains(objectClass);
+ }
+
+ };
+
+ return d.resolveManagedObjectDefinition(resolver);
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ throw oef.createException(e);
+ }
+ }
+
+
+
+ // Read the entry identified by the path and which is a sub-type of
+ // the
+ // specified definition.
+ private static <M extends ConfigurationClient>
+ ManagedObject<? extends M> readEntry(
+ DirContext dirContext, ManagedObjectPath p,
+ AbstractManagedObjectDefinition<M, ?> d)
+ throws OperationsException {
+ LdapName dn = LDAPNameBuilder.create(p);
+ final ManagedObjectDefinition<? extends M, ?> mod = getEntryDefinition(
+ dirContext, d, dn);
+ String[] attrIds = getAttributeNames(mod);
+
+ final Attributes attributes;
+ try {
+ attributes = dirContext.getAttributes(dn, attrIds);
+ } catch (NamingException e) {
+ OperationsExceptionFactory factory = new OperationsExceptionFactory();
+ throw factory.createException(e);
+ }
+
+ // Create a provider which uses LDAP string representations.
+
+ // TODO: the exception handling is a bit of a hack here.
+ final List<OperationsException> oelist =
+ new LinkedList<OperationsException>();
+ StringPropertyProvider provider = new StringPropertyProvider() {
+
+ public Collection<String> getPropertyValues(
+ PropertyDefinition<?> d) throws IllegalArgumentException {
+ String attrID = LDAPProfile.getInstance().getAttributeName(
+ mod, d);
+ Attribute attribute = attributes.get(attrID);
+ List<String> values = new LinkedList<String>();
+
+ if (attribute != null && attribute.size() != 0) {
+ try {
+ NamingEnumeration<?> ldapValues = attribute.getAll();
+ while (ldapValues.hasMore()) {
+ Object obj = ldapValues.next();
+ if (obj != null) {
+ values.add(obj.toString());
+ }
+ }
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ oelist.add(oef.createException(e));
+ }
+ }
+
+ return values;
+ }
+
+ };
+
+ // There can only be at most one operations exception.
+ if (!oelist.isEmpty()) {
+ throw oelist.get(0);
+ }
+
+ // Now decode the properties using the provider.
+ List<PropertyException> exceptions = new LinkedList<PropertyException>();
+ InheritedDefaultValueProvider i = new MyInheritedDefaultValueProvider(
+ dirContext, p);
+ PropertySet properties = PropertySet.create(mod, provider, i,
+ exceptions);
+ ManagedObject<? extends M> mo = createLDAPManagedObject(
+ dirContext, mod, p, properties);
+
+ // If there were no decoding problems then return the object,
+ // otherwise
+ // throw an operations exception.
+ if (exceptions.isEmpty()) {
+ return mo;
+ } else {
+ throw new ManagedObjectDecodingException(mo, exceptions);
+ }
+ }
+
+ // The JNDI context used for the ldap connection.
+ private final DirContext dirContext;
+
+ // The path associated with this managed object.
+ private final ManagedObjectPath path;
+
+ // LDAP profile associated with this connection.
+ private final LDAPProfile profile;
+
+ // The managed object definition associated with this managed
+ // object.
+ private final ManagedObjectDefinition<C, ?> definition;
+
+ // The managed object's properties.
+ private final PropertySet properties;
+
+
+
+ // Create an new LDAP managed object with the provided JNDI context.
+ private LDAPManagedObject(DirContext dirContext,
+ ManagedObjectDefinition<C, ?> d, ManagedObjectPath path,
+ PropertySet properties) {
+ this.definition = d;
+ this.dirContext = dirContext;
+ this.path = path;
+ this.profile = LDAPProfile.getInstance();
+ this.properties = properties;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void commit() throws OperationsException {
+ ManagedObjectDefinition<C, ?> d = getManagedObjectDefinition();
+ LDAPChangeBuilder builder = new LDAPChangeBuilder(dirContext,
+ path, d);
+ for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
+ // FIXME: should throw an error when there are missing mandatory
+ // properties.
+ Property<?> p = properties.getProperty(pd);
+ if (p.isModified()) {
+ builder.addChange(p);
+ }
+ }
+ builder.commit();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <M extends ConfigurationClient, N extends M>
+ ManagedObject<N> createChild(
+ InstantiableRelationDefinition<M, ?> r,
+ ManagedObjectDefinition<N, ?> d, String name, PropertyProvider p)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(r);
+
+ ManagedObjectPath childPath = path.child(r, name);
+
+ // First make sure all the properties are valid.
+ List<PropertyException> exceptions = new LinkedList<PropertyException>();
+ InheritedDefaultValueProvider i = new MyInheritedDefaultValueProvider(
+ dirContext, childPath);
+ PropertySet properties = PropertySet.create(d, p, i, exceptions);
+ if (!exceptions.isEmpty()) {
+ ManagedObject<N> mo = new LDAPManagedObject<N>(dirContext, d,
+ childPath, properties);
+ throw new ManagedObjectDecodingException(mo, exceptions);
+ }
+
+ try {
+ // TODO: this implementation does not handle relations which
+ // comprise of more than one RDN arc (this will probably never
+ // be required anyway).
+ LdapName dn = LDAPNameBuilder.create(path, r);
+
+ if (!entryExists(dn)) {
+ // Need to create the child managed object's parent entry i.e.
+ // the entry representing the relation itself.
+ Attributes attributes = new BasicAttributes();
+
+ // Create the branch's object class attribute.
+ Attribute oc = new BasicAttribute("objectClass");
+ for (String objectClass : profile
+ .getInstantiableRelationObjectClasses(r)) {
+ oc.add(objectClass);
+ }
+ attributes.put(oc);
+
+ // Create the branch's naming attribute.
+ Rdn rdn = dn.getRdn(dn.size() - 1);
+ attributes.put(rdn.getType(), rdn.getValue().toString());
+
+ // Create the entry.
+ dirContext.createSubcontext(dn, attributes);
+ }
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ throw oef.createException(e);
+ }
+
+ return createManagedObject(childPath, d, properties);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <M extends ConfigurationClient, N extends M>
+ ManagedObject<N> createChild(
+ OptionalRelationDefinition<M, ?> r,
+ ManagedObjectDefinition<N, ?> d, PropertyProvider p)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(r);
+
+ ManagedObjectPath childPath = path.child(r);
+
+ // First make sure all the properties are valid.
+ List<PropertyException> exceptions = new LinkedList<PropertyException>();
+ InheritedDefaultValueProvider i = new MyInheritedDefaultValueProvider(
+ dirContext, childPath);
+ PropertySet properties = PropertySet.create(d, p, i, exceptions);
+ if (!exceptions.isEmpty()) {
+ ManagedObject<N> mo = new LDAPManagedObject<N>(dirContext, d,
+ childPath, properties);
+ throw new ManagedObjectDecodingException(mo, exceptions);
+ }
+
+ return createManagedObject(childPath, d, properties);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ InstantiableRelationDefinition<M, ?> d, String name)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(d);
+ return readEntry(dirContext, path.child(d, name), d
+ .getChildDefinition());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ OptionalRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(d);
+ return readEntry(dirContext, path.child(d), d
+ .getChildDefinition());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <M extends ConfigurationClient> ManagedObject<? extends M> getChild(
+ SingletonRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(d);
+ return readEntry(dirContext, path.child(d), d
+ .getChildDefinition());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public C getConfiguration() {
+ return definition.createClientConfiguration(this);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedObjectDefinition<C, ?> getManagedObjectDefinition() {
+ return definition;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedObjectPath getManagedObjectPath() {
+ return path;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> T getPropertyValue(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ return properties.getPropertyValue(d);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ return properties.getPropertyValues(d);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasChild(OptionalRelationDefinition<?, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(d);
+
+ ManagedObjectPath p = path.child(d);
+ LdapName dn = LDAPNameBuilder.create(p);
+ try {
+ return entryExists(dn);
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ throw oef.createException(e);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] listChildren(InstantiableRelationDefinition<?, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(d);
+
+ LdapName dn = LDAPNameBuilder.create(path, d);
+
+ String filter = profile.getFilter(d.getChildDefinition());
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+
+ try {
+ NamingEnumeration<SearchResult> results;
+ results = dirContext.search(dn, filter, controls);
+
+ String rtype = profile.getInstantiableRelationChildRDNType(d);
+ List<String> names = new ArrayList<String>();
+ while (results.hasMore()) {
+ SearchResult sr = results.next();
+ Attributes attributes = sr.getAttributes();
+ Attribute cn = attributes.get(rtype);
+ if (cn != null && cn.get() != null) {
+ names.add(cn.get().toString());
+ }
+ }
+
+ return names.toArray(new String[names.size()]);
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ throw oef.createException(e);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <M extends ConfigurationClient> void removeChild(
+ InstantiableRelationDefinition<M, ?> d, String name)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(d);
+
+ ManagedObjectPath p = path.child(d, name);
+ removeManagedObject(p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <M extends ConfigurationClient> void removeChild(
+ OptionalRelationDefinition<M, ?> d)
+ throws IllegalArgumentException, OperationsException {
+ validateRelationDefinition(d);
+
+ ManagedObjectPath p = path.child(d);
+ removeManagedObject(p);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
+ throws IllegalPropertyValueException,
+ PropertyIsReadOnlyException, PropertyIsMandatoryException,
+ IllegalArgumentException {
+ properties.setPropertyValue(d, value);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public <T> void setPropertyValues(PropertyDefinition<T> d,
+ Collection<T> values) throws IllegalPropertyValueException,
+ PropertyIsSingleValuedException, PropertyIsReadOnlyException,
+ PropertyIsMandatoryException, IllegalArgumentException {
+ properties.setPropertyValues(d, values);
+ }
+
+
+
+ // Creates a new managed object. The parent LDAP entry is assumed to
+ // already exist.
+ private <N extends ConfigurationClient> ManagedObject<N> createManagedObject(
+ ManagedObjectPath path, ManagedObjectDefinition<N, ?> d,
+ PropertySet properties) throws OperationsException {
+ LdapName dn = LDAPNameBuilder.create(path);
+ Attributes attributes = new BasicAttributes();
+
+ // Create the child's object class attribute.
+ Attribute oc = new BasicAttribute("objectClass");
+ for (String objectClass : profile.getObjectClasses(d)) {
+ oc.add(objectClass);
+ }
+ attributes.put(oc);
+
+ // Create the child's naming attribute.
+ Rdn rdn = dn.getRdn(dn.size() - 1);
+ attributes.put(rdn.getType(), rdn.getValue().toString());
+
+ // Create the remaining attributes.
+ for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
+ String attrID = profile.getAttributeName(d, pd);
+ Attribute attribute = new BasicAttribute(attrID);
+ encodeProperty(attribute, pd, properties);
+ if (attribute.size() != 0) {
+ attributes.put(attribute);
+ }
+ }
+
+ try {
+ // Create the entry.
+ dirContext.createSubcontext(dn, attributes);
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ throw oef.createException(e);
+ }
+
+ return new LDAPManagedObject<N>(dirContext, d, path, properties);
+ }
+
+
+
+ // Recursively delete a subtree of entries.
+ private void destroySubtree(LdapName dn) throws NamingException {
+ // List the child entries.
+ String filter = "(objectClass=*)";
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+
+ NamingEnumeration<SearchResult> results;
+ results = dirContext.search(dn, filter, controls);
+
+ // Recursively delete child entries.
+ while (results.hasMore()) {
+ SearchResult sr = results.next();
+ LdapName child = new LdapName(dn.getRdns());
+ child.add(new Rdn(sr.getName()));
+ destroySubtree(child);
+ }
+
+ // Delete the specified entry.
+ dirContext.destroySubcontext(dn);
+ }
+
+
+
+ // Encode a property into LDAP string values.
+ private <T> void encodeProperty(Attribute attribute,
+ PropertyDefinition<T> pd, PropertySet properties) {
+ for (T value : properties.getPropertyValues(pd)) {
+ attribute.add(pd.encodeValue(value));
+ }
+ }
+
+
+
+ // Determine whether the named entry exists or not.
+ private boolean entryExists(LdapName dn) throws NamingException {
+ String filter = "(objectClass=*)";
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope(SearchControls.OBJECT_SCOPE);
+
+ try {
+ NamingEnumeration<SearchResult> results = dirContext.search(dn,
+ filter, controls);
+ if (results.hasMore()) {
+ // TODO: should really verify that the relation entry has
+ // the correct object classes, etc. It definitely has the
+ // correct name, which is ok.
+ return true;
+ }
+ } catch (NameNotFoundException e) {
+ // Fall through - parent not found.
+ }
+
+ return false;
+ }
+
+
+
+ // Remove the named managed object.
+ private void removeManagedObject(ManagedObjectPath p)
+ throws OperationsException {
+ try {
+ LdapName dn = LDAPNameBuilder.create(p);
+ if (entryExists(dn)) {
+ // Delete the entry and any subordinate entries.
+ destroySubtree(dn);
+ }
+ } catch (NamingException e) {
+ OperationsExceptionFactory oef = new OperationsExceptionFactory();
+ throw oef.createException(e);
+ }
+ }
+
+
+
+ // Validate that a relation definition belongs to this managed
+ // object.
+ private void validateRelationDefinition(RelationDefinition<?, ?> rd)
+ throws IllegalArgumentException {
+ ManagedObjectDefinition d = getManagedObjectDefinition();
+ RelationDefinition tmp = d.getRelationDefinition(rd.getName());
+ if (tmp != rd) {
+ throw new IllegalArgumentException("The relation "
+ + rd.getName() + " is not associated with a " + d.getName());
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagementContext.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagementContext.java
new file mode 100644
index 0000000..37bc258
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagementContext.java
@@ -0,0 +1,101 @@
+/*
+ * 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.admin.client.ldap;
+
+
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.ldap.InitialLdapContext;
+
+import org.opends.server.admin.client.ManagedObject;
+import org.opends.server.admin.client.ManagementContext;
+import org.opends.server.admin.std.client.RootCfgClient;
+
+
+
+/**
+ * An LDAP management connection context.
+ */
+public final class LDAPManagementContext extends ManagementContext {
+
+ // The JNDI context used for the ldap connection.
+ private final DirContext dirContext;
+
+
+
+ /**
+ * Create a new LDAP management context using simple authentication.
+ * <p>
+ * TODO: we will want to support more secure forms of
+ * authentication.
+ *
+ * @param host
+ * The host.
+ * @param port
+ * The port.
+ * @param name
+ * The LDAP bind DN.
+ * @param password
+ * The LDAP bind password.
+ * @return Returns the new management context.
+ * @throws NamingException
+ * If the LDAP connection could not be established.
+ */
+ public static ManagementContext createLDAPContext(String host,
+ int port, String name, String password) throws NamingException {
+ Hashtable<String, Object> env = new Hashtable<String, Object>();
+ env.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ env.put(Context.PROVIDER_URL, "ldap://" + host + ":" + port);
+ env.put(Context.SECURITY_PRINCIPAL, name);
+ env.put(Context.SECURITY_CREDENTIALS, password);
+
+ DirContext ctx = new InitialLdapContext(env, null);
+ return new LDAPManagementContext(ctx);
+ }
+
+
+
+ // Private constructor.
+ private LDAPManagementContext(DirContext dirContext) {
+ this.dirContext = dirContext;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedObject<RootCfgClient> getRootConfigurationManagedObject() {
+ return LDAPManagedObject.getRootManagedObject(dirContext);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/LDAPNameBuilder.java b/opends/src/server/org/opends/server/admin/client/ldap/LDAPNameBuilder.java
new file mode 100644
index 0000000..53c2f80
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ldap/LDAPNameBuilder.java
@@ -0,0 +1,177 @@
+/*
+ * 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.admin.client.ldap;
+
+
+
+import java.util.LinkedList;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.ManagedObjectPathSerializer;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+
+
+
+/**
+ * A strategy for creating <code>LdapName</code>s from managed object paths.
+ */
+final class LDAPNameBuilder implements ManagedObjectPathSerializer {
+
+ /**
+ * Creates a new LDAP name representing the specified managed object path.
+ *
+ * @param path
+ * The managed object path.
+ * @return Returns a new LDAP name representing the specified managed object
+ * path.
+ */
+ public static LdapName create(ManagedObjectPath path) {
+ LDAPNameBuilder builder = new LDAPNameBuilder();
+ path.serialize(builder);
+ return builder.getInstance();
+ }
+
+
+
+ /**
+ * Creates a new LDAP name representing the specified managed object path and
+ * instantiable relation.
+ *
+ * @param path
+ * The managed object path.
+ * @param relation
+ * The child instantiable relation.
+ * @return Returns a new LDAP name representing the specified managed object
+ * path and instantiable relation.
+ */
+ public static LdapName create(ManagedObjectPath path,
+ InstantiableRelationDefinition<?, ?> relation) {
+ LDAPNameBuilder builder = new LDAPNameBuilder();
+ path.serialize(builder);
+ builder.appendManagedObjectPathElement(relation);
+ return builder.getInstance();
+ }
+
+ // The list of RDNs in big-endian order.
+ private final LinkedList<Rdn> rdns;
+
+ // The LDAP profile.
+ private final LDAPProfile profile;
+
+
+
+ /**
+ * Create a new JNDI LDAP name builder.
+ */
+ public LDAPNameBuilder() {
+ this.rdns = new LinkedList<Rdn>();
+ this.profile = LDAPProfile.getInstance();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void appendManagedObjectPathElement(
+ InstantiableRelationDefinition<?, ?> r, String name) {
+ // Add the RDN sequence representing the relation.
+ appendManagedObjectPathElement((RelationDefinition) r);
+
+ // Now add the single RDN representing the named instance.
+ String type = profile.getInstantiableRelationChildRDNType(r);
+ try {
+ Rdn rdn = new Rdn(type, name.trim());
+ rdns.add(rdn);
+ } catch (InvalidNameException e1) {
+ // Should not happen.
+ throw new RuntimeException(e1);
+ }
+ }
+
+
+
+ /**
+ * Appends the RDN sequence representing the provided relation.
+ *
+ * @param r
+ * The relation definition.
+ */
+ public void appendManagedObjectPathElement(RelationDefinition<?, ?> r) {
+ // Add the RDN sequence representing the relation.
+ try {
+ LdapName tmp = new LdapName(profile.getRelationRDNSequence(r));
+ rdns.addAll(tmp.getRdns());
+ } catch (InvalidNameException e1) {
+ // Should not happen.
+ throw new RuntimeException(e1);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void appendManagedObjectPathElement(
+ OptionalRelationDefinition<?, ?> r) {
+ // Add the RDN sequence representing the relation.
+ appendManagedObjectPathElement((RelationDefinition) r);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void appendManagedObjectPathElement(
+ SingletonRelationDefinition<?, ?> r) {
+ // Add the RDN sequence representing the relation.
+ appendManagedObjectPathElement((RelationDefinition) r);
+ }
+
+
+
+ /**
+ * Create a new JNDI LDAP name using the current state of this LDAP name
+ * builder.
+ *
+ * @return Returns the new JNDI LDAP name instance.
+ */
+ public LdapName getInstance() {
+ return new LdapName(rdns);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/OperationsExceptionFactory.java b/opends/src/server/org/opends/server/admin/client/ldap/OperationsExceptionFactory.java
new file mode 100644
index 0000000..f0c74f1
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ldap/OperationsExceptionFactory.java
@@ -0,0 +1,72 @@
+/*
+ * 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.admin.client.ldap;
+
+
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.OperationsException;
+
+
+
+/**
+ * A factory for creating <code>OperationsExceptions</code> from
+ * <code>NamingExceptions</code>.
+ */
+final class OperationsExceptionFactory {
+
+ /**
+ * Creates a new operations exception factory.
+ */
+ public OperationsExceptionFactory() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Creates a new operations exception whose exact type depends upon the
+ * provided naming exception.
+ *
+ * @param e
+ * The naming exception.
+ * @return Returns a new operations exception whose exact type depends upon
+ * the provided naming exception.
+ */
+ public OperationsException createException(NamingException e) {
+ if (e instanceof NameNotFoundException) {
+ return new ManagedObjectNotFoundException(e);
+ } else {
+ // FIXME: resolve other naming exceptions.
+ return new OperationsException(e);
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/client/ldap/package-info.java b/opends/src/server/org/opends/server/admin/client/ldap/package-info.java
new file mode 100644
index 0000000..2ed977e
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/ldap/package-info.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/**
+ * LDAP configuration transport implementation.
+ * <p>
+ * This implementation uses JNDI for all communication. It is expected
+ * that, at some point in the future, we will replace this implementation
+ * with our own LDAP client SDK based implementation.
+ */
+package org.opends.server.admin.client.ldap;
diff --git a/opends/src/server/org/opends/server/admin/client/package-info.java b/opends/src/server/org/opends/server/admin/client/package-info.java
new file mode 100644
index 0000000..1379ac3
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/client/package-info.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+/**
+ * Common client-side administration classes.
+ * <p>
+ * This package contains classes which client applications and client-side
+ * driver implementations are expected to use.
+ * <p>
+ * In addition, there are also two example client
+ * applications, <code>ExampleClient</code> and
+ * <code>ExampleIntrospection</code>.
+ */
+package org.opends.server.admin.client;
+
+
+
diff --git a/opends/src/server/org/opends/server/admin/package-info.java b/opends/src/server/org/opends/server/admin/package-info.java
new file mode 100644
index 0000000..16bf903
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/package-info.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/**
+ * Common administration classes.
+ * <p>
+ * This package contains administration related classes and interfaces
+ * common to both the client and server.
+ */
+package org.opends.server.admin;
+
diff --git a/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
new file mode 100644
index 0000000..8d53775
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java
@@ -0,0 +1,87 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.List;
+
+import org.opends.server.admin.DecodingException;
+
+
+
+/**
+ * Common features of config listener adaptors.
+ */
+abstract class AbstractConfigListenerAdaptor {
+
+ /**
+ * Create a new config listener adaptor.
+ */
+ protected AbstractConfigListenerAdaptor() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Convert a decoding exception to an unacceptable reason.
+ *
+ * @param e
+ * The decoding exception.
+ * @param unacceptableReason
+ * The builder to which messages should be appended.
+ */
+ protected final void generateUnacceptableReason(
+ DecodingException e, StringBuilder unacceptableReason) {
+ // FIXME: generate a property OpenDS style message.
+ unacceptableReason.append(e.getLocalizedMessage());
+ }
+
+
+
+ /**
+ * Concatenate a list of messages into a single message.
+ *
+ * @param reasons
+ * The list of messages to concatenate.
+ * @param unacceptableReason
+ * The single message to which messages should be appended.
+ */
+ protected final void generateUnacceptableReason(
+ List<String> reasons, StringBuilder unacceptableReason) {
+ boolean isFirst = true;
+ for (String reason : reasons) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ unacceptableReason.append(" ");
+ }
+ unacceptableReason.append(reason);
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/AbstractOptionalConfigurationManager.java b/opends/src/server/org/opends/server/admin/server/AbstractOptionalConfigurationManager.java
new file mode 100644
index 0000000..6e9bcea
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/AbstractOptionalConfigurationManager.java
@@ -0,0 +1,724 @@
+/*
+ * 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.admin.server;
+
+
+
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.Configuration;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.messages.AdminMessages;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.InitializationException;
+import org.opends.server.types.ResultCode;
+
+
+
+/**
+ * A skeleton implementation of a configuration manager. This type of
+ * manager can be used for managing "optional" configurations (i.e.
+ * where there is a one to zero or one relationship).
+ * <p>
+ * Configuration managers are responsible for initializing and
+ * finalizing instances as required. During initialization, the
+ * manager takes responsibility for loading and instantiating the
+ * implementation class. It then initializes the implementation
+ * instance by invoking a method having the following signature:
+ *
+ * <pre>
+ * void initializeXXX(YYY config) throws ConfigException,
+ * InitializationException;
+ * </pre>
+ *
+ * Where <code>XXX</code> is the simple name of the instance type
+ * <code>T</code>, and <code>YYY</code> is the expected
+ * configuration type for the implementation, which is either the
+ * configuration type <code>C</code> or a sub-type thereof.
+ *
+ * @param <C>
+ * The type of configuration referenced by this manager.
+ * @param <T>
+ * The type of component represented by the configuration.
+ */
+public abstract class AbstractOptionalConfigurationManager
+ <C extends Configuration, T> {
+
+ /**
+ * Private add listener implementation.
+ */
+ private class AddListener implements ConfigurationAddListener<C> {
+
+ // Private constructor.
+ private AddListener() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(C config) {
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ // We have committed to this change so always update the
+ // configuration.
+ setConfiguration(config);
+
+ if (isEnabled(config)) {
+ // The configuration is enabled so it should be instantiated.
+ try {
+ // Notify that a new instance has been added.
+ doRegisterInstance(getImplementation(config));
+ } catch (ConfigException e) {
+ messages.add(e.getMessage());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ } catch (InitializationException e) {
+ messages.add(e.getMessage());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+ } else {
+ // Ignore this configuration if it is disabled - we don't need
+ // to set instance to null here since it should already be
+ // null, but we do just to make the behavior explicit.
+ if (instance != null) {
+ finalizeInstance(instance);
+ instance = null;
+ }
+ notifyDisableInstance(config);
+ }
+
+ // Return the configuration result.
+ return new ConfigChangeResult(resultCode, adminActionRequired,
+ messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(C config,
+ List<String> unacceptableReasons) {
+ if (isEnabled(config)) {
+ // It's enabled so always validate the class.
+ return isJavaClassAcceptable(config, unacceptableReasons);
+ } else {
+ // It's disabled so ignore it.
+ return true;
+ }
+ }
+ }
+
+
+
+ /**
+ * Private change listener implementation.
+ */
+ private class ChangeListener implements
+ ConfigurationChangeListener<C> {
+
+ // Private constructor.
+ private ChangeListener() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(C config) {
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ // We have committed to this change so always update the
+ // configuration.
+ setConfiguration(config);
+
+ // See whether the configuration should be enabled.
+ if (instance == null) {
+ if (isEnabled(config)) {
+ // The configuration is enabled so it should be
+ // instantiated.
+ try {
+ // Notify that a new instance has been added.
+ doRegisterInstance(getImplementation(config));
+ } catch (ConfigException e) {
+ messages.add(e.getMessage());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ } catch (InitializationException e) {
+ messages.add(e.getMessage());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+ } else {
+ // Do nothing: we could notify that the configuration is
+ // disabled, but it was already, so there's no point in
+ // notifying again.
+ }
+ } else if (isEnabled(config)) {
+ // The instance is currently active, so we don't need to do
+ // anything. Changes to the class name should not be applied
+ // dynamically, so if the class name did change then
+ // indicate that administrative action is required for that
+ // change to take effect.
+ String className = getJavaImplementationClass(config);
+ if (!className.equals(instance.getClass().getName())) {
+ adminActionRequired = true;
+ }
+ } else {
+ // We need to disable the instance.
+ if (instance != null) {
+ finalizeInstance(instance);
+ instance = null;
+ }
+ notifyDisableInstance(config);
+ }
+
+ // Return the configuration result.
+ return new ConfigChangeResult(resultCode, adminActionRequired,
+ messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(C config,
+ List<String> unacceptableReasons) {
+ if (isEnabled(config)) {
+ // It's enabled so always validate the class.
+ return isJavaClassAcceptable(config, unacceptableReasons);
+ } else if (isEnabled(getConfiguration())) {
+ return isDisableInstanceAcceptable(config,
+ unacceptableReasons);
+ } else {
+ // It's already disabled so ignore it.
+ return true;
+ }
+ }
+ }
+
+
+
+ /**
+ * Private delete listener implementation.
+ */
+ private class DeleteListener implements
+ ConfigurationDeleteListener<C> {
+
+ // Private constructor.
+ private DeleteListener() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(C config) {
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+
+ // We have committed to this change so always update the
+ // configuration and finalize the instance.
+ setConfiguration(null);
+
+ if (instance != null) {
+ finalizeInstance(instance);
+ instance = null;
+ }
+ notifyDeleteInstance(config);
+
+ return new ConfigChangeResult(resultCode, adminActionRequired);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(C config,
+ List<String> unacceptableReasons) {
+ if (isEnabled(getConfiguration())) {
+ return isDisableInstanceAcceptable(config,
+ unacceptableReasons);
+ } else {
+ return true;
+ }
+ }
+ }
+
+ // The property definition defining the Java implementation class.
+ private final ClassPropertyDefinition propertyDefinition;
+
+ // The instance class.
+ private final Class<T> theClass;
+
+ // Configuration add listener.
+ private final AddListener addListener;
+
+ // Configuration change listener.
+ private final ChangeListener changeListener;
+
+ // Configuration delete listener.
+ private final DeleteListener deleteListener;
+
+ // Indicates whether or not the parent listeners have been
+ // registered.
+ private boolean listenersRegistered;
+
+ // The current active configuration.
+ private C currentConfig;
+
+ // The current active instance.
+ private T instance;
+
+
+
+ /**
+ * Create a new optional configuration manager.
+ *
+ * @param theClass
+ * The instance class.
+ * @param propertyDefinition
+ * The property definition defining the Java implementation
+ * class.
+ */
+ protected AbstractOptionalConfigurationManager(Class<T> theClass,
+ ClassPropertyDefinition propertyDefinition) {
+ this.currentConfig = null;
+ this.instance = null;
+ this.theClass = theClass;
+ this.propertyDefinition = propertyDefinition;
+ this.listenersRegistered = false;
+
+ this.addListener = new AddListener();
+ this.deleteListener = new DeleteListener();
+ this.changeListener = new ChangeListener();
+ }
+
+
+
+ /**
+ * Performs any finalization that may be necessary for this manager.
+ */
+ public final void finalizeManager() {
+ deregisterAddListener(addListener);
+ deregisterDeleteListener(deleteListener);
+
+ if (currentConfig != null) {
+ deregisterChangeListener(changeListener, currentConfig);
+ }
+
+ if (instance != null) {
+ finalizeInstance(instance);
+ }
+ }
+
+
+
+ /**
+ * Get the current active configuration.
+ *
+ * @return Returns the current active configuration.
+ */
+ public final C getConfiguration() {
+ return currentConfig;
+ }
+
+
+
+ /**
+ * Get the current active instance.
+ *
+ * @return Returns the current active instance.
+ */
+ public final T getInstance() {
+ return instance;
+ }
+
+
+
+ /**
+ * Initializes this manager based on the information in the provided
+ * configuration if available. The implementation of this method
+ * will first register this manager as an add/delete listener before
+ * processing the provided initial configuration if it is available.
+ * <p>
+ * It is safe to initialize the manager more than once. This is
+ * useful during testing as an easy way to set the manager's
+ * configuration.
+ *
+ * @param config
+ * The configuration (can be <code>null</code> if there
+ * is no initial configuration.
+ * @throws ConfigException
+ * If there is a problem with the configuration.
+ * @throws InitializationException
+ * If a problem occurs during initialization.
+ */
+ public final void initialize(C config) throws ConfigException,
+ InitializationException {
+ // Register to be notified when a configuration is added or
+ // removed (only do this once).
+ if (!listenersRegistered) {
+ registerAddListener(addListener);
+ registerDeleteListener(deleteListener);
+ listenersRegistered = true;
+ }
+
+ // Make sure that there is no current instance.
+ instance = null;
+
+ if (config != null) {
+ // Always register as a listener.
+ setConfiguration(config);
+
+ if (isEnabled(config)) {
+ // We have a configuration and it is enabled.
+ doRegisterInstance(getImplementation(config));
+ } else {
+ // There is a configuration present but it is disabled. Don't
+ // process the configuration in case it is invalid. We don't
+ // want to issue warnings for components which are disabled.
+ notifyDisableInstance(config);
+ }
+ }
+ }
+
+
+
+ /**
+ * Deregisters an add listener.
+ *
+ * @param listener
+ * The configuration add listener.
+ */
+ protected abstract void deregisterAddListener(
+ ConfigurationAddListener<C> listener);
+
+
+
+ /**
+ * Deregisters a change listener.
+ *
+ * @param listener
+ * The configuration change listener.
+ * @param config
+ * The configuration from which to deregister the change
+ * listener.
+ */
+ protected abstract void deregisterChangeListener(
+ ConfigurationChangeListener<C> listener, C config);
+
+
+
+ /**
+ * Deregisters a delete listener.
+ *
+ * @param listener
+ * The configuration delete listener.
+ */
+ protected abstract void deregisterDeleteListener(
+ ConfigurationDeleteListener<C> listener);
+
+
+
+ /**
+ * Finalizes a previously activate instance.
+ *
+ * @param instance
+ * The instance to be finalized.
+ */
+ protected abstract void finalizeInstance(T instance);
+
+
+
+ /**
+ * Get the name of the Java implementation class.
+ * <p>
+ * Sub-classes should usually implement this method using a call to
+ * the configuration's <code>getJavaImplementationClass()</code>
+ * method.
+ *
+ * @param config
+ * The active configuration.
+ * @return Returns the name of the Java implementation class.
+ */
+ protected abstract String getJavaImplementationClass(C config);
+
+
+
+ /**
+ * Indicates whether the active instance can be disabled or deleted.
+ *
+ * @param config
+ * The configuration that will be disabled or deleted.
+ * @param unacceptableReasons
+ * A list that can be used to hold messages about why the
+ * active instance cannot be disabled or deleted..
+ * @return Returns <code>true</code> if the active instance can be
+ * disabled or deleted.
+ */
+ protected abstract boolean isDisableInstanceAcceptable(C config,
+ List<String> unacceptableReasons);
+
+
+
+ /**
+ * Determines whether or not the active configuration is enabled or
+ * not.
+ * <p>
+ * Sub-classes should usually implement this method using a call to
+ * the configuration's <code>isEnabled()</code> method.
+ *
+ * @param config
+ * The active configuration.
+ * @return Returns <code>true</code> if the configuration is
+ * enabled.
+ */
+ protected abstract boolean isEnabled(C config);
+
+
+
+ /**
+ * Notify that the configuration has been deleted. This may involve
+ * logging a message. Implementations do not need to worry about
+ * finalizing the instance, since that is performed by the
+ * {@link #finalizeInstance(Object)} method.
+ *
+ * @param config
+ * The deleted configuration.
+ */
+ protected abstract void notifyDeleteInstance(C config);
+
+
+
+ /**
+ * Notify that the configuration has been disabled. This may involve
+ * logging a message. Implementations do not need to worry about
+ * finalizing the instance, since that is performed by the
+ * {@link #finalizeInstance(Object)} method.
+ *
+ * @param config
+ * The disabled configuration.
+ */
+ protected abstract void notifyDisableInstance(C config);
+
+
+
+ /**
+ * Register to be notified when the configuration is added.
+ *
+ * @param listener
+ * The configuration add listener.
+ * @throws ConfigException
+ * If the add listener could not be registered.
+ */
+ protected abstract void registerAddListener(
+ ConfigurationAddListener<C> listener) throws ConfigException;
+
+
+
+ /**
+ * Register to be notified when a configuration is changed.
+ *
+ * @param listener
+ * The configuration change listener.
+ * @param config
+ * Receive change notifications for this configuration.
+ */
+ protected abstract void registerChangeListener(
+ ConfigurationChangeListener<C> listener, C config);
+
+
+
+ /**
+ * Register to be notified when the configuration is deleted.
+ *
+ * @param listener
+ * The configuration delete listener.
+ * @throws ConfigException
+ * If the add listener could not be registered.
+ */
+ protected abstract void registerDeleteListener(
+ ConfigurationDeleteListener<C> listener) throws ConfigException;
+
+
+
+ /**
+ * Registers a newly activated instance. This may involve updating
+ * the parent configuration, starting a thread, etc. This manager
+ * will have already invoked <code>initialize(C config)</code>
+ * against the instance.
+ *
+ * @param instance
+ * The new instance.
+ * @throws InitializationException
+ * If a problem occurs during initialization.
+ */
+ protected abstract void registerInstance(T instance)
+ throws InitializationException;
+
+
+
+ // Notify listeners that a new instance has been added and/or
+ // enabled.
+ private void doRegisterInstance(T instance)
+ throws InitializationException {
+ this.instance = instance;
+
+ // Let sub-class implementation decide what to do with the new
+ // instance.
+ registerInstance(instance);
+ }
+
+
+
+ // Load, instantiate, and initialize the class named in the Java
+ // implementation class property of the provided configuration.
+ private T getImplementation(C config) throws ConfigException {
+ String className = getJavaImplementationClass(config);
+
+ // Load the class and cast it to a T.
+ Class<? extends T> implClass;
+ T instance;
+
+ try {
+ implClass = propertyDefinition.loadClass(className, theClass);
+ instance = implClass.newInstance();
+ } catch (Exception e) {
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_INSTANTIATE_CLASS;
+ String message = getMessage(msgID, String.valueOf(className),
+ String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e));
+ throw new ConfigException(msgID, message, e);
+ }
+
+ // Perform the necessary initialization for the instance.
+ try {
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ String name = getInitializationMethodName();
+ Method method = implClass.getMethod(name, config.definition()
+ .getServerConfigurationClass());
+
+ method.invoke(instance, config);
+ } catch (Exception e) {
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_INITIALIZE_COMPONENT;
+ String message = getMessage(msgID, String.valueOf(className),
+ String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e));
+ throw new ConfigException(msgID, message, e);
+ }
+
+ // The instance has been successfully initialized.
+ return instance;
+ }
+
+
+
+ // Get the name of the method which should be used
+ // to initialize instances.
+ private String getInitializationMethodName() {
+ return "initialize" + theClass.getSimpleName();
+ }
+
+
+
+ // Determines whether or not the new configuration's implementation
+ // class is acceptable.
+ private boolean isJavaClassAcceptable(C config,
+ List<String> unacceptableReasons) {
+ String className = getJavaImplementationClass(config);
+
+ // Load the class and cast it to a T.
+ Class<? extends T> implClass;
+
+ try {
+ implClass = propertyDefinition.loadClass(className, theClass);
+ implClass.newInstance();
+ } catch (Exception e) {
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_INSTANTIATE_CLASS;
+ unacceptableReasons.add(getMessage(msgID, String
+ .valueOf(className), String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e)));
+ return false;
+ }
+
+ // Perform the necessary initialization for the instance.
+ try {
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ String name = getInitializationMethodName();
+ implClass.getMethod(name, config.definition()
+ .getServerConfigurationClass());
+ } catch (Exception e) {
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_INITIALIZE_COMPONENT;
+ unacceptableReasons.add(getMessage(msgID, String
+ .valueOf(className), String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e)));
+ return false;
+ }
+
+ // The class is valid as far as we can tell.
+ return true;
+ }
+
+
+
+ // Set the new configuration and register for change events.
+ private void setConfiguration(C config) {
+ // We only need to register for change events if there was no
+ // previous configuration. This is because the notification
+ // frameworks ensures that listeners are preserved when a new
+ // configuration replaces an old one.
+ if (currentConfig == null && config != null) {
+ registerChangeListener(changeListener, config);
+ }
+ currentConfig = config;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
new file mode 100644
index 0000000..d921be2
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -0,0 +1,206 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.DecodingException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.api.ConfigAddListener;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.ResultCode;
+
+
+
+/**
+ * An adaptor class which converts {@link ConfigAddListener} callbacks
+ * to strongly typed {@link ConfigurationAddListener} callbacks.
+ *
+ * @param <S>
+ * The type of server configuration handled by the add
+ * listener.
+ */
+final class ConfigAddListenerAdaptor<S extends Configuration> extends
+ AbstractConfigListenerAdaptor implements ConfigAddListener {
+
+ // The managed object path of the parent.
+ private final ManagedObjectPath path;
+
+ // The instantiable relation.
+ private final InstantiableRelationDefinition<?, S> instantiableRelation;
+
+ // The optional relation.
+ private final OptionalRelationDefinition<?, S> optionalRelation;
+
+ // The underlying add listener.
+ private final ConfigurationAddListener<S> listener;
+
+ // Cached configuration object between accept/apply callbacks.
+ private S cachedConfiguration;
+
+
+
+ /**
+ * Create a new configuration add listener adaptor for an
+ * instantiable relation.
+ *
+ * @param path
+ * The managed object path of the parent.
+ * @param relation
+ * The instantiable relation.
+ * @param listener
+ * The underlying add listener.
+ */
+ public ConfigAddListenerAdaptor(ManagedObjectPath path,
+ InstantiableRelationDefinition<?, S> relation,
+ ConfigurationAddListener<S> listener) {
+ this.path = path;
+ this.instantiableRelation = relation;
+ this.optionalRelation = null;
+ this.listener = listener;
+ this.cachedConfiguration = null;
+ }
+
+
+
+ /**
+ * Create a new configuration add listener adaptor for an optional
+ * relation.
+ *
+ * @param path
+ * The managed object path of the parent.
+ * @param relation
+ * The optional relation.
+ * @param listener
+ * The underlying add listener.
+ */
+ public ConfigAddListenerAdaptor(ManagedObjectPath path,
+ OptionalRelationDefinition<?, S> relation,
+ ConfigurationAddListener<S> listener) {
+ this.path = path;
+ this.optionalRelation = relation;
+ this.instantiableRelation = null;
+ this.listener = listener;
+ this.cachedConfiguration = null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(
+ ConfigEntry configEntry) {
+ if (optionalRelation != null) {
+ // Optional managed objects are located directly beneath the
+ // parent and have a well-defined name. We need to make sure
+ // that we are handling the correct entry.
+ ManagedObjectPath childPath = path.child(optionalRelation);
+ DN expectedDN = DNBuilder.create(childPath);
+ if (!configEntry.getDN().equals(expectedDN)) {
+ // Doesn't apply to us.
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+ }
+
+ // Cached objects are guaranteed to be from previous acceptable
+ // callback.
+ return listener.applyConfigurationAdd(cachedConfiguration);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean configAddIsAcceptable(ConfigEntry configEntry,
+ StringBuilder unacceptableReason) {
+ DN dn = configEntry.getDN();
+ AttributeValue av = dn.getRDN().getAttributeValue(0);
+ String name = av.getStringValue().trim();
+
+ ManagedObjectPath childPath;
+ RelationDefinition<?, S> r;
+ if (instantiableRelation != null) {
+ childPath = path.child(instantiableRelation, name);
+ r = instantiableRelation;
+ } else {
+ // Optional managed objects are located directly beneath the
+ // parent and have a well-defined name. We need to make sure
+ // that we are handling the correct entry.
+ childPath = path.child(optionalRelation);
+ DN expectedDN = DNBuilder.create(childPath);
+ if (!dn.equals(expectedDN)) {
+ // Doesn't apply to us.
+ return true;
+ }
+
+ r = optionalRelation;
+ }
+
+ ServerManagedObject<? extends S> mo;
+ try {
+ mo = ServerManagedObject.decode(childPath, r
+ .getChildDefinition(), configEntry);
+ } catch (DecodingException e) {
+ generateUnacceptableReason(e, unacceptableReason);
+ return false;
+ }
+
+ cachedConfiguration = mo.getConfiguration();
+ List<String> reasons = new LinkedList<String>();
+ if (listener.isConfigurationAddAcceptable(cachedConfiguration,
+ reasons)) {
+ return true;
+ } else {
+ generateUnacceptableReason(reasons, unacceptableReason);
+ return false;
+ }
+ }
+
+
+
+ /**
+ * Get the configuiration add listener associated with this adaptor.
+ *
+ * @return Returns the configuiration add listener associated with
+ * this adaptor.
+ */
+ ConfigurationAddListener<S> getConfigurationAddListener() {
+ return listener;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
new file mode 100644
index 0000000..439c308
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
@@ -0,0 +1,145 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.DecodingException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.api.ConfigChangeListener;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.types.ConfigChangeResult;
+
+
+
+/**
+ * An adaptor class which converts {@link ConfigChangeListener}
+ * callbacks to strongly typed {@link ConfigurationChangeListener}
+ * callbacks.
+ *
+ * @param <S>
+ * The type of server configuration handled by the change
+ * listener.
+ */
+final class ConfigChangeListenerAdaptor<S extends Configuration>
+ extends AbstractConfigListenerAdaptor implements
+ ConfigChangeListener {
+
+ // The managed object path.
+ private final ManagedObjectPath path;
+
+ // The managed object definition.
+ private final AbstractManagedObjectDefinition<?, S> d;
+
+ // The underlying change listener.
+ private final ConfigurationChangeListener<? super S> listener;
+
+ // Cached managed object between accept/apply callbacks.
+ private ServerManagedObject<? extends S> cachedManagedObject;
+
+
+
+ /**
+ * Create a new configuration change listener adaptor.
+ *
+ * @param path
+ * The managed object path.
+ * @param d
+ * The managed object definition.
+ * @param listener
+ * The underlying change listener.
+ */
+ public ConfigChangeListenerAdaptor(ManagedObjectPath path,
+ AbstractManagedObjectDefinition<?, S> d,
+ ConfigurationChangeListener<? super S> listener) {
+ this.path = path;
+ this.d = d;
+ this.listener = listener;
+ this.cachedManagedObject = null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ ConfigEntry configEntry) {
+ // TODO: looking at the ConfigFileHandler implementation reveals
+ // that this ConfigEntry will actually be a different object to
+ // the one passed in the previous callback (it will have the same
+ // content though). This config entry has the correct listener
+ // lists.
+ cachedManagedObject.setConfigEntry(configEntry);
+
+ return listener.applyConfigurationChange(cachedManagedObject
+ .getConfiguration());
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean configChangeIsAcceptable(ConfigEntry configEntry,
+ StringBuilder unacceptableReason) {
+ try {
+ cachedManagedObject = ServerManagedObject.decode(path, d,
+ configEntry);
+ } catch (DecodingException e) {
+ generateUnacceptableReason(e, unacceptableReason);
+ return false;
+ }
+
+ List<String> reasons = new LinkedList<String>();
+ if (listener.isConfigurationChangeAcceptable(cachedManagedObject
+ .getConfiguration(), reasons)) {
+ return true;
+ } else {
+ generateUnacceptableReason(reasons, unacceptableReason);
+ return false;
+ }
+ }
+
+
+
+ /**
+ * Get the configuiration change listener associated with this
+ * adaptor.
+ *
+ * @return Returns the configuration change listener associated with
+ * this adaptor.
+ */
+ ConfigurationChangeListener<? super S> getConfigurationChangeListener() {
+ return listener;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java b/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
new file mode 100644
index 0000000..8184d8e
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
@@ -0,0 +1,209 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.DecodingException;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.api.ConfigDeleteListener;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.ResultCode;
+
+
+
+/**
+ * An adaptor class which converts {@link ConfigDeleteListener}
+ * callbacks to strongly typed {@link ConfigurationDeleteListener}
+ * callbacks.
+ *
+ * @param <S>
+ * The type of server configuration handled by the delete
+ * listener.
+ */
+final class ConfigDeleteListenerAdaptor<S extends Configuration>
+ extends AbstractConfigListenerAdaptor implements
+ ConfigDeleteListener {
+
+ // The managed object path of the parent.
+ private final ManagedObjectPath path;
+
+ // The instantiable relation.
+ private final InstantiableRelationDefinition<?, S> instantiableRelation;
+
+ // The optional relation.
+ private final OptionalRelationDefinition<?, S> optionalRelation;
+
+ // The underlying delete listener.
+ private final ConfigurationDeleteListener<S> listener;
+
+ // Cached configuration object between accept/apply callbacks.
+ private S cachedConfiguration;
+
+
+
+ /**
+ * Create a new configuration delete listener adaptor for an
+ * instantiable relation.
+ *
+ * @param path
+ * The managed object path of the parent.
+ * @param relation
+ * The instantiable relation.
+ * @param listener
+ * The underlying delete listener.
+ */
+ public ConfigDeleteListenerAdaptor(ManagedObjectPath path,
+ InstantiableRelationDefinition<?, S> relation,
+ ConfigurationDeleteListener<S> listener) {
+ this.path = path;
+ this.optionalRelation = null;
+ this.instantiableRelation = relation;
+ this.listener = listener;
+ this.cachedConfiguration = null;
+ }
+
+
+
+ /**
+ * Create a new configuration delete listener adaptor for an
+ * optional relation.
+ *
+ * @param path
+ * The managed object path of the parent.
+ * @param relation
+ * The optional relation.
+ * @param listener
+ * The underlying delete listener.
+ */
+ public ConfigDeleteListenerAdaptor(ManagedObjectPath path,
+ OptionalRelationDefinition<?, S> relation,
+ ConfigurationDeleteListener<S> listener) {
+ this.path = path;
+ this.optionalRelation = relation;
+ this.instantiableRelation = null;
+ this.listener = listener;
+ this.cachedConfiguration = null;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(
+ ConfigEntry configEntry) {
+ if (optionalRelation != null) {
+ // Optional managed objects are located directly beneath the
+ // parent and have a well-defined name. We need to make sure
+ // that we are handling the correct entry.
+ ManagedObjectPath childPath = path.child(optionalRelation);
+ DN expectedDN = DNBuilder.create(childPath);
+ if (!configEntry.getDN().equals(expectedDN)) {
+ // Doesn't apply to us.
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
+ }
+
+ // Cached objects are guaranteed to be from previous acceptable
+ // callback.
+ return listener.applyConfigurationDelete(cachedConfiguration);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
+ StringBuilder unacceptableReason) {
+ DN dn = configEntry.getDN();
+ AttributeValue av = dn.getRDN().getAttributeValue(0);
+ String name = av.getStringValue().trim();
+
+ ManagedObjectPath childPath;
+ RelationDefinition<?, S> r;
+ if (instantiableRelation != null) {
+ childPath = path.child(instantiableRelation, name);
+ r = instantiableRelation;
+ } else {
+ // Optional managed objects are located directly beneath the
+ // parent and have a well-defined name. We need to make sure
+ // that we are handling the correct entry.
+ childPath = path.child(optionalRelation);
+ DN expectedDN = DNBuilder.create(childPath);
+ if (!dn.equals(expectedDN)) {
+ // Doesn't apply to us.
+ return true;
+ }
+
+ r = optionalRelation;
+ }
+
+ ServerManagedObject<? extends S> mo;
+ try {
+ mo = ServerManagedObject.decode(childPath, r
+ .getChildDefinition(), configEntry);
+ } catch (DecodingException e) {
+ generateUnacceptableReason(e, unacceptableReason);
+ return false;
+ }
+
+ cachedConfiguration = mo.getConfiguration();
+ List<String> reasons = new LinkedList<String>();
+ if (listener.isConfigurationDeleteAcceptable(cachedConfiguration,
+ reasons)) {
+ return true;
+ } else {
+ generateUnacceptableReason(reasons, unacceptableReason);
+ return false;
+ }
+ }
+
+
+
+ /**
+ * Get the configuiration delete listener associated with this
+ * adaptor.
+ *
+ * @return Returns the configuiration delete listener associated
+ * with this adaptor.
+ */
+ ConfigurationDeleteListener<S> getConfigurationDeleteListener() {
+ return listener;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java b/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java
new file mode 100644
index 0000000..c8ab7ed
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ConfigExceptionFactory.java
@@ -0,0 +1,129 @@
+/*
+ * 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.admin.server;
+
+
+
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.config.ConfigException;
+import org.opends.server.messages.AdminMessages;
+import org.opends.server.types.DN;
+
+
+
+/**
+ * A utility class for converting admin exceptions to config exceptions.
+ */
+final class ConfigExceptionFactory {
+
+ // The singleton instance.
+ private static final ConfigExceptionFactory INSTANCE =
+ new ConfigExceptionFactory();
+
+
+
+ // Prevent instantiation.
+ private ConfigExceptionFactory() {
+ // Do nothing.
+ }
+
+
+
+ /**
+ * Get the configuration exception factory instance.
+ *
+ * @return Returns the configuration exception factory instance.
+ */
+ public static ConfigExceptionFactory getInstance() {
+ return INSTANCE;
+ }
+
+
+
+ /**
+ * Create a configuration exception from a definition decoding exception.
+ *
+ * @param dn
+ * The dn of the configuration entry that could not be decoded.
+ * @param e
+ * The definition decoding exception
+ * @return Returns the configuration exception.
+ */
+ public ConfigException createDecodingExceptionAdaptor(DN dn,
+ DefinitionDecodingException e) {
+ int msgID = AdminMessages.MSGID_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM;
+ String message = getMessage(msgID, String.valueOf(dn),
+ stackTraceToSingleLineString(e));
+ return new ConfigException(msgID, message, e);
+ }
+
+
+
+ /**
+ * Create a configuration exception from a server managed object decoding
+ * exception.
+ *
+ * @param e
+ * The server managed object decoding exception.
+ * @return Returns the configuration exception.
+ */
+
+ public ConfigException createDecodingExceptionAdaptor(
+ ServerManagedObjectDecodingException e) {
+ int msgID = AdminMessages.MSGID_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM;
+ DN dn = e.getPartialManagedObject().getDN();
+ String message = getMessage(msgID, String.valueOf(dn),
+ stackTraceToSingleLineString(e));
+ return new ConfigException(msgID, message, e);
+ }
+
+
+
+ /**
+ * Create an exception that describes a problem that occurred when attempting
+ * to load and instantiate a class.
+ *
+ * @param dn
+ * The dn of the configuration entry was being processed.
+ * @param className
+ * The name of the class that could not be loaded or instantiated.
+ * @param e
+ * The exception that occurred.
+ * @return Returns the configuration exception.
+ */
+
+ public ConfigException createClassLoadingExceptionAdaptor(DN dn,
+ String className, Exception e) {
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_INSTANTIATE_CLASS;
+ String message = getMessage(msgID, String.valueOf(className), String
+ .valueOf(dn), stackTraceToSingleLineString(e));
+ return new ConfigException(msgID, message, e);
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigurationAddListener.java b/opends/src/server/org/opends/server/admin/server/ConfigurationAddListener.java
new file mode 100644
index 0000000..52b2f67
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ConfigurationAddListener.java
@@ -0,0 +1,74 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.List;
+
+import org.opends.server.types.ConfigChangeResult;
+
+
+
+/**
+ * This interface defines the methods that a Directory Server
+ * configurable component should implement if it wishes to be able to
+ * receive notifications when a new configuration is added.
+ *
+ * @param <T>
+ * The type of configuration that this listener should be
+ * notified about.
+ */
+public interface ConfigurationAddListener<T> {
+
+ /**
+ * Indicates whether the proposed addition of a new configuration is
+ * acceptable to this add listener.
+ *
+ * @param configuration
+ * The configuration that will be added.
+ * @param unacceptableReasons
+ * A list that can be used to hold messages about why the
+ * provided configuration is not acceptable.
+ * @return Returns <code>true</code> if the proposed addition is
+ * acceptable, or <code>false</code> if it is not.
+ */
+ public boolean isConfigurationAddAcceptable(T configuration,
+ List<String> unacceptableReasons);
+
+
+
+ /**
+ * Adds a new configuration to this add listener.
+ *
+ * @param configuration
+ * The configuration that will be added.
+ * @return Returns information about the result of adding the
+ * configuration.
+ */
+ public ConfigChangeResult applyConfigurationAdd(T configuration);
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigurationChangeListener.java b/opends/src/server/org/opends/server/admin/server/ConfigurationChangeListener.java
new file mode 100644
index 0000000..b6cddce
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ConfigurationChangeListener.java
@@ -0,0 +1,75 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.List;
+
+import org.opends.server.types.ConfigChangeResult;
+
+
+
+/**
+ * This interface defines the methods that a Directory Server
+ * configurable component should implement if it wishes to be able to
+ * receive notifications when a its associated configuration is
+ * changed.
+ *
+ * @param <T>
+ * The type of configuration that this listener should be
+ * notified about.
+ */
+public interface ConfigurationChangeListener<T> {
+
+ /**
+ * Indicates whether the proposed change to the configuration is
+ * acceptable to this change listener.
+ *
+ * @param configuration
+ * The new configuration containing the changes.
+ * @param unacceptableReasons
+ * A list that can be used to hold messages about why the
+ * provided configuration is not acceptable.
+ * @return Returns <code>true</code> if the proposed change is
+ * acceptable, or <code>false</code> if it is not.
+ */
+ public boolean isConfigurationChangeAcceptable(T configuration,
+ List<String> unacceptableReasons);
+
+
+
+ /**
+ * Applies the configuration changes to this change listener.
+ *
+ * @param configuration
+ * The new configuration containing the changes.
+ * @return Returns information about the result of changing the
+ * configuration.
+ */
+ public ConfigChangeResult applyConfigurationChange(T configuration);
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ConfigurationDeleteListener.java b/opends/src/server/org/opends/server/admin/server/ConfigurationDeleteListener.java
new file mode 100644
index 0000000..0457fee
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ConfigurationDeleteListener.java
@@ -0,0 +1,74 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.List;
+
+import org.opends.server.types.ConfigChangeResult;
+
+
+
+/**
+ * This interface defines the methods that a Directory Server
+ * configurable component should implement if it wishes to be able to
+ * receive notifications when an existing configuration is deleted.
+ *
+ * @param <T>
+ * The type of configuration that this listener should be
+ * notified about.
+ */
+public interface ConfigurationDeleteListener<T> {
+
+ /**
+ * Indicates whether the proposed deletion of an existing
+ * configuration is acceptable to this delete listener.
+ *
+ * @param configuration
+ * The configuration that will be deleted.
+ * @param unacceptableReasons
+ * A list that can be used to hold messages about why the
+ * provided configuration is not acceptable.
+ * @return Returns <code>true</code> if the proposed deletion is
+ * acceptable, or <code>false</code> if it is not.
+ */
+ public boolean isConfigurationDeleteAcceptable(T configuration,
+ List<String> unacceptableReasons);
+
+
+
+ /**
+ * Deletes an existing configuration from this delete listener.
+ *
+ * @param configuration
+ * The existing configuration that will be deleted.
+ * @return Returns information about the result of deleting the
+ * configuration.
+ */
+ public ConfigChangeResult applyConfigurationDelete(T configuration);
+}
diff --git a/opends/src/server/org/opends/server/admin/server/DNBuilder.java b/opends/src/server/org/opends/server/admin/server/DNBuilder.java
new file mode 100644
index 0000000..31bc078
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/DNBuilder.java
@@ -0,0 +1,170 @@
+/*
+ * 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.admin.server;
+
+
+
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.ManagedObjectPathSerializer;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.RDN;
+
+
+
+/**
+ * A strategy for creating <code>DN</code>s from managed object paths.
+ */
+final class DNBuilder implements ManagedObjectPathSerializer {
+
+ /**
+ * Creates a new DN representing the specified managed object path.
+ *
+ * @param path
+ * The managed object path.
+ * @return Returns a new DN representing the specified managed object path.
+ */
+ public static DN create(ManagedObjectPath path) {
+ DNBuilder builder = new DNBuilder();
+ path.serialize(builder);
+ return builder.getInstance();
+ }
+
+
+
+ /**
+ * Creates a new DN representing the specified managed object path
+ * and relation.
+ *
+ * @param path
+ * The managed object path.
+ * @param relation
+ * The child relation.
+ * @return Returns a new DN representing the specified managed
+ * object path and relation.
+ */
+ public static DN create(ManagedObjectPath path,
+ RelationDefinition<?, ?> relation) {
+ DNBuilder builder = new DNBuilder();
+ path.serialize(builder);
+ builder.appendManagedObjectPathElement(relation);
+ return builder.getInstance();
+ }
+
+ // The current DN.
+ private DN dn;
+
+ // The LDAP profile.
+ private final LDAPProfile profile;
+
+
+
+ /**
+ * Create a new DN builder.
+ */
+ public DNBuilder() {
+ this.dn = DN.nullDN();
+ this.profile = LDAPProfile.getInstance();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void appendManagedObjectPathElement(
+ InstantiableRelationDefinition<?, ?> r, String name) {
+ // Add the RDN sequence representing the relation.
+ appendManagedObjectPathElement((RelationDefinition) r);
+
+ // Now add the single RDN representing the named instance.
+ String type = profile.getInstantiableRelationChildRDNType(r);
+ AttributeType atype = DirectoryServer.getAttributeType(type.toLowerCase());
+ AttributeValue avalue = new AttributeValue(atype, name);
+ dn = dn.concat(RDN.create(atype, avalue));
+ }
+
+
+
+ /**
+ * Appends the RDN sequence representing the provided relation.
+ *
+ * @param r
+ * The relation definition.
+ */
+ public void appendManagedObjectPathElement(RelationDefinition<?, ?> r) {
+ // Add the RDN sequence representing the relation.
+ try {
+ DN localName = DN.decode(profile.getRelationRDNSequence(r));
+ dn = dn.concat(localName);
+ } catch (DirectoryException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void appendManagedObjectPathElement(
+ OptionalRelationDefinition<?, ?> r) {
+ // Add the RDN sequence representing the relation.
+ appendManagedObjectPathElement((RelationDefinition) r);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void appendManagedObjectPathElement(
+ SingletonRelationDefinition<?, ?> r) {
+ // Add the RDN sequence representing the relation.
+ appendManagedObjectPathElement((RelationDefinition) r);
+ }
+
+
+
+ /**
+ * Create a new DN using the current state of this DN builder.
+ *
+ * @return Returns the new DN instance.
+ */
+ public DN getInstance() {
+ return dn;
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java b/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
new file mode 100644
index 0000000..67d12df
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
@@ -0,0 +1,994 @@
+/*
+ * 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 2006-2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.admin.server;
+
+
+
+import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.DefinitionResolver;
+import org.opends.server.admin.InheritedDefaultValueProvider;
+import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.LDAPProfile;
+import org.opends.server.admin.ManagedObjectDefinition;
+import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.admin.OperationsException;
+import org.opends.server.admin.OptionalRelationDefinition;
+import org.opends.server.admin.PropertyDefinition;
+import org.opends.server.admin.PropertyException;
+import org.opends.server.admin.PropertyNotFoundException;
+import org.opends.server.admin.PropertyProvider;
+import org.opends.server.admin.RelationDefinition;
+import org.opends.server.admin.SingletonRelationDefinition;
+import org.opends.server.admin.StringPropertyProvider;
+import org.opends.server.admin.client.PropertySet;
+import org.opends.server.admin.std.meta.RootCfgDefn;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.api.AttributeValueDecoder;
+import org.opends.server.api.ConfigAddListener;
+import org.opends.server.api.ConfigChangeListener;
+import org.opends.server.api.ConfigDeleteListener;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.messages.AdminMessages;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DirectoryException;
+
+
+
+/**
+ * A server-side managed object.
+ *
+ * @param <S>
+ * The type of server configuration represented by the server
+ * managed object.
+ */
+public final class ServerManagedObject<S extends Configuration>
+ implements PropertyProvider {
+
+ /**
+ * Internal inherited default value provider implementation.
+ */
+ private static class MyInheritedDefaultValueProvider implements
+ InheritedDefaultValueProvider {
+
+ // The base path.
+ private final ManagedObjectPath path;
+
+
+
+ /**
+ * Create a new inherited default value provider.
+ *
+ * @param path
+ * The base path.
+ */
+ public MyInheritedDefaultValueProvider(ManagedObjectPath path) {
+ this.path = path;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<?> getDefaultPropertyValues(
+ ManagedObjectPath path, String propertyName)
+ throws OperationsException, PropertyNotFoundException {
+ // Get the configuration entry.
+ DN targetDN = DNBuilder.create(path);
+ final ConfigEntry configEntry;
+ try {
+ configEntry = DirectoryServer.getConfigEntry(targetDN);
+ } catch (ConfigException e) {
+ throw new ManagedObjectNotFoundException(e);
+ }
+
+ if (configEntry == null) {
+ throw new ManagedObjectNotFoundException();
+ }
+
+ ServerManagedObject<?> mo = decode(path, path
+ .getManagedObjectDefinition(), configEntry);
+ ManagedObjectDefinition<?, ?> mod = mo
+ .getManagedObjectDefinition();
+ try {
+ PropertyDefinition<?> dpd = mod
+ .getPropertyDefinition(propertyName);
+ return mo.getPropertyValues(dpd);
+ } catch (IllegalArgumentException e) {
+ throw new PropertyNotFoundException(propertyName);
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ManagedObjectPath getManagedObjectPath() {
+ return path;
+ }
+
+ }
+
+
+
+ /**
+ * Decodes a configuration entry into the required type of server
+ * managed object.
+ *
+ * @param <S>
+ * The type of server configuration represented by the
+ * decoded server managed object.
+ * @param path
+ * The location of the server managed object.
+ * @param definition
+ * The required managed object type.
+ * @param configEntry
+ * The configuration entry that should be decoded.
+ * @return Returns the new server-side managed object from the
+ * provided definition and configuration entry.
+ * @throws DefinitionDecodingException
+ * If the managed object's type could not be determined.
+ * @throws ServerManagedObjectDecodingException
+ * If one or more of the managed object's properties could
+ * not be decoded.
+ */
+ static <S extends Configuration> ServerManagedObject<? extends S> decode(
+ ManagedObjectPath path,
+ AbstractManagedObjectDefinition<?, S> definition,
+ final ConfigEntry configEntry)
+ throws DefinitionDecodingException,
+ ServerManagedObjectDecodingException {
+ // First determine the correct definition to use for the entry.
+ // This could either be the provided definition, or one of its
+ // sub-definitions.
+ DefinitionResolver resolver = new DefinitionResolver() {
+
+ public boolean matches(AbstractManagedObjectDefinition<?, ?> d) {
+ String oc = LDAPProfile.getInstance().getObjectClass(d);
+ return configEntry.hasObjectClass(oc);
+ }
+
+ };
+
+ final ManagedObjectDefinition<?, ? extends S> mod = definition
+ .resolveManagedObjectDefinition(resolver);
+
+ // Use a string-based property provider to pull in the property
+ // values.
+ StringPropertyProvider provider = new StringPropertyProvider() {
+
+ public Collection<String> getPropertyValues(
+ PropertyDefinition<?> d) throws IllegalArgumentException {
+ String attrID = LDAPProfile.getInstance().getAttributeName(
+ mod, d);
+ // TODO: we create a default attribute type if it is
+ // undefined. We should log a warning here if this is the case
+ // since the attribute should have been defined.
+ AttributeType type = DirectoryServer.getAttributeType(attrID, true);
+ AttributeValueDecoder<String> decoder =
+ new AttributeValueDecoder<String>() {
+
+ public String decode(AttributeValue value)
+ throws DirectoryException {
+ return value.getStringValue();
+ }
+ };
+
+ try {
+ Collection<String> values = new LinkedList<String>();
+ configEntry.getEntry().getAttributeValues(type, decoder,
+ values);
+ return values;
+ } catch (DirectoryException e) {
+ // Should not happen.
+ throw new RuntimeException(e);
+ }
+ }
+
+ };
+
+ // Create the new managed object's property set, saving any
+ // decoding exceptions.
+ List<PropertyException> exceptions = new LinkedList<PropertyException>();
+ InheritedDefaultValueProvider i = new MyInheritedDefaultValueProvider(
+ path);
+ PropertySet properties = PropertySet.create(mod, provider, i,
+ exceptions);
+ ServerManagedObject<? extends S> mo = decodeAux(path, mod,
+ properties, configEntry);
+
+ // If there were no decoding problems then return the object,
+ // otherwise throw an operations exception.
+ if (exceptions.isEmpty()) {
+ return mo;
+ } else {
+ throw new ServerManagedObjectDecodingException(mo, exceptions);
+ }
+ }
+
+
+
+ /**
+ * Construct a root server managed object.
+ *
+ * @return Returns a root server managed object.
+ */
+ static ServerManagedObject<RootCfg> getRootManagedObject() {
+ ManagedObjectPath path = ManagedObjectPath.emptyPath();
+ List<PropertyException> exceptions = new LinkedList<PropertyException>();
+ InheritedDefaultValueProvider i = new MyInheritedDefaultValueProvider(
+ path);
+ PropertySet properties = PropertySet.create(
+ RootCfgDefn.getInstance(),
+ PropertyProvider.DEFAULT_PROVIDER, i, exceptions);
+
+ // Should never get any exceptions.
+ if (!exceptions.isEmpty()) {
+ throw new RuntimeException(
+ "Got exceptions when creating root managed object");
+ }
+
+ return new ServerManagedObject<RootCfg>(path,
+ RootCfgDefn.getInstance(), properties,
+ null);
+ }
+
+
+
+ // Decode helper method required to avoid generics warning.
+ private static <S extends Configuration> ServerManagedObject<S> decodeAux(
+ ManagedObjectPath path, ManagedObjectDefinition<?, S> d,
+ PropertySet properties, ConfigEntry configEntry) {
+ return new ServerManagedObject<S>(path, d, properties,
+ configEntry);
+ }
+
+ // The managed object's definition.
+ private final ManagedObjectDefinition<?, S> definition;
+
+ // The managed object path identifying this managed object's
+ // location.
+ private final ManagedObjectPath path;
+
+ // The managed object's properties.
+ private final PropertySet properties;
+
+ // The configuration entry associated with this server managed
+ // object (null if root).
+ private ConfigEntry configEntry;
+
+
+
+ // Create an new server side managed object.
+ private ServerManagedObject(ManagedObjectPath path,
+ ManagedObjectDefinition<?, S> d, PropertySet properties,
+ ConfigEntry configEntry) {
+ this.definition = d;
+ this.path = path;
+ this.properties = properties;
+ this.configEntry = configEntry;
+ }
+
+
+
+ /**
+ * Deregisters an existing configuration add listener.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The instantiable relation definition.
+ * @param listener
+ * The configuration add listener.
+ * @throws IllegalArgumentException
+ * If the instantiable relation definition is not
+ * associated with this managed object's definition.
+ */
+ public <M extends Configuration> void deregisterAddListener(
+ InstantiableRelationDefinition<?, M> d,
+ ConfigurationAddListener<M> listener)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ DN baseDN = DNBuilder.create(path, d);
+ deregisterAddListener(baseDN, listener);
+ }
+
+
+
+ /**
+ * Deregisters an existing configuration add listener.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The optional relation definition.
+ * @param listener
+ * The configuration add listener.
+ * @throws IllegalArgumentException
+ * If the optional relation definition is not associated
+ * with this managed object's definition.
+ */
+ public <M extends Configuration> void deregisterAddListener(
+ OptionalRelationDefinition<?, M> d,
+ ConfigurationAddListener<M> listener)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ DN baseDN = DNBuilder.create(path);
+ deregisterAddListener(baseDN, listener);
+ }
+
+
+
+ /**
+ * Deregisters an existing configuration change listener.
+ *
+ * @param listener
+ * The configuration change listener.
+ */
+ public void deregisterChangeListener(
+ ConfigurationChangeListener<? super S> listener) {
+ for (ConfigChangeListener l : configEntry.getChangeListeners()) {
+ if (l instanceof ConfigChangeListenerAdaptor) {
+ ConfigChangeListenerAdaptor adaptor = (ConfigChangeListenerAdaptor) l;
+ if (adaptor.getConfigurationChangeListener() == listener) {
+ configEntry.deregisterChangeListener(adaptor);
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * Deregisters an existing configuration delete listener.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The instantiable relation definition.
+ * @param listener
+ * The configuration delete listener.
+ * @throws IllegalArgumentException
+ * If the instantiable relation definition is not
+ * associated with this managed object's definition.
+ */
+ public <M extends Configuration> void deregisterDeleteListener(
+ InstantiableRelationDefinition<?, M> d,
+ ConfigurationDeleteListener<M> listener)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ DN baseDN = DNBuilder.create(path, d);
+ deregisterDeleteListener(baseDN, listener);
+ }
+
+
+
+ /**
+ * Deregisters an existing configuration delete listener.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The optional relation definition.
+ * @param listener
+ * The configuration delete listener.
+ * @throws IllegalArgumentException
+ * If the optional relation definition is not associated
+ * with this managed object's definition.
+ */
+ public <M extends Configuration> void deregisterDeleteListener(
+ OptionalRelationDefinition<?, M> d,
+ ConfigurationDeleteListener<M> listener)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ DN baseDN = DNBuilder.create(path);
+ deregisterDeleteListener(baseDN, listener);
+ }
+
+
+
+ /**
+ * Retrieve an instantiable child managed object.
+ *
+ * @param <M>
+ * The requested type of the child server managed object
+ * configuration.
+ * @param d
+ * The instantiable relation definition.
+ * @param name
+ * The name of the child managed object.
+ * @return Returns the instantiable child managed object.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws ConfigException
+ * If the child managed object could not be found or if it
+ * could not be decoded.
+ */
+ public <M extends Configuration> ServerManagedObject<? extends M> getChild(
+ InstantiableRelationDefinition<?, M> d, String name)
+ throws IllegalArgumentException, ConfigException {
+ validateRelationDefinition(d);
+
+ ManagedObjectPath childPath = path.child(d, name);
+ return getChild(childPath, d);
+ }
+
+
+
+ /**
+ * Retrieve an optional child managed object.
+ *
+ * @param <M>
+ * The requested type of the child server managed object
+ * configuration.
+ * @param d
+ * The optional relation definition.
+ * @return Returns the optional child managed object.
+ * @throws IllegalArgumentException
+ * If the optional relation definition is not associated
+ * with this managed object's definition.
+ * @throws ConfigException
+ * If the child managed object could not be found or if it
+ * could not be decoded.
+ */
+ public <M extends Configuration> ServerManagedObject<? extends M> getChild(
+ OptionalRelationDefinition<?, M> d)
+ throws IllegalArgumentException, ConfigException {
+ validateRelationDefinition(d);
+
+ // Get the configuration entry.
+ ManagedObjectPath childPath = path.child(d);
+ return getChild(childPath, d);
+ }
+
+
+
+ /**
+ * Retrieve a singleton child managed object.
+ *
+ * @param <M>
+ * The requested type of the child server managed object
+ * configuration.
+ * @param d
+ * The singleton relation definition.
+ * @return Returns the singleton child managed object.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ * @throws ConfigException
+ * If the child managed object could not be found or if it
+ * could not be decoded.
+ */
+ public <M extends Configuration> ServerManagedObject<? extends M> getChild(
+ SingletonRelationDefinition<?, M> d)
+ throws IllegalArgumentException, ConfigException {
+ validateRelationDefinition(d);
+
+ // Get the configuration entry.
+ ManagedObjectPath childPath = path.child(d);
+ return getChild(childPath, d);
+ }
+
+
+
+ /**
+ * Creates a server configuration view of this managed object.
+ *
+ * @return Returns the server configuration view of this managed
+ * object.
+ */
+ public S getConfiguration() {
+ return definition.createServerConfiguration(this);
+ }
+
+
+
+ /**
+ * Get the DN of the LDAP entry associated with this server managed
+ * object.
+ *
+ * @return Returns the DN of the LDAP entry associated with this
+ * server managed object, or an null DN if this is the root
+ * managed object.
+ */
+ public DN getDN() {
+ if (configEntry != null) {
+ return configEntry.getDN();
+ } else {
+ return DN.nullDN();
+ }
+ }
+
+
+
+ /**
+ * Get the definition associated with this server managed object.
+ *
+ * @return Returns the definition associated with this server
+ * managed object.
+ */
+ public ManagedObjectDefinition<?, S> getManagedObjectDefinition() {
+ return definition;
+ }
+
+
+
+ /**
+ * Get the path of this server managed object.
+ *
+ * @return Returns the path of this server managed object.
+ */
+ public ManagedObjectPath getManagedObjectPath() {
+ return path;
+ }
+
+
+
+ /**
+ * Get the current value of the specified property.
+ * <p>
+ * If the value has been modified then the new value is returned,
+ * otherwise the original value will be returned.
+ *
+ * @param <T>
+ * The type of the property to be retrieved.
+ * @param d
+ * The property to be retrieved.
+ * @return Returns the property's current value, or
+ * <code>null</code> if there is no value(s) associated
+ * with the property and any default behavior is
+ * applicable.
+ * @throws IllegalArgumentException
+ * If the property definition is not associated with this
+ * managed object's definition.
+ */
+ public <T> T getPropertyValue(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ return properties.getPropertyValue(d);
+ }
+
+
+
+ /**
+ * Get the current values of the specified property.
+ * <p>
+ * If the property has been modified then the new values are
+ * returned, otherwise the original values will be returned.
+ *
+ * @param <T>
+ * The type of the property to be retrieved.
+ * @param d
+ * The property to be retrieved.
+ * @return Returns a newly allocated set containing a copy of the
+ * property's current values. An empty set indicates that
+ * the property has no values defined and any default
+ * behavior is applicable.
+ * @throws IllegalArgumentException
+ * If the property definition is not associated with this
+ * managed object's definition.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d)
+ throws IllegalArgumentException {
+ return properties.getPropertyValues(d);
+ }
+
+
+
+ /**
+ * Determines whether or not the optional managed object associated
+ * with the specified optional relations exists.
+ *
+ * @param d
+ * The optional relation definition.
+ * @return Returns <code>true</code> if the optional managed
+ * object exists, <code>false</code> otherwise.
+ * @throws IllegalArgumentException
+ * If the optional relation definition is not associated
+ * with this managed object's definition.
+ */
+ public boolean hasChild(OptionalRelationDefinition<?, ?> d)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ // Get the configuration entry.
+ DN targetDN = DNBuilder.create(path, d);
+ try {
+ return (getManagedObjectConfigEntry(targetDN) != null);
+ } catch (ConfigException e) {
+ // Assume it doesn't exist.
+ return false;
+ }
+ }
+
+
+
+ /**
+ * Lists the child managed objects associated with the specified
+ * instantiable relation.
+ *
+ * @param d
+ * The instantiable relation definition.
+ * @return Returns the names of the child managed objects.
+ * @throws IllegalArgumentException
+ * If the relation definition is not associated with this
+ * managed object's definition.
+ */
+ public String[] listChildren(InstantiableRelationDefinition<?, ?> d)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ // Get the target entry.
+ DN targetDN = DNBuilder.create(path, d);
+ ConfigEntry configEntry;
+ try {
+ configEntry = DirectoryServer.getConfigEntry(targetDN);
+ } catch (ConfigException e) {
+ return new String[0];
+ }
+
+ if (configEntry == null) {
+ return new String[0];
+ }
+
+ // Retrieve the children.
+ Set<DN> children = configEntry.getChildren().keySet();
+ ArrayList<String> names = new ArrayList<String>(children.size());
+ for (DN child : children) {
+ // Assume that RDNs are single-valued and can be trimmed.
+ AttributeValue av = child.getRDN().getAttributeValue(0);
+ names.add(av.getStringValue().trim());
+ }
+
+ return names.toArray(new String[names.size()]);
+ }
+
+
+
+ /**
+ * Register to be notified when new child configurations are added
+ * beneath an instantiable relation.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The instantiable relation definition.
+ * @param listener
+ * The configuration add listener.
+ * @throws IllegalArgumentException
+ * If the instantiable relation definition is not
+ * associated with this managed object's definition.
+ * @throws ConfigException
+ * If the configuration entry associated with the
+ * instantiable relation could not be retrieved.
+ */
+ public <M extends Configuration> void registerAddListener(
+ InstantiableRelationDefinition<?, M> d,
+ ConfigurationAddListener<M> listener)
+ throws IllegalArgumentException, ConfigException {
+ validateRelationDefinition(d);
+
+ DN baseDN = DNBuilder.create(path, d);
+ ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+ ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path,
+ d, listener);
+ configEntry.registerAddListener(adaptor);
+ }
+
+
+
+ /**
+ * Register to be notified when a new child configurations is added
+ * beneath an optional relation.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The optional relation definition.
+ * @param listener
+ * The configuration add listener.
+ * @throws IllegalArgumentException
+ * If the optional relation definition is not associated
+ * with this managed object's definition.
+ */
+ public <M extends Configuration> void registerAddListener(
+ OptionalRelationDefinition<?, M> d,
+ ConfigurationAddListener<M> listener)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path,
+ d, listener);
+ configEntry.registerAddListener(adaptor);
+ }
+
+
+
+ /**
+ * Register to be notified when this server managed object is
+ * changed.
+ *
+ * @param listener
+ * The configuration change listener.
+ */
+ public void registerChangeListener(
+ ConfigurationChangeListener<? super S> listener) {
+ ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(
+ path, definition, listener);
+ configEntry.registerChangeListener(adaptor);
+ }
+
+
+
+ /**
+ * Register to be notified when existing child configurations are
+ * deleted beneath an instantiable relation.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The instantiable relation definition.
+ * @param listener
+ * The configuration delete listener.
+ * @throws IllegalArgumentException
+ * If the instantiable relation definition is not
+ * associated with this managed object's definition.
+ * @throws ConfigException
+ * If the configuration entry associated with the
+ * instantiable relation could not be retrieved.
+ */
+ public <M extends Configuration> void registerDeleteListener(
+ InstantiableRelationDefinition<?, M> d,
+ ConfigurationDeleteListener<M> listener)
+ throws IllegalArgumentException, ConfigException {
+ validateRelationDefinition(d);
+
+ DN baseDN = DNBuilder.create(path, d);
+ ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+
+ ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(
+ path, d, listener);
+ configEntry.registerDeleteListener(adaptor);
+ }
+
+
+
+ /**
+ * Register to be notified when an existing child configuration is
+ * deleted beneath an optional relation.
+ *
+ * @param <M>
+ * The type of the child server configuration object.
+ * @param d
+ * The optional relation definition.
+ * @param listener
+ * The configuration delete listener.
+ * @throws IllegalArgumentException
+ * If the optional relation definition is not associated
+ * with this managed object's definition.
+ */
+ public <M extends Configuration> void registerDeleteListener(
+ OptionalRelationDefinition<?, M> d,
+ ConfigurationDeleteListener<M> listener)
+ throws IllegalArgumentException {
+ validateRelationDefinition(d);
+
+ ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(
+ path, d, listener);
+ configEntry.registerDeleteListener(adaptor);
+ }
+
+
+
+ /**
+ * Update the config entry associated with this server managed
+ * object. This is only intended to be used by change listener call
+ * backs in order to update the managed object with the correct
+ * config entry.
+ *
+ * @param configEntry
+ * The configuration entry.
+ */
+ void setConfigEntry(ConfigEntry configEntry) {
+ this.configEntry = configEntry;
+ }
+
+
+
+ // Deregister an add listener.
+ private <M extends Configuration> void deregisterAddListener(
+ DN baseDN, ConfigurationAddListener<M> listener) {
+ try {
+ ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+ for (ConfigAddListener l : configEntry.getAddListeners()) {
+ if (l instanceof ConfigAddListenerAdaptor) {
+ ConfigAddListenerAdaptor adaptor = (ConfigAddListenerAdaptor) l;
+ if (adaptor.getConfigurationAddListener() == listener) {
+ configEntry.deregisterAddListener(adaptor);
+ }
+ }
+ }
+ } catch (ConfigException e) {
+ // Ignore the exception since this implies deregistration.
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
+ }
+
+
+
+ // Deregister a delete listener.
+ private <M> void deregisterDeleteListener(DN baseDN,
+ ConfigurationDeleteListener<M> listener) {
+ try {
+ ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+ for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+ if (l instanceof ConfigDeleteListenerAdaptor) {
+ ConfigDeleteListenerAdaptor adaptor = (ConfigDeleteListenerAdaptor) l;
+ if (adaptor.getConfigurationDeleteListener() == listener) {
+ configEntry.deregisterDeleteListener(adaptor);
+ }
+ }
+ }
+ } catch (ConfigException e) {
+ // Ignore the exception since this implies deregistration.
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
+ }
+
+
+
+ // Get a child managed object.
+ private <M extends Configuration> ServerManagedObject<? extends M> getChild(
+ ManagedObjectPath childPath, RelationDefinition<?, M> d)
+ throws ConfigException {
+ // Get the configuration entry.
+ DN targetDN = DNBuilder.create(childPath);
+ ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN);
+ try {
+ return decode(childPath, d.getChildDefinition(), configEntry);
+ } catch (DefinitionDecodingException e) {
+ throw ConfigExceptionFactory.getInstance()
+ .createDecodingExceptionAdaptor(targetDN, e);
+ } catch (ServerManagedObjectDecodingException e) {
+ throw ConfigExceptionFactory.getInstance()
+ .createDecodingExceptionAdaptor(e);
+ }
+ }
+
+
+
+ // Gets a config entry required for a listener and throws a config
+ // exception on failure.
+ private ConfigEntry getListenerConfigEntry(DN dn)
+ throws ConfigException {
+ // Attempt to retrieve the listener base entry.
+ ConfigEntry configEntry;
+ try {
+ configEntry = DirectoryServer.getConfigEntry(dn);
+ } catch (ConfigException e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_GET_LISTENER_BASE;
+ String message = getMessage(msgID, String.valueOf(dn),
+ stackTraceToSingleLineString(e));
+ throw new ConfigException(msgID, message, e);
+ }
+
+ // The configuration handler is free to return null indicating
+ // that the entry does not exist.
+ if (configEntry == null) {
+ int msgID = AdminMessages.MSGID_ADMIN_LISTENER_BASE_DOES_NOT_EXIST;
+ String message = getMessage(msgID, String.valueOf(dn));
+ throw new ConfigException(msgID, message);
+ }
+
+ return configEntry;
+ }
+
+
+
+ // Gets a config entry required for a managed object and throws a
+ // config exception on failure.
+ private ConfigEntry getManagedObjectConfigEntry(DN dn)
+ throws ConfigException {
+ ConfigEntry configEntry;
+ try {
+ configEntry = DirectoryServer.getConfigEntry(dn);
+ } catch (ConfigException e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = AdminMessages.MSGID_ADMIN_CANNOT_GET_MANAGED_OBJECT;
+ String message = getMessage(msgID, String.valueOf(dn),
+ stackTraceToSingleLineString(e));
+ throw new ConfigException(msgID, message, e);
+ }
+
+ // The configuration handler is free to return null indicating
+ // that the entry does not exist.
+ if (configEntry == null) {
+ int msgID = AdminMessages.MSGID_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST;
+ String message = getMessage(msgID, String.valueOf(dn));
+ throw new ConfigException(msgID, message);
+ }
+
+ return configEntry;
+ }
+
+
+
+ // Validate that a relation definition belongs to this managed
+ // object.
+ private void validateRelationDefinition(RelationDefinition<?, ?> rd)
+ throws IllegalArgumentException {
+ RelationDefinition tmp = definition.getRelationDefinition(rd
+ .getName());
+ if (tmp != rd) {
+ throw new IllegalArgumentException("The relation "
+ + rd.getName() + " is not associated with a "
+ + definition.getName());
+ }
+ }
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ServerManagedObjectDecodingException.java b/opends/src/server/org/opends/server/admin/server/ServerManagedObjectDecodingException.java
new file mode 100644
index 0000000..e477dee
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ServerManagedObjectDecodingException.java
@@ -0,0 +1,120 @@
+/*
+ * 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.admin.server;
+
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import org.opends.server.admin.DecodingException;
+import org.opends.server.admin.PropertyException;
+
+
+
+/**
+ * The requested server managed object was found but one or more of its
+ * properties could not be decoded successfully.
+ */
+public class ServerManagedObjectDecodingException extends DecodingException {
+
+ /**
+ * Version ID required by serializable classes.
+ */
+ private static final long serialVersionUID = 1598401431084729853L;
+
+ // The partially created server managed object.
+ private final ServerManagedObject<?> partialManagedObject;
+
+ // The exception(s) that caused this decoding exception.
+ private final Collection<PropertyException> causes;
+
+
+
+ /**
+ * Create a new property decoding exception.
+ *
+ * @param partialManagedObject
+ * The partially created server managed object containing properties
+ * which were successfully decoded and empty properties for those
+ * which were not (this may include empty mandatory properties).
+ * @param causes
+ * The exception(s) that caused this decoding exception.
+ */
+ public ServerManagedObjectDecodingException(
+ ServerManagedObject<?> partialManagedObject,
+ Collection<PropertyException> causes) {
+ this.partialManagedObject = partialManagedObject;
+ this.causes = Collections
+ .unmodifiableList(new LinkedList<PropertyException>(causes));
+ }
+
+
+
+ /**
+ * Get an unmodifiable collection view of the causes of this exception.
+ *
+ * @return Returns an unmodifiable collection view of the causes of this
+ * exception.
+ */
+ public Collection<PropertyException> getCauses() {
+ return causes;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("The managed object could not be decoded due"
+ + " to the following property exceptions: ");
+ // FIXME: better formatting.
+ builder.append(causes.toString());
+ return builder.toString();
+ }
+
+
+
+ /**
+ * Get the partially created server managed object containing properties which
+ * were successfully decoded and empty properties for those which were not
+ * (this may include empty mandatory properties).
+ *
+ * @return Returns the partially created server managed object containing
+ * properties which were successfully decoded and empty properties for
+ * those which were not (this may include empty mandatory properties).
+ */
+ public ServerManagedObject<?> getPartialManagedObject() {
+ return partialManagedObject;
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java b/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
new file mode 100644
index 0000000..ee0d9d5
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/ServerManagementContext.java
@@ -0,0 +1,83 @@
+/*
+ * 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.admin.server;
+
+
+
+import org.opends.server.admin.std.server.RootCfg;
+
+
+
+/**
+ * Server management connection context.
+ */
+public final class ServerManagementContext {
+
+ // Singleton instance.
+ private final static ServerManagementContext INSTANCE =
+ new ServerManagementContext();
+
+
+
+ /**
+ * Get the single server-side management context.
+ *
+ * @return Returns the single server-side management context.
+ */
+ public static ServerManagementContext getInstance() {
+ return INSTANCE;
+ }
+
+
+
+ /**
+ * Get the root configuration server managed object associated with
+ * this management context.
+ *
+ * @return Returns the root configuration server managed object
+ * associated with this management context.
+ */
+ public ServerManagedObject<RootCfg>
+ getRootConfigurationManagedObject() {
+ return ServerManagedObject.getRootManagedObject();
+ }
+
+
+
+ /**
+ * Get the root configuration manager associated with this
+ * management context.
+ *
+ * @return Returns the root configuration manager associated with
+ * this management context.
+ */
+ public RootCfg getRootConfiguration() {
+ return getRootConfigurationManagedObject().getConfiguration();
+ }
+
+}
diff --git a/opends/src/server/org/opends/server/admin/server/package-info.java b/opends/src/server/org/opends/server/admin/server/package-info.java
new file mode 100644
index 0000000..2eca7b0
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/server/package-info.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/**
+ * Server-side administration interface.
+ * <p>
+ * This package contains classes and interfaces which internal
+ * directory server components are expected to use in order to
+ * access the server's current configuration and register
+ * to be notified when the configuration changes.
+ */
+package org.opends.server.admin.server;
+
+
+
diff --git a/opends/src/server/org/opends/server/api/CertificateMapper.java b/opends/src/server/org/opends/server/api/CertificateMapper.java
index c0762fb..85538d2 100644
--- a/opends/src/server/org/opends/server/api/CertificateMapper.java
+++ b/opends/src/server/org/opends/server/api/CertificateMapper.java
@@ -30,7 +30,8 @@
import java.security.cert.Certificate;
-import org.opends.server.config.ConfigEntry;
+import org.opends.server.admin.std.server.
+ CertificateMapperCfg;
import org.opends.server.config.ConfigException;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
@@ -44,19 +45,19 @@
* implemented by a Directory Server module that implements the
* functionality required to uniquely map an SSL client certificate to
* a Directory Server user entry.
+ *
+ * @param <T> The type of configuration handled by this certificate
+ * mapper.
*/
public abstract class CertificateMapper
+ <T extends CertificateMapperCfg>
{
-
-
-
/**
* Initializes this certificate mapper based on the information in
* the provided configuration entry.
*
- * @param configEntry The configuration entry that contains the
- * information to use to initialize this
- * certificate mapper.
+ * @param configuration The configuration that should be used to
+ * intialize this certificate mapper.
*
* @throws ConfigException If the provided entry does not contain
* a valid certificate mapper
@@ -67,8 +68,7 @@
* related to the server
* configuration.
*/
- public abstract void initializeCertificateMapper(
- ConfigEntry configEntry)
+ public abstract void initializeCertificateMapper(T configuration)
throws ConfigException, InitializationException;
diff --git a/opends/src/server/org/opends/server/api/ConnectionHandler.java b/opends/src/server/org/opends/server/api/ConnectionHandler.java
index aa08754..dc946ab 100644
--- a/opends/src/server/org/opends/server/api/ConnectionHandler.java
+++ b/opends/src/server/org/opends/server/api/ConnectionHandler.java
@@ -29,7 +29,8 @@
import java.util.Collection;
-import org.opends.server.config.ConfigEntry;
+
+import org.opends.server.admin.std.server.*;
import org.opends.server.config.ConfigException;
import org.opends.server.monitors.ConnectionHandlerMonitor;
import org.opends.server.types.HostPort;
@@ -37,16 +38,17 @@
-
/**
* This class defines the set of methods and structures that must be
* implemented by a Directory Server connection handler.
+ *
+ * @param <T>
+ * The type of connection handler configuration handled by
+ * this connection handler implementation.
*/
public abstract class ConnectionHandler
- extends DirectoryThread
-{
-
-
+ <T extends ConnectionHandlerCfg>
+ extends DirectoryThread {
// The monitor associated with this connection handler.
private ConnectionHandlerMonitor monitor;
@@ -54,15 +56,15 @@
/**
- * Creates a new instance of this connection handler. This must be
+ * Creates a new instance of this connection handler. This must be
* called by all connection handlers, and all connection handlers
* must provide default constructors (i.e., those that do not take
* any arguments) that invoke this constructor.
*
- * @param threadName The name to use for this thread.
+ * @param threadName
+ * The name to use for this thread.
*/
- protected ConnectionHandler(String threadName)
- {
+ protected ConnectionHandler(String threadName) {
super(threadName);
monitor = null;
@@ -71,46 +73,24 @@
/**
- * Initializes this connection handler based on the information in
- * the provided configuration entry.
- *
- * @param configEntry The configuration entry that contains the
- * information to use to initialize this
- * connection handler.
- *
- * @throws ConfigException If there is a problem with the
- * configuration for this connection
- * handler.
- *
- * @throws InitializationException If a problem occurs while
- * attempting to initialize this
- * connection handler.
- */
- public abstract void initializeConnectionHandler(
- ConfigEntry configEntry)
- throws ConfigException, InitializationException;
-
-
-
- /**
* Closes this connection handler so that it will no longer accept
- * new client connections. It may or may not disconnect existing
- * client connections based on the provided flag. Note, however,
+ * new client connections. It may or may not disconnect existing
+ * client connections based on the provided flag. Note, however,
* that some connection handler implementations may not have any way
* to continue processing requests from existing connections, in
* which case they should always be closed regardless of the value
* of the <CODE>closeConnections</CODE> flag.
*
- * @param finalizeReason The reason that this connection handler
- * should be finalized.
- * @param closeConnections Indicates whether any established
- * client connections associated with the
- * connection handler should also be
- * closed.
+ * @param finalizeReason
+ * The reason that this connection handler should be
+ * finalized.
+ * @param closeConnections
+ * Indicates whether any established client connections
+ * associated with the connection handler should also be
+ * closed.
*/
public abstract void finalizeConnectionHandler(
- String finalizeReason,
- boolean closeConnections);
+ String finalizeReason, boolean closeConnections);
@@ -156,14 +136,35 @@
* Retrieves the set of active client connections that have been
* established through this connection handler.
*
- * @return The set of active client connections that have been
- * established through this connection handler.
+ * @return The set of active client connections that have been
+ * established through this connection handler.
*/
public abstract Collection<ClientConnection> getClientConnections();
/**
+ * Initializes this connection handler provider based on the
+ * information in the provided connection handler configuration.
+ *
+ * @param configuration
+ * The connection handler configuration that contains the
+ * information to use to initialize this connection
+ * handler.
+ * @throws ConfigException
+ * If an unrecoverable problem arises in the process of
+ * performing the initialization as a result of the server
+ * configuration.
+ * @throws InitializationException
+ * If a problem occurs during initialization that is not
+ * related to the server configuration.
+ */
+ public abstract void initializeConnectionHandler(T configuration)
+ throws ConfigException, InitializationException;
+
+
+
+ /**
* Operates in a loop, accepting new connections and ensuring that
* requests on those connections are handled properly.
*/
@@ -201,10 +202,9 @@
/**
* Retrieves a string representation of this connection handler.
*
- * @return A string representation of this connection handler.
+ * @return A string representation of this connection handler.
*/
- public String toString()
- {
+ public String toString() {
StringBuilder buffer = new StringBuilder();
toString(buffer);
return buffer.toString();
@@ -216,9 +216,8 @@
* Appends a string representation of this connection handler to the
* provided buffer.
*
- * @param buffer The buffer to which the information should be
- * appended.
+ * @param buffer
+ * The buffer to which the information should be appended.
*/
public abstract void toString(StringBuilder buffer);
}
-
diff --git a/opends/src/server/org/opends/server/api/IdentityMapper.java b/opends/src/server/org/opends/server/api/IdentityMapper.java
index ee7656d..b7f06be 100644
--- a/opends/src/server/org/opends/server/api/IdentityMapper.java
+++ b/opends/src/server/org/opends/server/api/IdentityMapper.java
@@ -28,7 +28,7 @@
-import org.opends.server.config.ConfigEntry;
+import org.opends.server.admin.std.server.IdentityMapperCfg;
import org.opends.server.config.ConfigException;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
@@ -36,7 +36,6 @@
-
/**
* This class defines the set of methods and structures that must be
* implemented by a Directory Server identity mapper. An identity
@@ -45,19 +44,18 @@
* mechanisms to identify the user that is authenticating to the
* server. It may also be used in other areas, like in conjunction
* with the proxied authorization control.
+ *
+ * @param <T> The type of configuration handled by this identity
+ * mapper.
*/
public abstract class IdentityMapper
+ <T extends IdentityMapperCfg>
{
-
-
-
/**
* Initializes this identity mapper based on the information in the
* provided configuration entry.
*
- * @param configEntry The configuration entry that contains the
- * information to use to initialize this
- * identity mapper.
+ * @param configuration The configuration for the identity mapper.
*
* @throws ConfigException If an unrecoverable problem arises in
* the process of performing the
@@ -68,8 +66,7 @@
* related to the server
* configuration.
*/
- public abstract void initializeIdentityMapper(
- ConfigEntry configEntry)
+ public abstract void initializeIdentityMapper(T configuration)
throws ConfigException, InitializationException;
diff --git a/opends/src/server/org/opends/server/api/KeyManagerProvider.java b/opends/src/server/org/opends/server/api/KeyManagerProvider.java
index 8e84dec..dbbbcb0 100644
--- a/opends/src/server/org/opends/server/api/KeyManagerProvider.java
+++ b/opends/src/server/org/opends/server/api/KeyManagerProvider.java
@@ -30,6 +30,7 @@
import javax.net.ssl.KeyManager;
+import org.opends.server.admin.std.server.KeyManagerCfg;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.DirectoryException;
@@ -41,8 +42,13 @@
* This class defines an API that may be used to obtain a set of
* <CODE>javax.net.ssl.KeyManager</CODE> objects for use when
* performing SSL communication.
+ *
+ * @param <T>
+ * The type of key manager provider configuration handled by
+ * this key manager provider implementation.
*/
public abstract class KeyManagerProvider
+ <T extends KeyManagerCfg>
{
/**
* Initializes this key manager provider based on the information in
@@ -69,6 +75,27 @@
/**
+ * Initializes this key manager provider based on the information in
+ * the provided key manager provider configuration.
+ *
+ * @param configuration
+ * The key manager provider configuration that contains the
+ * information to use to initialize this key manager
+ * provider.
+ * @throws ConfigException
+ * If an unrecoverable problem arises in the process of
+ * performing the initialization as a result of the server
+ * configuration.
+ * @throws InitializationException
+ * If a problem occurs during initialization that is not
+ * related to the server configuration.
+ */
+ public abstract void initializeKeyManagerProvider(T configuration)
+ throws ConfigException, InitializationException;
+
+
+
+ /**
* Performs any finalization that may be necessary for this key
* manager provider.
*/
diff --git a/opends/src/server/org/opends/server/api/PasswordValidator.java b/opends/src/server/org/opends/server/api/PasswordValidator.java
index 85d32a9..9e0b255 100644
--- a/opends/src/server/org/opends/server/api/PasswordValidator.java
+++ b/opends/src/server/org/opends/server/api/PasswordValidator.java
@@ -30,7 +30,8 @@
import java.util.Set;
-import org.opends.server.config.ConfigEntry;
+import org.opends.server.admin.std.server.
+ PasswordValidatorCfg;
import org.opends.server.config.ConfigException;
import org.opends.server.core.Operation;
import org.opends.server.types.ByteString;
@@ -39,24 +40,23 @@
-
/**
* This class defines the set of methods and structures that must be
* implemented by a Directory Server module that may be used to
* determine whether a proposed password is acceptable for a user.
+ *
+ * @param <T> The type of configuration handled by this password
+ * validator.
*/
public abstract class PasswordValidator
+ <T extends PasswordValidatorCfg>
{
-
-
-
/**
* Initializes this password validator based on the information in
* the provided configuration entry.
*
- * @param configEntry The configuration entry that contains the
- * information to use to initialize this
- * password validator.
+ * @param configuration The configuration to use to initialize
+ * this password validator.
*
* @throws ConfigException If an unrecoverable problem arises in
* the process of performing the
@@ -67,8 +67,7 @@
* related to the server
* configuration.
*/
- public abstract void initializePasswordValidator(
- ConfigEntry configEntry)
+ public abstract void initializePasswordValidator(T configuration)
throws ConfigException, InitializationException;
diff --git a/opends/src/server/org/opends/server/api/SASLMechanismHandler.java b/opends/src/server/org/opends/server/api/SASLMechanismHandler.java
index bf6aa0d..b01e923 100644
--- a/opends/src/server/org/opends/server/api/SASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/api/SASLMechanismHandler.java
@@ -28,7 +28,8 @@
-import org.opends.server.config.ConfigEntry;
+import org.opends.server.admin.std.server.
+ SASLMechanismHandlerCfg;
import org.opends.server.config.ConfigException;
import org.opends.server.core.BindOperation;
import org.opends.server.types.InitializationException;
@@ -40,21 +41,21 @@
* This class defines the set of methods and structures that must be
* implemented by a Directory Server module that implements the
* functionality required for one or more SASL mechanisms.
+ *
+ * @param <T> The type of configuration handled by this SASL
+ * mechanism handler.
*/
public abstract class SASLMechanismHandler
+ <T extends SASLMechanismHandlerCfg>
{
-
-
-
/**
* Initializes this SASL mechanism handler based on the information
* in the provided configuration entry. It should also register
* itself with the Directory Server for the particular kinds of SASL
* mechanisms that it will process.
*
- * @param configEntry The configuration entry that contains the
- * information to use to initialize this SASL
- * mechanism handler.
+ * @param configuration The configuration to use to initialize
+ * this SASL mechanism handler.
*
* @throws ConfigException If an unrecoverable problem arises in
* the process of performing the
@@ -65,8 +66,7 @@
* related to the server
* configuration.
*/
- public abstract void initializeSASLMechanismHandler(
- ConfigEntry configEntry)
+ public abstract void initializeSASLMechanismHandler(T configuration)
throws ConfigException, InitializationException;
diff --git a/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java b/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
index 98a0050..5af25db 100644
--- a/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
+++ b/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
@@ -30,8 +30,8 @@
import java.util.Set;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.ClientConnection;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
@@ -55,12 +55,12 @@
* class that may be used for all types of plugins, and an individual
* plugin only needs to implement the specific methods that are
* applicable to that particular plugin type.
+ *
+ * @param <T> The type of configuration handled by this plugin.
*/
public abstract class DirectoryServerPlugin
+ <T extends PluginCfg>
{
-
-
-
// The DN of the configuration entry for this plugin.
private DN pluginDN;
@@ -105,10 +105,9 @@
* be called as soon as the plugin has been loaded and before it is
* registered with the server.
*
- * @param pluginTypes The set of plugin types that indicate the
- * ways in which this plugin will be invoked.
- * @param configEntry The entry containing the configuration
- * information for this plugin.
+ * @param pluginTypes The set of plugin types that indicate the
+ * ways in which this plugin will be invoked.
+ * @param configuration The configuration for this plugin.
*
* @throws ConfigException If the provided entry does not contain
* a valid configuration for this plugin.
@@ -119,7 +118,7 @@
* configuration.
*/
public abstract void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ T configuration)
throws ConfigException, InitializationException;
diff --git a/opends/src/server/org/opends/server/backends/task/RecurringTask.java b/opends/src/server/org/opends/server/backends/task/RecurringTask.java
index 784cf3f..5545228 100644
--- a/opends/src/server/org/opends/server/backends/task/RecurringTask.java
+++ b/opends/src/server/org/opends/server/backends/task/RecurringTask.java
@@ -206,8 +206,7 @@
Class taskClass;
try
{
- // FIXME -- Should this use a custom class loader?
- taskClass = Class.forName(taskClassName);
+ taskClass = DirectoryServer.loadClass(taskClassName);
}
catch (Exception e)
{
diff --git a/opends/src/server/org/opends/server/backends/task/TaskScheduler.java b/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
index e8d21ad..3294a46 100644
--- a/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
+++ b/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
@@ -1830,8 +1830,7 @@
Class taskClass;
try
{
- // FIXME -- Should we use a custom class loader for this?
- taskClass = Class.forName(taskClassName);
+ taskClass = DirectoryServer.loadClass(taskClassName);
}
catch (Exception e)
{
diff --git a/opends/src/server/org/opends/server/core/AccessControlConfigManager.java b/opends/src/server/org/opends/server/core/AccessControlConfigManager.java
index 3d16723..40325b0 100644
--- a/opends/src/server/org/opends/server/core/AccessControlConfigManager.java
+++ b/opends/src/server/org/opends/server/core/AccessControlConfigManager.java
@@ -507,7 +507,7 @@
// Load the access control implementation class.
String className = classAttr.activeValue();
try {
- return Class.forName(className).asSubclass(
+ return DirectoryServer.loadClass(className).asSubclass(
AccessControlProvider.class);
} catch (ClassNotFoundException e) {
if (debugEnabled())
diff --git a/opends/src/server/org/opends/server/core/AccountStatusNotificationHandlerConfigManager.java b/opends/src/server/org/opends/server/core/AccountStatusNotificationHandlerConfigManager.java
index 3bb5dd2..3b2d68d 100644
--- a/opends/src/server/org/opends/server/core/AccountStatusNotificationHandlerConfigManager.java
+++ b/opends/src/server/org/opends/server/core/AccountStatusNotificationHandlerConfigManager.java
@@ -59,7 +59,6 @@
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
@@ -278,8 +277,7 @@
Class handlerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- handlerClass = Class.forName(classNameAttr.pendingValue());
+ handlerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -526,8 +524,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class handlerClass = Class.forName(className);
+ Class handlerClass = DirectoryServer.loadClass(className);
handler = (AccountStatusNotificationHandler) handlerClass.newInstance();
}
catch (Exception e)
@@ -655,8 +652,7 @@
Class handlerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- handlerClass = Class.forName(classNameAttr.pendingValue());
+ handlerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -877,8 +873,7 @@
AccountStatusNotificationHandler handler;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class handlerClass = Class.forName(className);
+ Class handlerClass = DirectoryServer.loadClass(className);
handler = (AccountStatusNotificationHandler) handlerClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/AddOperation.java b/opends/src/server/org/opends/server/core/AddOperation.java
index f84653d..25e398f 100644
--- a/opends/src/server/org/opends/server/core/AddOperation.java
+++ b/opends/src/server/org/opends/server/core/AddOperation.java
@@ -2379,7 +2379,7 @@
// There are never any current passwords for an add operation.
HashSet<ByteString> currentPasswords = new HashSet<ByteString>(0);
StringBuilder invalidReason = new StringBuilder();
- for (PasswordValidator validator :
+ for (PasswordValidator<?> validator :
passwordPolicy.getPasswordValidators().values())
{
if (! validator.passwordIsAcceptable(value, currentPasswords, this,
diff --git a/opends/src/server/org/opends/server/core/BackendConfigManager.java b/opends/src/server/org/opends/server/core/BackendConfigManager.java
index be51a4d..f150fd8 100644
--- a/opends/src/server/org/opends/server/core/BackendConfigManager.java
+++ b/opends/src/server/org/opends/server/core/BackendConfigManager.java
@@ -446,8 +446,7 @@
Backend backend;
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class backendClass = Class.forName(className);
+ Class backendClass = DirectoryServer.loadClass(className);
backend = (Backend) backendClass.newInstance();
}
catch (Exception e)
@@ -890,8 +889,7 @@
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class backendClass = Class.forName(className);
+ Class backendClass = DirectoryServer.loadClass(className);
if (! Backend.class.isAssignableFrom(backendClass))
{
msgID = MSGID_CONFIG_BACKEND_CLASS_NOT_BACKEND;
@@ -1270,8 +1268,7 @@
// implementation.
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class backendClass = Class.forName(className);
+ Class backendClass = DirectoryServer.loadClass(className);
if (Backend.class.isAssignableFrom(backendClass))
{
// It appears to be a valid backend class. We'll return that the
@@ -1320,8 +1317,7 @@
{
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class backendClass = Class.forName(className);
+ Class backendClass = DirectoryServer.loadClass(className);
backend = (Backend) backendClass.newInstance();
}
catch (Exception e)
@@ -1730,8 +1726,7 @@
Backend backend;
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class backendClass = Class.forName(className);
+ Class backendClass = DirectoryServer.loadClass(className);
backend = (Backend) backendClass.newInstance();
}
catch (Exception e)
@@ -2107,8 +2102,7 @@
Backend backend;
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class backendClass = Class.forName(className);
+ Class backendClass = DirectoryServer.loadClass(className);
backend = (Backend) backendClass.newInstance();
}
catch (Exception e)
@@ -2408,7 +2402,7 @@
{
int msgID = MSGID_CONFIG_BACKEND_CANNOT_REMOVE_BACKEND_WITH_SUBORDINATES;
messages.add(getMessage(msgID, String.valueOf(backendDN)));
- resultCode = resultCode.UNWILLING_TO_PERFORM;
+ resultCode = ResultCode.UNWILLING_TO_PERFORM;
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
}
diff --git a/opends/src/server/org/opends/server/core/CertificateMapperConfigManager.java b/opends/src/server/org/opends/server/core/CertificateMapperConfigManager.java
index 1659955..c79315d 100644
--- a/opends/src/server/org/opends/server/core/CertificateMapperConfigManager.java
+++ b/opends/src/server/org/opends/server/core/CertificateMapperConfigManager.java
@@ -28,22 +28,21 @@
+import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.admin.std.meta.CertificateMapperCfgDefn;
+import org.opends.server.admin.std.server.CertificateMapperCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.api.CertificateMapper;
-import org.opends.server.api.ConfigAddListener;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.api.ConfigHandler;
-import org.opends.server.api.ConfigurableComponent;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.ErrorLogCategory;
@@ -51,14 +50,10 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
@@ -66,21 +61,18 @@
* This class defines a utility that will be used to manage the set of
* certificate mappers defined in the Directory Server. It will initialize the
* certificate mappers when the server starts, and then will manage any
- * additions, removals, or modifications of any certificate mappers while the
+ * additions, removals, or modifications to any certificate mappers while the
* server is running.
*/
public class CertificateMapperConfigManager
- implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
+ implements ConfigurationChangeListener<CertificateMapperCfg>,
+ ConfigurationAddListener<CertificateMapperCfg>,
+ ConfigurationDeleteListener<CertificateMapperCfg>
+
{
-
-
-
// A mapping between the DNs of the config entries and the associated
// certificate mappers.
- private ConcurrentHashMap<DN,CertificateMapper> mappers;
-
- // The configuration handler for the Directory Server.
- private ConfigHandler configHandler;
+ private ConcurrentHashMap<DN,CertificateMapper> certificateMappers;
@@ -89,8 +81,7 @@
*/
public CertificateMapperConfigManager()
{
- configHandler = DirectoryServer.getConfigHandler();
- mappers = new ConcurrentHashMap<DN,CertificateMapper>();
+ certificateMappers = new ConcurrentHashMap<DN,CertificateMapper>();
}
@@ -110,858 +101,319 @@
public void initializeCertificateMappers()
throws ConfigException, InitializationException
{
- // First, get the configuration base entry.
- ConfigEntry baseEntry;
- try
+ // 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 certificate mapper entries are added or removed.
+ rootConfiguration.addCertificateMapperAddListener(this);
+ rootConfiguration.addCertificateMapperDeleteListener(this);
+
+
+ //Initialize the existing certificate mappers.
+ for (String mapperName : rootConfiguration.listCertificateMappers())
{
- DN certMapperBase = DN.decode(DN_CERTMAPPER_CONFIG_BASE);
- baseEntry = configHandler.getConfigEntry(certMapperBase);
- }
- catch (Exception e)
- {
- if (debugEnabled())
+ CertificateMapperCfg mapperConfiguration =
+ rootConfiguration.getCertificateMapper(mapperName);
+ mapperConfiguration.addChangeListener(this);
+
+ if (mapperConfiguration.isEnabled())
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_CANNOT_GET_BASE;
- String message = getMessage(msgID, String.valueOf(e));
- throw new ConfigException(msgID, message, e);
- }
-
- if (baseEntry == null)
- {
- // The certificate mapper base entry does not exist. This is not
- // acceptable, so throw an exception.
- int msgID = MSGID_CONFIG_CERTMAPPER_BASE_DOES_NOT_EXIST;
- String message = getMessage(msgID);
- throw new ConfigException(msgID, message);
- }
-
-
- // Register add and delete listeners with the certificate mapper base entry.
- // We don't care about modifications to it.
- baseEntry.registerAddListener(this);
- baseEntry.registerDeleteListener(this);
-
-
- // See if the base entry has any children. If not, then we don't need to do
- // anything else.
- if (! baseEntry.hasChildren())
- {
- return;
- }
-
-
- // Iterate through the child entries and process them as certificate mapper
- // configuration entries.
- for (ConfigEntry childEntry : baseEntry.getChildren().values())
- {
- childEntry.registerChangeListener(this);
-
- StringBuilder unacceptableReason = new StringBuilder();
- if (! configAddIsAcceptable(childEntry, unacceptableReason))
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_CERTMAPPER_ENTRY_UNACCEPTABLE,
- childEntry.getDN().toString(), unacceptableReason.toString());
- continue;
- }
-
- try
- {
- ConfigChangeResult result = applyConfigurationAdd(childEntry);
- if (result.getResultCode() != ResultCode.SUCCESS)
+ String className = mapperConfiguration.getMapperClass();
+ try
{
- StringBuilder buffer = new StringBuilder();
-
- List<String> resultMessages = result.getMessages();
- if ((resultMessages == null) || (resultMessages.isEmpty()))
- {
- buffer.append(getMessage(MSGID_CONFIG_UNKNOWN_UNACCEPTABLE_REASON));
- }
- else
- {
- Iterator<String> iterator = resultMessages.iterator();
-
- buffer.append(iterator.next());
- while (iterator.hasNext())
- {
- buffer.append(EOL);
- buffer.append(iterator.next());
- }
- }
-
+ CertificateMapper mapper = loadMapper(className, mapperConfiguration);
+ certificateMappers.put(mapperConfiguration.dn(), mapper);
+ DirectoryServer.registerCertificateMapper(mapperConfiguration.dn(),
+ mapper);
+ }
+ catch (InitializationException ie)
+ {
logError(ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_CERTMAPPER_CANNOT_CREATE_MAPPER,
- childEntry.getDN().toString(), buffer.toString());
+ ie.getMessage(), ie.getMessageID());
+ continue;
}
}
- catch (Exception e)
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_CERTMAPPER_CANNOT_CREATE_MAPPER,
- childEntry.getDN().toString(), String.valueOf(e));
- }
}
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * modification is acceptable to this change listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested update.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed change is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configChangeIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationAddAcceptable(
+ CertificateMapperCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that the entry has an appropriate objectclass for a certificate
- // mapper.
- if (! configEntry.hasObjectClass(OC_CERTIFICATE_MAPPER))
+ if (configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the mapper class name.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CERTMAPPER_CLASS,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_CLASS),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
+ // Get the name of the class and make sure we can instantiate it as a
+ // certificate mapper.
+ String className = configuration.getMapperClass();
+ try
{
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
+ loadMapper(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
return false;
}
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class mapperClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- mapperClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- try
- {
- CertificateMapper mapper = (CertificateMapper) mapperClass.newInstance();
- }
- catch(Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS;
- String message = getMessage(msgID, mapperClass.getName(),
- String.valueOf(configEntry.getDN()),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // See if this certificate mapper should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CERTMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the certificate mapper entry appears to be
- // acceptable.
+ // If we've gotten here, then it's fine.
return true;
}
/**
- * Attempts to apply a new configuration to this Directory Server component
- * based on the provided changed entry.
- *
- * @param configEntry The configuration entry that containing the updated
- * configuration for this component.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationAdd(
+ CertificateMapperCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
+ configuration.addChangeListener(this);
- // Make sure that the entry has an appropriate objectclass for a certificate
- // mapper.
- if (! configEntry.hasObjectClass(OC_CERTIFICATE_MAPPER))
+ if (! configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
+ CertificateMapper certificateMapper = null;
- // Get the corresponding certificate mapper if it is active.
- CertificateMapper mapper = mappers.get(configEntryDN);
-
-
- // See if this mapper should be enabled or disabled.
- boolean needsEnabled = false;
- BooleanConfigAttribute enabledAttr;
+ // Get the name of the class and make sure we can instantiate it as a
+ // certificate mapper.
+ String className = configuration.getMapperClass();
try
{
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CERTMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- if (enabledAttr.activeValue())
- {
- if (mapper == null)
- {
- needsEnabled = true;
- }
- else
- {
- // The mapper is already active, so no action is required.
- }
- }
- else
- {
- if (mapper == null)
- {
- // The mapper is already disabled, so no action is required and we
- // can short-circuit out of this processing.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- // The mapper is active, so it needs to be disabled. Do this and
- // return that we were successful.
- mappers.remove(configEntryDN);
- DirectoryServer.deregisterCertificateMapper(configEntryDN);
- mapper.finalizeCertificateMapper();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
+ certificateMapper = loadMapper(className, configuration);
}
- catch (Exception e)
+ catch (InitializationException ie)
{
- if (debugEnabled())
+ if (resultCode == ResultCode.SUCCESS)
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the mapper class name. If it has
- // changed, then we will not try to dynamically apply it.
- String className;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CERTMAPPER_CLASS,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_CLASS),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- className = classNameAttr.pendingValue();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- boolean classChanged = false;
- String oldClassName = null;
- if (mapper != null)
- {
- oldClassName = mapper.getClass().getName();
- classChanged = (! className.equals(oldClassName));
- }
-
-
- if (classChanged)
- {
- // This will not be applied dynamically. Add a message to the response
- // and indicate that admin action is required.
- adminActionRequired = true;
- messages.add(getMessage(MSGID_CONFIG_CERTMAPPER_CLASS_ACTION_REQUIRED,
- String.valueOf(oldClassName),
- String.valueOf(className),
- String.valueOf(configEntryDN)));
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- if (needsEnabled)
- {
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class mapperClass = Class.forName(className);
- mapper = (CertificateMapper) mapperClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
}
- try
- {
- mapper.initializeCertificateMapper(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
-
- mappers.put(configEntryDN, mapper);
- DirectoryServer.registerCertificateMapper(configEntryDN, mapper);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ messages.add(ie.getMessage());
}
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ certificateMappers.put(configuration.dn(), certificateMapper);
+ DirectoryServer.registerCertificateMapper(configuration.dn(),
+ certificateMapper);
+ }
- // If we've gotten here, then there haven't been any changes to anything
- // that we care about.
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * add is acceptable to this add listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested add.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed entry is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configAddIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationDeleteAcceptable(
+ CertificateMapperCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that no entry already exists with the specified DN.
- DN configEntryDN = configEntry.getDN();
- if (mappers.containsKey(configEntryDN))
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_EXISTS;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry has an appropriate objectclass for a certificate
- // mapper.
- if (! configEntry.hasObjectClass(OC_CERTIFICATE_MAPPER))
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the certificate mapper class.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CERTMAPPER_CLASS,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_CLASS),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class mapperClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- mapperClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- CertificateMapper mapper;
- try
- {
- mapper = (CertificateMapper) mapperClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS;
- String message = getMessage(msgID, mapperClass.getName(),
- String.valueOf(configEntryDN),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // See if this mapper should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CERTMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- else if (! enabledAttr.pendingValue())
- {
- // The certificate mapper is not enabled so we don't need to do any
- // further validation.
- return true;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If the mapper is a configurable component, then make sure that its
- // configuration is valid.
- if (mapper instanceof ConfigurableComponent)
- {
- ConfigurableComponent cc = (ConfigurableComponent) mapper;
- LinkedList<String> errorMessages = new LinkedList<String>();
- if (! cc.hasAcceptableConfiguration(configEntry, errorMessages))
- {
- if (errorMessages.isEmpty())
- {
- int msgID = MSGID_CONFIG_CERTMAPPER_UNACCEPTABLE_CONFIG;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
- else
- {
- Iterator<String> iterator = errorMessages.iterator();
- unacceptableReason.append(iterator.next());
- while (iterator.hasNext())
- {
- unacceptableReason.append(" ");
- unacceptableReason.append(iterator.next());
- }
- }
-
- return false;
- }
- }
-
-
- // If we've gotten here then the mapper entry appears to be acceptable.
+ // FIXME -- We should try to perform some check to determine whether the
+ // certificate mapper is in use.
return true;
}
/**
- * Attempts to apply a new configuration based on the provided added entry.
- *
- * @param configEntry The new configuration entry that contains the
- * configuration to apply.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationDelete(
+ CertificateMapperCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ DirectoryServer.deregisterCertificateMapper(configuration.dn());
+
+ CertificateMapper certificateMapper =
+ certificateMappers.remove(configuration.dn());
+ if (certificateMapper != null)
+ {
+ certificateMapper.finalizeCertificateMapper();
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ CertificateMapperCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ if (configuration.isEnabled())
+ {
+ // Get the name of the class and make sure we can instantiate it as a
+ // certificate mapper.
+ String className = configuration.getMapperClass();
+ try
+ {
+ loadMapper(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
+ return false;
+ }
+ }
+
+ // If we've gotten here, then it's fine.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ CertificateMapperCfg configuration)
+ {
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
- // Make sure that the entry has an appropriate objectclass for a certificate
- // mapper.
- if (! configEntry.hasObjectClass(OC_CERTIFICATE_MAPPER))
+ // Get the existing mapper if it's already enabled.
+ CertificateMapper existingMapper =
+ certificateMappers.get(configuration.dn());
+
+
+ // If the new configuration has the mapper disabled, then disable it if it
+ // is enabled, or do nothing if it's already disabled.
+ if (! configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_OBJECTCLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
+ if (existingMapper != null)
+ {
+ DirectoryServer.deregisterCertificateMapper(configuration.dn());
+
+ CertificateMapper certificateMapper =
+ certificateMappers.remove(configuration.dn());
+ if (certificateMapper != null)
+ {
+ certificateMapper.finalizeCertificateMapper();
+ }
+ }
+
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
- // See if this mapper should be enabled or disabled.
- BooleanConfigAttribute enabledAttr;
- try
+ // Get the class for the certificate mapper. If the mapper is already
+ // enabled, then we shouldn't do anything with it although if the class has
+ // changed then we'll at least need to indicate that administrative action
+ // is required. If the mapper is disabled, then instantiate the class and
+ // initialize and register it as a certificate mapper.
+ String className = configuration.getMapperClass();
+ if (existingMapper != null)
{
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CERTMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
+ if (! className.equals(existingMapper.getClass().getName()))
{
- // The attribute doesn't exist, so it will be disabled by default.
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.SUCCESS;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else if (! enabledAttr.activeValue())
- {
- // It is explicitly configured as disabled, so we don't need to do
- // anything.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
+ adminActionRequired = true;
}
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
-
- // Make sure that the entry specifies the mapper class name.
- String className;
+ CertificateMapper certificateMapper = null;
try
{
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CERTMAPPER_CLASS,
- getMessage(MSGID_CONFIG_CERTMAPPER_DESCRIPTION_CLASS),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
+ certificateMapper = loadMapper(className, configuration);
+ }
+ catch (InitializationException ie)
+ {
+ if (resultCode == ResultCode.SUCCESS)
{
- int msgID = MSGID_CONFIG_CERTMAPPER_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
+ resultCode = DirectoryServer.getServerErrorResultCode();
}
- className = classNameAttr.pendingValue();
+ messages.add(ie.getMessage());
+ }
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ certificateMappers.put(configuration.dn(), certificateMapper);
+ DirectoryServer.registerCertificateMapper(configuration.dn(),
+ certificateMapper);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * Loads the specified class, instantiates it as a certificate mapper, and
+ * optionally initializes that instance.
+ *
+ * @param className The fully-qualified name of the certificate mapper
+ * class to load, instantiate, and initialize.
+ * @param configuration The configuration to use to initialize the
+ * certificate mapper, or {@code null} if the
+ * certificate mapper should not be initialized.
+ *
+ * @return The possibly initialized certificate mapper.
+ *
+ * @throws InitializationException If a problem occurred while attempting to
+ * initialize the certificate mapper.
+ */
+ private CertificateMapper loadMapper(String className,
+ CertificateMapperCfg configuration)
+ throws InitializationException
+ {
+ try
+ {
+ CertificateMapperCfgDefn definition =
+ CertificateMapperCfgDefn.getInstance();
+ ClassPropertyDefinition propertyDefinition =
+ definition.getMapperClassPropertyDefinition();
+ Class<? extends CertificateMapper> mapperClass =
+ propertyDefinition.loadClass(className, CertificateMapper.class);
+ CertificateMapper mapper = mapperClass.newInstance();
+
+ if (configuration != null)
+ {
+ Method method =
+ mapper.getClass().getMethod("initializeCertificateMapper",
+ configuration.definition().getServerConfigurationClass());
+ method.invoke(mapper, configuration);
+ }
+
+ return mapper;
}
catch (Exception e)
{
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Load and initialize the mapper class, and register it with the Directory
- // Server.
- CertificateMapper mapper;
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class mapperClass = Class.forName(className);
- mapper = (CertificateMapper) mapperClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_CERTMAPPER_INVALID_CLASS;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
- try
- {
- mapper.initializeCertificateMapper(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
int msgID = MSGID_CONFIG_CERTMAPPER_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ String message = getMessage(msgID, className,
+ String.valueOf(configuration.dn()),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
}
-
-
- mappers.put(configEntryDN, mapper);
- DirectoryServer.registerCertificateMapper(configEntryDN, mapper);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
- * Indicates whether it is acceptable to remove the provided configuration
- * entry.
- *
- * @param configEntry The configuration entry that will be removed
- * from the configuration.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed delete is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry may be removed from the
- * configuration, or <CODE>false</CODE> if not.
- */
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- // A delete should always be acceptable, so just return true.
- return true;
- }
-
-
-
- /**
- * Attempts to apply a new configuration based on the provided deleted entry.
- *
- * @param configEntry The new configuration entry that has been deleted.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry)
- {
- DN configEntryDN = configEntry.getDN();
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
-
-
- // See if the entry is registered as a certificate mapper. If so,
- // deregister it and stop the mapper.
- CertificateMapper mapper = mappers.remove(configEntryDN);
- if (mapper != null)
- {
- DirectoryServer.deregisterCertificateMapper(configEntryDN);
- mapper.finalizeCertificateMapper();
- }
-
-
- return new ConfigChangeResult(resultCode, adminActionRequired);
}
}
diff --git a/opends/src/server/org/opends/server/core/ConnectionHandlerConfigManager.java b/opends/src/server/org/opends/server/core/ConnectionHandlerConfigManager.java
index fc6219a..bc4cff5 100644
--- a/opends/src/server/org/opends/server/core/ConnectionHandlerConfigManager.java
+++ b/opends/src/server/org/opends/server/core/ConnectionHandlerConfigManager.java
@@ -28,1145 +28,448 @@
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.opends.server.api.ConfigAddListener;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.api.ConfigurableComponent;
-import org.opends.server.api.ConnectionHandler;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.config.StringConfigAttribute;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
-import org.opends.server.types.ErrorLogCategory;
-import org.opends.server.types.ErrorLogSeverity;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
-import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.CoreMessages.*;
-import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.admin.server.ServerManagementContext;
+import org.opends.server.admin.std.meta.*;
+import org.opends.server.admin.std.server.ConnectionHandlerCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.api.ConnectionHandler;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.InitializationException;
+import org.opends.server.types.ResultCode;
/**
- * This class defines a utility that will be used to manage the configuration
- * for the set of connection handlers defined in the Directory Server. It will
- * perform the necessary initialization of those connection handlers when the
- * server is first started, and then will manage any changes to them while the
- * server is running.
+ * This class defines a utility that will be used to manage the
+ * configuration for the set of connection handlers defined in the
+ * Directory Server. It will perform the necessary initialization of
+ * those connection handlers when the server is first started, and
+ * then will manage any changes to them while the server is running.
*/
-public class ConnectionHandlerConfigManager
- implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
-{
+public class ConnectionHandlerConfigManager implements
+ ConfigurationAddListener<ConnectionHandlerCfg>,
+ ConfigurationDeleteListener<ConnectionHandlerCfg>,
+ ConfigurationChangeListener<ConnectionHandlerCfg> {
-
-
- // The mapping between configuration entry DNs and their corresponding
- // connection handler implementations.
- private ConcurrentHashMap<DN,ConnectionHandler> connectionHandlers;
-
- // The DN of the associated configuration entry.
- private DN configEntryDN;
+ // The mapping between configuration entry DNs and their
+ // corresponding connection handler implementations.
+ private ConcurrentHashMap<DN, ConnectionHandler> connectionHandlers;
/**
* Creates a new instance of this connection handler config manager.
*/
- public ConnectionHandlerConfigManager()
- {
+ public ConnectionHandlerConfigManager() {
// No implementation is required.
}
/**
- * Initializes the configuration associated with the Directory Server
- * connection handlers. This should only be called at Directory Server
- * startup.
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(
+ ConnectionHandlerCfg configuration) {
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ // Register as a change listener for this connection handler entry
+ // so that we will be notified of any changes that may be made to
+ // it.
+ configuration.addChangeListener(this);
+
+ // Ignore this connection handler if it is disabled.
+ if (configuration.isEnabled()) {
+ // The connection handler needs to be enabled.
+ DN dn = configuration.dn();
+ try {
+ // Attempt to start the connection handler.
+ ConnectionHandler connectionHandler =
+ getConnectionHandler(configuration);
+ connectionHandler.start();
+
+ // Put this connection handler in the hash so that we will be
+ // able to find it if it is altered.
+ connectionHandlers.put(dn, connectionHandler);
+
+ // Register the connection handler with the Directory Server.
+ DirectoryServer.registerConnectionHandler(connectionHandler);
+ } catch (ConfigException e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ messages.add(e.getMessage());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
+ messages.add(getMessage(msgID, String.valueOf(configuration
+ .getJavaImplementationClass()), String.valueOf(dn),
+ stackTraceToSingleLineString(e)));
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+ }
+
+ // Return the configuration result.
+ return new ConfigChangeResult(resultCode, adminActionRequired,
+ messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ ConnectionHandlerCfg configuration) {
+ // Attempt to get the existing connection handler. This will only
+ // succeed if it was enabled.
+ DN dn = configuration.dn();
+ ConnectionHandler connectionHandler = connectionHandlers.get(dn);
+
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ // See whether the connection handler should be enabled.
+ if (connectionHandler == null) {
+ if (configuration.isEnabled()) {
+ // The connection handler needs to be enabled.
+ try {
+ // Attempt to start the connection handler.
+ connectionHandler = getConnectionHandler(configuration);
+ connectionHandler.start();
+
+ // Put this connection handler in the hash so that we will
+ // be able to find it if it is altered.
+ connectionHandlers.put(dn, connectionHandler);
+
+ // Register the connection handler with the Directory
+ // Server.
+ DirectoryServer
+ .registerConnectionHandler(connectionHandler);
+ } catch (ConfigException e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ messages.add(e.getMessage());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
+ messages.add(getMessage(msgID, String.valueOf(configuration
+ .getJavaImplementationClass()), String.valueOf(dn),
+ stackTraceToSingleLineString(e)));
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+ }
+ } else {
+ if (configuration.isEnabled()) {
+ // The connection handler is currently active, so we don't
+ // need to do anything. Changes to the class name cannot be
+ // applied dynamically, so if the class name did change then
+ // indicate that administrative action is required for that
+ // change to take effect.
+ String className = configuration.getJavaImplementationClass();
+ if (!className.equals(connectionHandler.getClass().getName())) {
+ adminActionRequired = true;
+ }
+ } else {
+ // We need to disable the connection handler.
+ DirectoryServer
+ .deregisterConnectionHandler(connectionHandler);
+ connectionHandlers.remove(dn);
+
+ int id = MSGID_CONNHANDLER_CLOSED_BY_DISABLE;
+ connectionHandler.finalizeConnectionHandler(getMessage(id),
+ false);
+ }
+ }
+
+ // Return the configuration result.
+ return new ConfigChangeResult(resultCode, adminActionRequired,
+ messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(
+ ConnectionHandlerCfg configuration) {
+
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+
+ // See if the entry is registered as a connection handler. If so,
+ // deregister and stop it. We'll try to leave any established
+ // connections alone if possible.
+ DN dn = configuration.dn();
+ ConnectionHandler connectionHandler = connectionHandlers.get(dn);
+ if (connectionHandler != null) {
+ DirectoryServer.deregisterConnectionHandler(connectionHandler);
+
+ int id = MSGID_CONNHANDLER_CLOSED_BY_DELETE;
+ connectionHandler.finalizeConnectionHandler(getMessage(id),
+ false);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired);
+ }
+
+
+
+ /**
+ * Initializes the configuration associated with the Directory
+ * Server connection handlers. This should only be called at
+ * Directory Server startup.
*
- * @throws ConfigException If a critical configuration problem prevents the
- * connection handler initialization from
- * succeeding.
- *
- * @throws InitializationException If a problem occurs while initializing
- * the connection handlers that is not
- * related to the server configuration.
+ * @throws ConfigException
+ * If a critical configuration problem prevents the
+ * connection handler initialization from succeeding.
+ * @throws InitializationException
+ * If a problem occurs while initializing the connection
+ * handlers that is not related to the server
+ * configuration.
*/
public void initializeConnectionHandlerConfig()
- throws ConfigException, InitializationException
- {
- connectionHandlers = new ConcurrentHashMap<DN,ConnectionHandler>();
+ throws ConfigException, InitializationException {
+ connectionHandlers = new ConcurrentHashMap<DN, ConnectionHandler>();
+ // Get the root configuration which acts as the parent of all
+ // connection handlers.
+ ServerManagementContext context = ServerManagementContext
+ .getInstance();
+ RootCfg root = context.getRootConfiguration();
+ // Register as an add and delete listener so that we can
+ // be notified if new connection handlers are added or existing
+ // connection handlers are removed.
+ root.addConnectionHandlerAddListener(this);
+ root.addConnectionHandlerDeleteListener(this);
- // Get the configuration entry that is at the root of all the connection
- // handlers in the server.
- ConfigEntry connectionHandlerRoot;
- try
- {
- configEntryDN = DN.decode(DN_CONNHANDLER_BASE);
- connectionHandlerRoot = DirectoryServer.getConfigEntry(configEntryDN);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
+ // Initialize existing connection handles.
+ for (String name : root.listConnectionHandlers()) {
+ ConnectionHandlerCfg config = root
+ .getConnectionHandler(name);
+
+ // Register as a change listener for this connection handler
+ // entry so that we will be notified of any changes that may be
+ // made to it.
+ config.addChangeListener(this);
+
+ // Ignore this connection handler if it is disabled.
+ if (config.isEnabled()) {
+ // Note that we don't want to start the connection handler
+ // because we're still in the startup process. Therefore, we
+ // will not do so and allow the server to start it at the very
+ // end of the initialization process.
+ ConnectionHandler connectionHandler = getConnectionHandler(config);
+
+ // Put this connection handler in the hash so that we will be
+ // able to find it if it is altered.
+ connectionHandlers.put(config.dn(), connectionHandler);
+
+ // Register the connection handler with the Directory Server.
+ DirectoryServer.registerConnectionHandler(connectionHandler);
}
-
- int msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_GET_CONFIG_BASE;
- String message = getMessage(msgID, stackTraceToSingleLineString(e));
- throw new ConfigException(msgID, message, e);
- }
-
-
- // If the configuration root entry is null, then assume it doesn't exist.
- // In that case, then fail. At least that entry must exist in the
- // configuration, even if there are no connection handlers defined below it.
- if (connectionHandlerRoot == null)
- {
- int msgID = MSGID_CONFIG_CONNHANDLER_BASE_DOES_NOT_EXIST;
- String message = getMessage(msgID);
- throw new ConfigException(msgID, message);
- }
-
-
- // Register as an add and delete listener for the base entry so that we can
- // be notified if new connection handlers are added or existing connection
- // handlers are removed.
- connectionHandlerRoot.registerAddListener(this);
- connectionHandlerRoot.registerDeleteListener(this);
-
-
- // Iterate through the set of immediate children below the connection
- // handler config root.
- for (ConfigEntry connectionHandlerEntry :
- connectionHandlerRoot.getChildren().values())
- {
- DN connectionHandlerDN = connectionHandlerEntry.getDN();
-
-
- // Register as a change listener for this connection handler entry so that
- // we will be notified of any changes that may be made to it.
- connectionHandlerEntry.registerChangeListener(this);
-
-
- // Check to see if this entry appears to contain a connection handler
- // configuration. If not, log a warning and skip it.
- if (! connectionHandlerEntry.hasObjectClass(OC_CONNECTION_HANDLER))
- {
- int msgID =
- MSGID_CONFIG_CONNHANDLER_ENTRY_DOES_NOT_HAVE_CONNHANDLER_CONFIG;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_WARNING, message, msgID);
- continue;
- }
-
-
- // See if the entry contains an attribute that indicates whether the
- // connection handler should be enabled. If it does not, or if it is not
- // set to "true", then skip it.
- int msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_ENABLED;
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute enabledAttr =
- (BooleanConfigAttribute)
- connectionHandlerEntry.getConfigAttribute(enabledStub);
- if (enabledAttr == null)
- {
- // The attribute is not present, so this connection handler will be
- // disabled. Log a message and continue.
- msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_WARNING, message, msgID);
- continue;
- }
- else if (! enabledAttr.activeValue())
- {
- // The connection handler is explicitly disabled. Log a mild warning
- // and continue.
- msgID = MSGID_CONFIG_CONNHANDLER_DISABLED;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.INFORMATIONAL, message, msgID);
- continue;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_UNABLE_TO_DETERMINE_ENABLED_STATE;
- String message = getMessage(msgID, String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
-
- // See if the entry contains an attribute that specifies the class name
- // for the connection handler implementation. If it does, then load it
- // and make sure that it's a valid connection handler implementation.
- // If there is no such attribute, the specified class cannot be loaded, or
- // it does not contain a valid connection handler implementation, then log
- // an error and skip it.
- String className;
- msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_CLASS;
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CONNECTION_HANDLER_CLASS,
- getMessage(msgID), true, false, true);
- try
- {
- StringConfigAttribute classAttr =
- (StringConfigAttribute)
- connectionHandlerEntry.getConfigAttribute(classStub);
- if (classAttr == null)
- {
- msgID = MSGID_CONFIG_CONNHANDLER_NO_CLASS_ATTR;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_ERROR, message, msgID);
- continue;
- }
- else
- {
- className = classAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_GET_CLASS;
- String message = getMessage(msgID, String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
- ConnectionHandler connectionHandler;
- try
- {
- // FIXME -- Should we use a custom class loader for this?
- Class connectionHandlerClass = Class.forName(className);
- connectionHandler =
- (ConnectionHandler) connectionHandlerClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INSTANTIATE;
- String message = getMessage(msgID, String.valueOf(className),
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
-
- // Perform the necessary initialization for the connection handler.
- try
- {
- connectionHandler.initializeConnectionHandler(connectionHandlerEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
- String message = getMessage(msgID, String.valueOf(className),
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
-
- // Put this connection handler in the hash so that we will be able to find
- // it if it is altered.
- connectionHandlers.put(connectionHandlerDN, connectionHandler);
-
-
- // Register the connection handler with the Directory Server.
- DirectoryServer.registerConnectionHandler(connectionHandler);
-
-
- // Note that we don't want to start the connection handler because we're
- // still in the startup process. Therefore, we will not do so and allow
- // the server to start it at the very end of the initialization process.
}
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * modification is acceptable to this change listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested update.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed change is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configChangeIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- DN connectionHandlerDN = configEntry.getDN();
-
-
- // Register as a change listener for this connection handler entry so that
- // we will be notified of any changes that may be made to it.
- configEntry.registerChangeListener(this);
-
-
- // Check to see if this entry appears to contain a connection handler
- // configuration. If not, then it is unacceptable.
- try
- {
- SearchFilter connectionHandlerFilter =
- SearchFilter.createFilterFromString("(objectClass=" +
- OC_CONNECTION_HANDLER + ")");
- if (! connectionHandlerFilter.matchesEntry(
- configEntry.getEntry()))
- {
- int msgID =
- MSGID_CONFIG_CONNHANDLER_ENTRY_DOES_NOT_HAVE_CONNHANDLER_CONFIG;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- unacceptableReason.append(message);
- return false;
- }
+ public boolean isConfigurationAddAcceptable(
+ ConnectionHandlerCfg configuration,
+ List<String> unacceptableReasons) {
+ if (configuration.isEnabled()) {
+ // It's enabled so always validate the class.
+ return isJavaClassAcceptable(configuration, unacceptableReasons);
+ } else {
+ // It's disabled so ignore it.
+ return true;
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID =
- MSGID_CONFIG_CONNHANDLER_ERROR_INTERACTING_WITH_CONNHANDLER_ENTRY;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // See if the entry contains an attribute that indicates whether the
- // connection handler should be enabled. If it does not, then reject it.
- int msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_ENABLED;
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute enabledAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
- if (enabledAttr == null)
- {
- // The attribute is not present, which is not acceptable.
- msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_UNABLE_TO_DETERMINE_ENABLED_STATE;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // See if the entry contains an attribute that specifies the class name for
- // the connection handler implementation. If it does, then load it and make
- // sure that it's a valid connection handler implementation. If there is no
- // such attribute, the specified class cannot be loaded, or it does not
- // contain a valid connection handler implementation, then it is
- // unacceptable.
- String className;
- msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_CLASS;
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CONNECTION_HANDLER_CLASS,
- getMessage(msgID), true, false, true);
- try
- {
- StringConfigAttribute classAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
- if (classAttr == null)
- {
- msgID = MSGID_CONFIG_CONNHANDLER_NO_CLASS_ATTR;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- unacceptableReason.append(message);
- return false;
- }
- else
- {
- className = classAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_GET_CLASS;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
- try
- {
- // FIXME -- Should we use a custom class loader for this?
- Class connectionHandlerClass = Class.forName(className);
- ConnectionHandler connectionHandler =
- (ConnectionHandler) connectionHandlerClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INSTANTIATE;
- unacceptableReason.append(getMessage(msgID, String.valueOf(className),
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // If we've gotten to this point, then it is acceptable as far as we are
- // concerned. If it is unacceptable according to the configuration for that
- // connection handler, then the handler itself will need to make that
- // determination.
- return true;
}
/**
- * Attempts to apply a new configuration to this Directory Server component
- * based on the provided changed entry.
- *
- * @param configEntry The configuration entry that containing the updated
- * configuration for this component.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry)
- {
- DN connectionHandlerDN = configEntry.getDN();
- ConnectionHandler connectionHandler =
- connectionHandlers.get(connectionHandlerDN);
-
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Check to see if this entry appears to contain a connection handler
- // configuration. If not, then skip it.
- if (! configEntry.hasObjectClass(OC_CONNECTION_HANDLER))
- {
- int msgID =
- MSGID_CONFIG_CONNHANDLER_ENTRY_DOES_NOT_HAVE_CONNHANDLER_CONFIG;
- messages.add(getMessage(msgID, String.valueOf(connectionHandlerDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
+ public boolean isConfigurationChangeAcceptable(
+ ConnectionHandlerCfg configuration,
+ List<String> unacceptableReasons) {
+ if (configuration.isEnabled()) {
+ // It's enabled so always validate the class.
+ return isJavaClassAcceptable(configuration, unacceptableReasons);
+ } else {
+ // It's disabled so ignore it.
+ return true;
}
-
-
- // See if the entry contains an attribute that indicates whether the
- // connection handler should be enabled.
- boolean needToEnable = false;
- int msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_ENABLED;
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute enabledAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
- if (enabledAttr == null)
- {
- // The attribute is not present. We won't allow this.
- msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(connectionHandlerDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else if (enabledAttr.activeValue())
- {
- // The connection handler is marked as enabled. See if that is already
- // true.
- if (connectionHandler == null)
- {
- needToEnable = true;
- }
- else
- {
- // It's already enabled, so we don't need to do anything.
- }
- }
- else
- {
- // The connection handler is marked as disabled. See if that is already
- // true.
- if (connectionHandler != null)
- {
- // It isn't disabled, so we will do so now and deregister it from the
- // server. We'll try to preserve existing connections if possible.
- DirectoryServer.deregisterConnectionHandler(connectionHandler);
- connectionHandlers.remove(connectionHandlerDN);
-
- int id = MSGID_CONNHANDLER_CLOSED_BY_DISABLE;
- connectionHandler.finalizeConnectionHandler(getMessage(id), false);
-
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- // It's already disabled, so we don't need to do anything.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_UNABLE_TO_DETERMINE_ENABLED_STATE;
- messages.add(getMessage(msgID, String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // See if the entry contains an attribute that specifies the class name
- // for the connection handler implementation. If it does, then load it and
- // make sure that it's a valid connection handler. If there is no such
- // attribute, the specified class cannot be loaded, or it does not contain a
- // valid connection handler implementation, then flag an error and skip it.
- String className;
- msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_CLASS;
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CONNECTION_HANDLER_CLASS,
- getMessage(msgID), true, false, true);
- try
- {
- StringConfigAttribute classAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
- if (classAttr == null)
- {
- msgID = MSGID_CONFIG_CONNHANDLER_NO_CLASS_ATTR;
- messages.add(getMessage(msgID, String.valueOf(connectionHandlerDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- className = classAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_GET_CLASS;
- messages.add(getMessage(msgID, String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
-
- // If the connection handler is currently active, then we don't need to do
- // anything. Changes to the class name cannot be applied dynamically, so
- // if the class name did change then indicate that administrative action
- // is required for that change to take effect.
- if (connectionHandler != null)
- {
- if (! className.equals(connectionHandler.getClass().getName()))
- {
- adminActionRequired = true;
- }
-
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // If we've gotten here, then that should mean that we need to enable the
- // connection handler. Try to do so.
- if (needToEnable)
- {
- try
- {
- // FIXME -- Should we use a custom class loader for this?
- Class handlerClass = Class.forName(className);
- connectionHandler = (ConnectionHandler) handlerClass.newInstance();
- }
- catch (Exception e)
- {
- // It is not a valid connection handler class. This is an error.
- msgID = MSGID_CONFIG_CONNHANDLER_CLASS_NOT_CONNHANDLER;
- messages.add(getMessage(msgID, String.valueOf(className),
- String.valueOf(connectionHandlerDN)));
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
-
- try
- {
- connectionHandler.initializeConnectionHandler(configEntry);
- connectionHandler.start();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
- messages.add(getMessage(msgID, String.valueOf(className),
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- connectionHandlers.put(connectionHandlerDN, connectionHandler);
- DirectoryServer.registerConnectionHandler(connectionHandler);
- }
-
-
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * add is acceptable to this add listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested add.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed entry is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configAddIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- DN connectionHandlerDN = configEntry.getDN();
-
-
- // Register as a change listener for this connection handler entry so that
- // we will be notified of any changes that may be made to it.
- configEntry.registerChangeListener(this);
-
-
- // Check to see if this entry appears to contain a connection handler
- // configuration. If not, then it is unacceptable.
- try
- {
- SearchFilter connectionHandlerFilter =
- SearchFilter.createFilterFromString("(objectClass=" +
- OC_CONNECTION_HANDLER + ")");
- if (! connectionHandlerFilter.matchesEntry(
- configEntry.getEntry()))
- {
- int msgID =
- MSGID_CONFIG_CONNHANDLER_ENTRY_DOES_NOT_HAVE_CONNHANDLER_CONFIG;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID =
- MSGID_CONFIG_CONNHANDLER_ERROR_INTERACTING_WITH_CONNHANDLER_ENTRY;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // See if the entry contains an attribute that indicates whether the
- // connection handler should be enabled. If it does not, then reject it.
- int msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_ENABLED;
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute enabledAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
- if (enabledAttr == null)
- {
- // The attribute is not present, which is not acceptable.
- msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_UNABLE_TO_DETERMINE_ENABLED_STATE;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // See if the entry contains an attribute that specifies the class name for
- // the connection handler implementation. If it does, then load it and make
- // sure that it's a valid connection handler implementation. If there is no
- // such attribute, the specified class cannot be loaded, or it does not
- // contain a valid connection handler implementation, then it is
- // unacceptable.
- String className;
- msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_CLASS;
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CONNECTION_HANDLER_CLASS,
- getMessage(msgID), true, false, true);
- try
- {
- StringConfigAttribute classAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
- if (classAttr == null)
- {
- msgID = MSGID_CONFIG_CONNHANDLER_NO_CLASS_ATTR;
- String message = getMessage(msgID,
- String.valueOf(connectionHandlerDN));
- unacceptableReason.append(message);
- return false;
- }
- else
- {
- className = classAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_GET_CLASS;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
- ConnectionHandler connectionHandler;
- try
- {
- // FIXME -- Should we use a custom class loader for this?
- Class connectionHandlerClass = Class.forName(className);
- connectionHandler =
- (ConnectionHandler) connectionHandlerClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INSTANTIATE;
- unacceptableReason.append(getMessage(msgID, String.valueOf(className),
- String.valueOf(connectionHandlerDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // If the connection handler is a configurable component, then make sure
- // that its configuration is valid.
- if (connectionHandler instanceof ConfigurableComponent)
- {
- ConfigurableComponent cc = (ConfigurableComponent) connectionHandler;
- LinkedList<String> errorMessages = new LinkedList<String>();
- if (! cc.hasAcceptableConfiguration(configEntry, errorMessages))
- {
- if (errorMessages.isEmpty())
- {
- msgID = MSGID_CONFIG_CONNHANDLER_UNACCEPTABLE_CONFIG;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
- else
- {
- Iterator<String> iterator = errorMessages.iterator();
- unacceptableReason.append(iterator.next());
- while (iterator.hasNext())
- {
- unacceptableReason.append(" ");
- unacceptableReason.append(iterator.next());
- }
- }
-
- return false;
- }
- }
-
-
- // If we've gotten to this point, then it is acceptable as far as we are
- // concerned. If it is unacceptable according to the configuration for that
- // connection handler, then the handler itself will need to make that
- // determination.
- return true;
- }
-
-
-
- /**
- * Attempts to apply a new configuration based on the provided added entry.
- *
- * @param configEntry The new configuration entry that contains the
- * configuration to apply.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry)
- {
- DN configEntryDN = configEntry.getDN();
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Register as a change listener for this connection handler entry so that
- // we will be notified of any changes that may be made to it.
- configEntry.registerChangeListener(this);
-
-
- // Check to see if this entry appears to contain a connection handler
- // configuration. If not, log a warning and skip it.
- if (! configEntry.hasObjectClass(OC_CONNECTION_HANDLER))
- {
- int msgID =
- MSGID_CONFIG_CONNHANDLER_ENTRY_DOES_NOT_HAVE_CONNHANDLER_CONFIG;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // See if the entry contains an attribute that indicates whether the
- // connection handler should be enabled. If it does not, or if it is not
- // set to "true", then skip it.
- int msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_ENABLED;
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute enabledAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
- if (enabledAttr == null)
- {
- // The attribute is not present, so this connection handler will be
- // disabled. We don't need to do anything else with this entry.
- msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else if (! enabledAttr.activeValue())
- {
- // The connection handler is explicitly disabled. We don't need to do
- // anything else with this entry.
- msgID = MSGID_CONFIG_CONNHANDLER_DISABLED;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_UNABLE_TO_DETERMINE_ENABLED_STATE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // See if the entry contains an attribute that specifies the class name
- // for the connection handler implementation. If it does, then load it
- // and make sure that it's a valid connection handler implementation.
- // If there is no such attribute, the specified class cannot be loaded, or
- // it does not contain a valid connection handler implementation, then log
- // an error and skip it.
- String className;
- msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_CLASS;
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_CONNECTION_HANDLER_CLASS,
- getMessage(msgID), true, false, true);
- try
- {
- StringConfigAttribute classAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
- if (classAttr == null)
- {
- msgID = MSGID_CONFIG_CONNHANDLER_NO_CLASS_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- className = classAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_GET_CLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
- ConnectionHandler connectionHandler;
- try
- {
- // FIXME -- Should we use a custom class loader for this?
- Class connectionHandlerClass = Class.forName(className);
- connectionHandler =
- (ConnectionHandler) connectionHandlerClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INSTANTIATE;
- messages.add(getMessage(msgID, String.valueOf(className),
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Perform the necessary initialization for the connection handler.
- try
- {
- connectionHandler.initializeConnectionHandler(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
- messages.add(getMessage(msgID, String.valueOf(className),
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Put this connection handler in the hash so that we will be able to find
- // it if it is altered.
- connectionHandlers.put(configEntryDN, connectionHandler);
-
-
- // Register the connection handler with the Directory Server.
- DirectoryServer.registerConnectionHandler(connectionHandler);
-
-
- // Since this method should only be called if the directory server is
- // online, then we will want to actually start the connection handler. Do
- // so now.
- connectionHandler.start();
-
-
- // At this point, everything should be done so return success.
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
- * Indicates whether it is acceptable to remove the provided configuration
- * entry.
- *
- * @param configEntry The configuration entry that will be removed
- * from the configuration.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed delete is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry may be removed from the
- * configuration, or <CODE>false</CODE> if not.
- */
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
+ public boolean isConfigurationDeleteAcceptable(
+ ConnectionHandlerCfg configuration,
+ List<String> unacceptableReasons) {
// A delete should always be acceptable, so just return true.
return true;
}
- /**
- * Attempts to apply a new configuration based on the provided deleted entry.
- *
- * @param configEntry The new configuration entry that has been deleted.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry)
- {
- DN configEntryDN = configEntry.getDN();
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
+ // Load and initialize the connection handler named in the config.
+ private ConnectionHandler getConnectionHandler(
+ ConnectionHandlerCfg config) throws ConfigException {
+ String className = config.getJavaImplementationClass();
+ ConnectionHandlerCfgDefn d =
+ ConnectionHandlerCfgDefn.getInstance();
+ ClassPropertyDefinition pd = d
+ .getJavaImplementationClassPropertyDefinition();
+ // Load the class and cast it to a connection handler.
+ Class<? extends ConnectionHandler> theClass;
+ ConnectionHandler connectionHandler;
- // See if the entry is registered as a connection handler. If so,
- // deregister and stop it. We'll try to leave any established connections
- // alone if possible.
- ConnectionHandler connectionHandler =
- connectionHandlers.get(configEntryDN);
- if (connectionHandler != null)
- {
- DirectoryServer.deregisterConnectionHandler(connectionHandler);
+ try {
+ theClass = pd.loadClass(className, ConnectionHandler.class);
+ connectionHandler = theClass.newInstance();
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
- int id = MSGID_CONNHANDLER_CLOSED_BY_DELETE;
- connectionHandler.finalizeConnectionHandler(getMessage(id), false);
+ int msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
+ String message = getMessage(msgID, String.valueOf(className),
+ String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e));
+ throw new ConfigException(msgID, message, e);
}
+ // Perform the necessary initialization for the connection
+ // handler.
+ try {
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ Method method = theClass.getMethod(
+ "initializeConnectionHandler", config.definition()
+ .getServerConfigurationClass());
- return new ConfigChangeResult(resultCode, adminActionRequired);
+ method.invoke(connectionHandler, config);
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
+ String message = getMessage(msgID, String.valueOf(className),
+ String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e));
+ throw new ConfigException(msgID, message, e);
+ }
+
+ // The connection handler has been successfully initialized.
+ return connectionHandler;
+ }
+
+
+
+ // Determines whether or not the new configuration's implementation
+ // class is acceptable.
+ private boolean isJavaClassAcceptable(
+ ConnectionHandlerCfg config,
+ List<String> unacceptableReasons) {
+ String className = config.getJavaImplementationClass();
+ ConnectionHandlerCfgDefn d =
+ ConnectionHandlerCfgDefn.getInstance();
+ ClassPropertyDefinition pd = d
+ .getJavaImplementationClassPropertyDefinition();
+
+ // Load the class and cast it to a connection handler.
+ Class<? extends ConnectionHandler> theClass;
+ try {
+ theClass = pd.loadClass(className, ConnectionHandler.class);
+ theClass.newInstance();
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
+ unacceptableReasons.add(getMessage(msgID, String
+ .valueOf(className), String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e)));
+ return false;
+ }
+
+ // Perform the necessary initialization for the connection
+ // handler.
+ try {
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ theClass.getMethod("initializeConnectionHandler", config.definition()
+ .getServerConfigurationClass());
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
+ unacceptableReasons.add(getMessage(msgID, String
+ .valueOf(className), String.valueOf(config.dn()),
+ stackTraceToSingleLineString(e)));
+ return false;
+ }
+
+ // The class is valid as far as we can tell.
+ return true;
}
}
-
diff --git a/opends/src/server/org/opends/server/core/DirectoryServer.java b/opends/src/server/org/opends/server/core/DirectoryServer.java
index 90d031f..17ef39b 100644
--- a/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -47,7 +47,8 @@
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
-
+import org.opends.server.admin.ClassLoaderProvider;
+import org.opends.server.admin.std.server.PasswordValidatorCfg;
import org.opends.server.api.*;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.StartupPluginResult;
@@ -264,7 +265,9 @@
// The set of password validators registered with the Directory Server, as a
// mapping between the DN of the associated configuration entry and the
// validator implementation.
- private ConcurrentHashMap<DN,PasswordValidator> passwordValidators;
+ private ConcurrentHashMap<DN,
+ PasswordValidator<? extends PasswordValidatorCfg>>
+ passwordValidators;
// The set of trust manager providers registered with the server.
private ConcurrentHashMap<DN,TrustManagerProvider> trustManagerProviders;
@@ -593,7 +596,8 @@
directoryServer.authPasswordStorageSchemes =
new ConcurrentHashMap<String,PasswordStorageScheme>();
directoryServer.passwordValidators =
- new ConcurrentHashMap<DN,PasswordValidator>();
+ new ConcurrentHashMap<DN,
+ PasswordValidator<? extends PasswordValidatorCfg>>();
directoryServer.accountStatusNotificationHandlers =
new ConcurrentHashMap<DN,AccountStatusNotificationHandler>();
directoryServer.rootDNs = new CopyOnWriteArraySet<DN>();
@@ -734,6 +738,10 @@
pluginConfigManager = new PluginConfigManager();
+ // Make sure that administration framework definition classes are loaded.
+ ClassLoaderProvider.getInstance().enable();
+
+
// If we have gotten here, then the configuration should be properly
// bootstrapped.
synchronized (directoryServer)
@@ -2490,7 +2498,13 @@
{
if (directoryServer.configHandler == null)
{
- String serverRoot = System.getenv(ENV_VAR_INSTANCE_ROOT);
+ String serverRoot = System.getProperty(PROPERTY_SERVER_ROOT);
+
+ if (serverRoot == null)
+ {
+ serverRoot = System.getenv(ENV_VAR_INSTANCE_ROOT);
+ }
+
if (serverRoot != null)
{
return serverRoot;
@@ -3970,6 +3984,257 @@
{
mBean.addConfigurableComponent(component);
}
+
+
+
+ // This is all code used to dynamically generate an admin definition from
+ // the configurable component. We'll only generate it if the
+ // org.opends.server.dumpComponents property is set to "true".
+ String propValue = System.getProperty("org.opends.server.dumpComponents");
+ if ((propValue == null) || (! propValue.equals("true")))
+ {
+ return;
+ }
+
+ try
+ {
+ DN entryDN = component.getConfigurableComponentEntryDN();
+ ConfigEntry configEntry =
+ directoryServer.configHandler.getConfigEntry(entryDN);
+ ObjectClass structuralClass =
+ configEntry.getEntry().getStructuralObjectClass();
+ ObjectClass superiorClass = structuralClass.getSuperiorClass();
+
+ String baseName;
+ String primaryName = structuralClass.getPrimaryName();
+ if (primaryName.startsWith("ds-cfg-"))
+ {
+ baseName = primaryName.substring(7);
+ }
+ else
+ {
+ baseName = "___NAME___";
+ }
+
+
+ LinkedList<String> lines = new LinkedList<String>();
+ lines.add("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ lines.add("<adm:managed-object name=\"" + baseName + "\" plural-name=\"" +
+ baseName + "s\"");
+ lines.add(" package=\"org.opends.server.admin.std\"");
+ lines.add(" xmlns:adm=\"http://www.opends.org/admin\"");
+ lines.add(" xmlns:ldap=\"http://www.opends.org/admin-ldap\"");
+ lines.add(" <adm:synopsis>");
+ lines.add(" ___SYNOPSIS___");
+ lines.add(" </adm:synopsis>");
+
+
+ // Write information about the object class.
+ lines.add(" <adm:profile name=\"ldap\">");
+ lines.add(" <ldap:object-class>");
+ lines.add(" <ldap:oid>" + structuralClass.getOID() + "</ldap:oid>");
+ lines.add(" <ldap:name>" + primaryName + "</ldap:name>");
+
+ if (superiorClass != null)
+ {
+ lines.add(" <ldap:superior>" + superiorClass.getNameOrOID() +
+ "</ldap:superior>");
+ }
+
+ lines.add(" </ldap:object-class>");
+ lines.add(" </adm:profile>");
+
+
+ // Write information about all of the configuration attributes.
+ for (org.opends.server.config.ConfigAttribute attr :
+ component.getConfigurationAttributes())
+ {
+ if (attr instanceof org.opends.server.config.ReadOnlyConfigAttribute)
+ {
+ continue;
+ }
+
+ primaryName = attr.getName();
+ AttributeType type = getAttributeType(toLowerCase(primaryName), true);
+ if (primaryName.startsWith("ds-cfg-"))
+ {
+ baseName = primaryName.substring(7);
+ }
+ else
+ {
+ baseName = "___NAME___";
+ }
+
+ lines.add(" <adm:property name=\"" + baseName + "\" mandatory=\"" +
+ String.valueOf(attr.isRequired()) + "\">");
+ lines.add(" <adm:synopsis>");
+ lines.add(" ___SYNOPSIS___");
+ lines.add(" </adm:synopsis>");
+ lines.add(" <adm:description>");
+
+ String description = attr.getDescription();
+ int startPos = 0;
+ while (startPos < description.length())
+ {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(" ");
+ int remaining = description.length() - startPos;
+ if (remaining <= 73)
+ {
+ buffer.append(description.substring(startPos));
+ startPos += remaining;
+ }
+ else
+ {
+ int endPos = startPos + 72;
+ while ((endPos > startPos) && (description.charAt(endPos) != ' '))
+ {
+ endPos--;
+ }
+ if (description.charAt(endPos) == ' ')
+ {
+ buffer.append(description.substring(startPos, endPos));
+ startPos = endPos + 1;
+ }
+ else
+ {
+ buffer.append(description.substring(startPos));
+ startPos += remaining;
+ }
+ }
+
+ lines.add(buffer.toString());
+ }
+
+ lines.add(" </adm:description>");
+ lines.add(" <adm:syntax>");
+
+ if (attr instanceof org.opends.server.config.BooleanConfigAttribute)
+ {
+ lines.add(" <adm:boolean />");
+ }
+ else if (attr instanceof org.opends.server.config.DNConfigAttribute)
+ {
+ lines.add(" <adm:dn />");
+ }
+ else if (attr instanceof
+ org.opends.server.config.IntegerConfigAttribute)
+ {
+ org.opends.server.config.IntegerConfigAttribute intAttr =
+ (org.opends.server.config.IntegerConfigAttribute) attr;
+ String lineStr = " <adm:integer ";
+ if (intAttr.hasLowerBound())
+ {
+ lineStr += " lower-limit=\"" + intAttr.getLowerBound() + "\" ";
+ }
+
+ if (intAttr.hasUpperBound())
+ {
+ lineStr += " upper-limit=\"" + intAttr.getUpperBound() + "\" ";
+ }
+
+ lineStr += "/>";
+ lines.add(lineStr);
+ }
+ else if (attr instanceof
+ org.opends.server.config.IntegerWithUnitConfigAttribute)
+ {
+ lines.add(" <!-- ___INTEGER_WITH_UNIT_TYPE___ -->");
+ lines.add(" <adm:string />");
+ }
+ else if (attr instanceof
+ org.opends.server.config.MultiChoiceConfigAttribute)
+ {
+ lines.add(" <adm:enumeration>");
+
+ org.opends.server.config.MultiChoiceConfigAttribute mcAttr =
+ (org.opends.server.config.MultiChoiceConfigAttribute) attr;
+ for (String allowedValue : mcAttr.allowedValues())
+ {
+ lines.add(" <adm:value name=\"" + allowedValue + "\">");
+ lines.add(" <adm:synopsis>");
+ lines.add(" ___SYNOPSIS___");
+ lines.add(" </adm:synopsis>");
+ lines.add(" </adm:value>");
+ }
+
+ lines.add(" </adm:enumeration>");
+ }
+ else if (attr instanceof
+ org.opends.server.config.StringConfigAttribute)
+ {
+ lines.add(" <adm:string />");
+ }
+ else
+ {
+ lines.add(" <!-- ___UNKNOWN_CONFIG_ATTR_TYPE___ -->");
+ lines.add(" <adm:string />");
+ }
+
+ lines.add(" </adm:syntax>");
+ lines.add(" <adm:profile name=\"ldap\">");
+ lines.add(" <ldap:attribute>");
+ lines.add(" <ldap:oid>" + type.getOID() + "</ldap:oid>");
+ lines.add(" <ldap:name>" + primaryName + "</ldap:name>");
+ lines.add(" </ldap:attribute>");
+ lines.add(" </adm:profile>");
+ lines.add(" </adm:property>");
+ }
+
+ lines.add("</adm:managed-object>");
+
+
+ File parentDir = new File("/tmp/admin-framework");
+ if (! parentDir.exists())
+ {
+ parentDir.mkdirs();
+ }
+
+ String dnString = entryDN.toNormalizedString();
+ StringBuilder filename = new StringBuilder();
+ filename.append(parentDir.getAbsolutePath());
+ filename.append("/");
+ for (int i=0; i < dnString.length(); i++)
+ {
+ char c = dnString.charAt(i);
+ if (Character.isLetter(c) || Character.isDigit(c))
+ {
+ filename.append(c);
+ }
+ else
+ {
+ filename.append('_');
+ }
+ }
+ filename.append(".xml");
+
+ java.io.BufferedWriter bw =
+ new java.io.BufferedWriter(new java.io.FileWriter(
+ filename.toString()));
+ for (String line : lines)
+ {
+ bw.write(line);
+ bw.newLine();
+ }
+ bw.flush();
+ bw.close();
+
+ System.err.println();
+ System.err.println();
+ System.err.println("---------- Registered Configurable Component " +
+ "----------");
+ for (String line : lines)
+ {
+ System.err.println(line);
+ }
+
+ System.err.println();
+ System.err.println();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
}
@@ -4282,7 +4547,10 @@
* @return The set of password validators that have been registered for use
* with the Directory Server.
*/
- public static ConcurrentHashMap<DN,PasswordValidator> getPasswordValidators()
+ public static
+ ConcurrentHashMap<DN,
+ PasswordValidator<? extends PasswordValidatorCfg>>
+ getPasswordValidators()
{
return directoryServer.passwordValidators;
}
@@ -4299,7 +4567,8 @@
* @return The requested password validator, or <CODE>null</CODE> if no such
* validator is defined.
*/
- public static PasswordValidator getPasswordValidator(DN configEntryDN)
+ public static PasswordValidator<? extends PasswordValidatorCfg>
+ getPasswordValidator(DN configEntryDN)
{
return directoryServer.passwordValidators.get(configEntryDN);
}
@@ -4315,8 +4584,10 @@
* @param validator The password validator to register with the
* Directory Server.
*/
- public static void registerPasswordValidator(DN configEntryDN,
- PasswordValidator validator)
+ public static void
+ registerPasswordValidator(DN configEntryDN,
+ PasswordValidator<? extends PasswordValidatorCfg>
+ validator)
{
directoryServer.passwordValidators.put(configEntryDN, validator);
}
@@ -6508,7 +6779,7 @@
Class workQueueClass ;
try
{
- workQueueClass = Class.forName(classAttr.activeValue());
+ workQueueClass = DirectoryServer.loadClass(classAttr.activeValue());
}
catch (Exception e)
{
@@ -8435,6 +8706,56 @@
return monitorRootDN.concat(rdn);
}
+
+
+ /**
+ * Gets the class loader to be used with this directory server
+ * application.
+ * <p>
+ * The class loader will automatically load classes from plugins
+ * where required.
+ *
+ * @return Returns the class loader to be used with this directory
+ * server application.
+ */
+ public static ClassLoader getClassLoader()
+ {
+ return ClassLoaderProvider.getInstance().getClassLoader();
+ }
+
+
+
+ /**
+ * Loads the named class using this directory server application's
+ * class loader.
+ * <p>
+ * This method provided as a convenience and is equivalent to
+ * calling:
+ *
+ * <pre>
+ * Class.forName(name, true, DirectoryServer.getClassLoader());
+ * </pre>
+ *
+ * @param name
+ * The fully qualified name of the desired class.
+ * @return Returns the class object representing the desired class.
+ * @throws LinkageError
+ * If the linkage fails.
+ * @throws ExceptionInInitializerError
+ * If the initialization provoked by this method fails.
+ * @throws ClassNotFoundException
+ * If the class cannot be located by the specified class
+ * loader.
+ * @see Class#forName(String, boolean, ClassLoader)
+ */
+ public static Class<?> loadClass(String name) throws LinkageError,
+ ExceptionInInitializerError, ClassNotFoundException
+ {
+ return Class.forName(name, true, DirectoryServer.getClassLoader());
+ }
+
+
+
/**
* Returns the error code that we return when we are checking the startability
* of the server.
@@ -8562,6 +8883,5 @@
}
return isRunningAsWindowsService;
}
-
}
diff --git a/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java b/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
index a5c1bb0..deda12d 100644
--- a/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
+++ b/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
@@ -270,8 +270,7 @@
Class cacheClass;
try
{
- // FIXME -- Should we use a custom class loader for this?
- cacheClass = Class.forName(className);
+ cacheClass = DirectoryServer.loadClass(className);
}
catch (Exception e)
{
diff --git a/opends/src/server/org/opends/server/core/ExtendedOperationConfigManager.java b/opends/src/server/org/opends/server/core/ExtendedOperationConfigManager.java
index eba44a5..2b71695 100644
--- a/opends/src/server/org/opends/server/core/ExtendedOperationConfigManager.java
+++ b/opends/src/server/org/opends/server/core/ExtendedOperationConfigManager.java
@@ -274,8 +274,7 @@
Class handlerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- handlerClass = Class.forName(classNameAttr.pendingValue());
+ handlerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -517,8 +516,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class handlerClass = Class.forName(className);
+ Class handlerClass = DirectoryServer.loadClass(className);
handler = (ExtendedOperationHandler) handlerClass.newInstance();
}
catch (Exception e)
@@ -665,8 +663,7 @@
Class handlerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- handlerClass = Class.forName(classNameAttr.pendingValue());
+ handlerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -886,8 +883,7 @@
ExtendedOperationHandler handler;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class handlerClass = Class.forName(className);
+ Class handlerClass = DirectoryServer.loadClass(className);
handler = (ExtendedOperationHandler) handlerClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/GroupManager.java b/opends/src/server/org/opends/server/core/GroupManager.java
index 2556c54..b1f5f71 100644
--- a/opends/src/server/org/opends/server/core/GroupManager.java
+++ b/opends/src/server/org/opends/server/core/GroupManager.java
@@ -372,8 +372,7 @@
Class groupClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- groupClass = Class.forName(classNameAttr.pendingValue());
+ groupClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -626,8 +625,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class groupClass = Class.forName(className);
+ Class groupClass = DirectoryServer.loadClass(className);
groupImplementation = (Group) groupClass.newInstance();
}
catch (Exception e)
@@ -756,8 +754,7 @@
Class groupClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- groupClass = Class.forName(classNameAttr.pendingValue());
+ groupClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -977,8 +974,7 @@
Group groupImplementation;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class groupClass = Class.forName(className);
+ Class groupClass = DirectoryServer.loadClass(className);
groupImplementation = (Group) groupClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/IdentityMapperConfigManager.java b/opends/src/server/org/opends/server/core/IdentityMapperConfigManager.java
index 976c87e..466ad21 100644
--- a/opends/src/server/org/opends/server/core/IdentityMapperConfigManager.java
+++ b/opends/src/server/org/opends/server/core/IdentityMapperConfigManager.java
@@ -28,22 +28,21 @@
+import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
-import org.opends.server.api.ConfigAddListener;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.api.ConfigurableComponent;
-import org.opends.server.api.ConfigHandler;
+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.std.meta.IdentityMapperCfgDefn;
+import org.opends.server.admin.std.server.IdentityMapperCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.api.IdentityMapper;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.ErrorLogCategory;
@@ -51,14 +50,9 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -70,18 +64,15 @@
* or modifications to any identity mappers while the server is running.
*/
public class IdentityMapperConfigManager
- implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
+ implements ConfigurationChangeListener<IdentityMapperCfg>,
+ ConfigurationAddListener<IdentityMapperCfg>,
+ ConfigurationDeleteListener<IdentityMapperCfg>
+
{
-
-
-
// A mapping between the DNs of the config entries and the associated identity
// mappers.
private ConcurrentHashMap<DN,IdentityMapper> identityMappers;
- // The configuration handler for the Directory Server.
- private ConfigHandler configHandler;
-
/**
@@ -89,7 +80,6 @@
*/
public IdentityMapperConfigManager()
{
- configHandler = DirectoryServer.getConfigHandler();
identityMappers = new ConcurrentHashMap<DN,IdentityMapper>();
}
@@ -109,100 +99,44 @@
public void initializeIdentityMappers()
throws ConfigException, InitializationException
{
- // First, get the configuration base entry.
- ConfigEntry baseEntry;
- try
+ // 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 identity mapper entries are added or removed.
+ rootConfiguration.addIdentityMapperAddListener(this);
+ rootConfiguration.addIdentityMapperDeleteListener(this);
+
+
+ //Initialize the existing identity mappers.
+ for (String mapperName : rootConfiguration.listIdentityMappers())
{
- DN mapperBase = DN.decode(DN_IDMAPPER_CONFIG_BASE);
- baseEntry = configHandler.getConfigEntry(mapperBase);
- }
- catch (Exception e)
- {
- if (debugEnabled())
+ IdentityMapperCfg mapperConfiguration =
+ rootConfiguration.getIdentityMapper(mapperName);
+ mapperConfiguration.addChangeListener(this);
+
+ if (mapperConfiguration.isEnabled())
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_CANNOT_GET_BASE;
- String message = getMessage(msgID, String.valueOf(e));
- throw new ConfigException(msgID, message, e);
- }
-
- if (baseEntry == null)
- {
- // The identity mapper base entry does not exist. This is not acceptable,
- // so throw an exception.
- int msgID = MSGID_CONFIG_IDMAPPER_BASE_DOES_NOT_EXIST;
- String message = getMessage(msgID);
- throw new ConfigException(msgID, message);
- }
-
-
- // Register add and delete listeners with the identity mapper base entry.
- // We don't care about modifications to it.
- baseEntry.registerAddListener(this);
- baseEntry.registerDeleteListener(this);
-
-
- // See if the base entry has any children. If not, then we don't need to do
- // anything else.
- if (! baseEntry.hasChildren())
- {
- return;
- }
-
-
- // Iterate through the child entries and process them as identity mapper
- // configuration entries.
- for (ConfigEntry childEntry : baseEntry.getChildren().values())
- {
- childEntry.registerChangeListener(this);
-
- StringBuilder unacceptableReason = new StringBuilder();
- if (! configAddIsAcceptable(childEntry, unacceptableReason))
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_IDMAPPER_ENTRY_UNACCEPTABLE,
- childEntry.getDN().toString(), unacceptableReason.toString());
- continue;
- }
-
- try
- {
- ConfigChangeResult result = applyConfigurationAdd(childEntry);
- if (result.getResultCode() != ResultCode.SUCCESS)
+ String className = mapperConfiguration.getMapperClass();
+ try
{
- StringBuilder buffer = new StringBuilder();
-
- List<String> resultMessages = result.getMessages();
- if ((resultMessages == null) || (resultMessages.isEmpty()))
- {
- buffer.append(getMessage(MSGID_CONFIG_UNKNOWN_UNACCEPTABLE_REASON));
- }
- else
- {
- Iterator<String> iterator = resultMessages.iterator();
-
- buffer.append(iterator.next());
- while (iterator.hasNext())
- {
- buffer.append(EOL);
- buffer.append(iterator.next());
- }
- }
-
+ IdentityMapper mapper = loadMapper(className, mapperConfiguration);
+ identityMappers.put(mapperConfiguration.dn(), mapper);
+ DirectoryServer.registerIdentityMapper(mapperConfiguration.dn(),
+ mapper);
+ }
+ catch (InitializationException ie)
+ {
logError(ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_IDMAPPER_CANNOT_CREATE_MAPPER,
- childEntry.getDN().toString(), buffer.toString());
+ ie.getMessage(), ie.getMessageID());
+ continue;
}
}
- catch (Exception e)
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_IDMAPPER_CANNOT_CREATE_MAPPER,
- childEntry.getDN().toString(), String.valueOf(e));
- }
}
@@ -226,754 +160,273 @@
/**
- * Indicates whether the configuration entry that will result from a proposed
- * modification is acceptable to this change listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested update.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed change is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configChangeIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationAddAcceptable(
+ IdentityMapperCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that the entry has an appropriate objectclass for an identity
- // mapper.
- if (! configEntry.hasObjectClass(OC_IDENTITY_MAPPER))
+ if (configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the identity mapper class name.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_IDMAPPER_CLASS,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_CLASS_NAME),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
+ // Get the name of the class and make sure we can instantiate it as an
+ // identity mapper.
+ String className = configuration.getMapperClass();
+ try
{
- int msgID = MSGID_CONFIG_IDMAPPER_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
+ loadMapper(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
return false;
}
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class mapperClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- mapperClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- try
- {
- IdentityMapper mapper =
- (IdentityMapper) mapperClass.newInstance();
- }
- catch(Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS;
- String message = getMessage(msgID, mapperClass.getName(),
- String.valueOf(configEntry.getDN()),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // See if this identity mapper should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_IDMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_IDMAPPER_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the identity mapper entry appears to be
- // acceptable.
+ // If we've gotten here, then it's fine.
return true;
}
/**
- * Attempts to apply a new configuration to this Directory Server component
- * based on the provided changed entry.
- *
- * @param configEntry The configuration entry that containing the updated
- * configuration for this component.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationAdd(
+ IdentityMapperCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
+ configuration.addChangeListener(this);
- // Make sure that the entry has an appropriate objectclass for an identity
- // mapper.
- if (! configEntry.hasObjectClass(OC_IDENTITY_MAPPER))
+ if (! configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_OBJECTCLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
+ IdentityMapper identityMapper = null;
- // Get the corresponding identity mapper if it is active.
- IdentityMapper mapper = identityMappers.get(configEntryDN);
-
-
- // See if this identity mapper should be enabled or disabled.
- boolean needsEnabled = false;
- BooleanConfigAttribute enabledAttr;
+ // Get the name of the class and make sure we can instantiate it as an
+ // identity mapper.
+ String className = configuration.getMapperClass();
try
{
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_IDMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_IDMAPPER_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- if (enabledAttr.activeValue())
- {
- if (mapper == null)
- {
- needsEnabled = true;
- }
- else
- {
- // The identity mapper is already active, so no action is required.
- }
- }
- else
- {
- if (mapper == null)
- {
- // The identity mapper is already disabled, so no action is required
- // and we can short-circuit out of this processing.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- // The identity mapper is active, so it needs to be disabled. Do this
- // and return that we were successful.
- identityMappers.remove(configEntryDN);
- mapper.finalizeIdentityMapper();
- DirectoryServer.deregisterIdentityMapper(configEntryDN);
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
+ identityMapper = loadMapper(className, configuration);
}
- catch (Exception e)
+ catch (InitializationException ie)
{
- if (debugEnabled())
+ if (resultCode == ResultCode.SUCCESS)
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the identity mapper class name. If it
- // has changed, then we will not try to dynamically apply it.
- String className;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_IDMAPPER_CLASS,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_CLASS_NAME),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_IDMAPPER_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- className = classNameAttr.pendingValue();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- boolean classChanged = false;
- String oldClassName = null;
- if (mapper != null)
- {
- oldClassName = mapper.getClass().getName();
- classChanged = (! className.equals(oldClassName));
- }
-
-
- if (classChanged)
- {
- // This will not be applied dynamically. Add a message to the response
- // and indicate that admin action is required.
- adminActionRequired = true;
- messages.add(getMessage(MSGID_CONFIG_IDMAPPER_CLASS_ACTION_REQUIRED,
- String.valueOf(oldClassName),
- String.valueOf(className),
- String.valueOf(configEntryDN)));
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- if (needsEnabled)
- {
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class mapperClass = Class.forName(className);
- mapper = (IdentityMapper) mapperClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
}
- try
- {
- mapper.initializeIdentityMapper(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
-
- identityMappers.put(configEntryDN, mapper);
- DirectoryServer.registerIdentityMapper(configEntryDN, mapper);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ messages.add(ie.getMessage());
}
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ identityMappers.put(configuration.dn(), identityMapper);
+ DirectoryServer.registerIdentityMapper(configuration.dn(),
+ identityMapper);
+ }
- // If we've gotten here, then there haven't been any changes to anything
- // that we care about.
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * add is acceptable to this add listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested add.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed entry is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configAddIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationDeleteAcceptable(
+ IdentityMapperCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that no entry already exists with the specified DN.
- DN configEntryDN = configEntry.getDN();
- if (identityMappers.containsKey(configEntryDN))
- {
- int msgID = MSGID_CONFIG_IDMAPPER_EXISTS;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry has an appropriate objectclass for an identity
- // mapper.
- if (! configEntry.hasObjectClass(OC_IDENTITY_MAPPER))
- {
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the identity mapper class.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_IDMAPPER_CLASS,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_CLASS_NAME),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_IDMAPPER_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class mapperClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- mapperClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- IdentityMapper identityMapper;
- try
- {
- identityMapper = (IdentityMapper) mapperClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS;
- String message = getMessage(msgID, mapperClass.getName(),
- String.valueOf(configEntryDN),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If the identity mapper is a configurable component, then make sure that
- // its configuration is valid.
- if (identityMapper instanceof ConfigurableComponent)
- {
- ConfigurableComponent cc = (ConfigurableComponent) identityMapper;
- LinkedList<String> errorMessages = new LinkedList<String>();
- if (! cc.hasAcceptableConfiguration(configEntry, errorMessages))
- {
- if (errorMessages.isEmpty())
- {
- int msgID = MSGID_CONFIG_IDMAPPER_UNACCEPTABLE_CONFIG;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
- else
- {
- Iterator<String> iterator = errorMessages.iterator();
- unacceptableReason.append(iterator.next());
- while (iterator.hasNext())
- {
- unacceptableReason.append(" ");
- unacceptableReason.append(iterator.next());
- }
- }
-
- return false;
- }
- }
-
-
- // See if this identity mapper should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_IDMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_IDMAPPER_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the identity mapper entry appears to be
- // acceptable.
+ // FIXME -- We should try to perform some check to determine whether the
+ // identity mapper is in use.
return true;
}
/**
- * Attempts to apply a new configuration based on the provided added entry.
- *
- * @param configEntry The new configuration entry that contains the
- * configuration to apply.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationDelete(
+ IdentityMapperCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
+ DirectoryServer.deregisterIdentityMapper(configuration.dn());
- // Make sure that the entry has an appropriate objectclass for an identity
- // mapper.
- if (! configEntry.hasObjectClass(OC_IDENTITY_MAPPER))
- {
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_OBJECTCLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // See if this identity mapper should be enabled or disabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_IDMAPPER_ENABLED,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- // The attribute doesn't exist, so it will be disabled by default.
- int msgID = MSGID_CONFIG_IDMAPPER_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.SUCCESS;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else if (! enabledAttr.activeValue())
- {
- // It is explicitly configured as disabled, so we don't need to do
- // anything.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the identity mapper class name.
- String className;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_IDMAPPER_CLASS,
- getMessage(MSGID_CONFIG_IDMAPPER_DESCRIPTION_CLASS_NAME),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_IDMAPPER_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- className = classNameAttr.pendingValue();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Load and initialize the identity mapper class, and register it with the
- // Directory Server.
- IdentityMapper identityMapper;
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class mapperClass = Class.forName(className);
- identityMapper = (IdentityMapper) mapperClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INVALID_CLASS;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
- try
- {
- identityMapper.initializeIdentityMapper(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_IDMAPPER_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- identityMappers.put(configEntryDN, identityMapper);
- DirectoryServer.registerIdentityMapper(configEntryDN, identityMapper);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
- * Indicates whether it is acceptable to remove the provided configuration
- * entry.
- *
- * @param configEntry The configuration entry that will be removed
- * from the configuration.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed delete is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry may be removed from the
- * configuration, or <CODE>false</CODE> if not.
- */
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- // A delete should always be acceptable, so just return true.
- return true;
- }
-
-
-
- /**
- * Attempts to apply a new configuration based on the provided deleted entry.
- *
- * @param configEntry The new configuration entry that has been deleted.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry)
- {
- DN configEntryDN = configEntry.getDN();
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
-
-
- // See if the entry is registered as an identity mapper. If so, deregister
- // it and stop the mapper.
- DirectoryServer.deregisterIdentityMapper(configEntryDN);
- IdentityMapper identityMapper = identityMappers.remove(configEntryDN);
+ IdentityMapper identityMapper = identityMappers.remove(configuration.dn());
if (identityMapper != null)
{
identityMapper.finalizeIdentityMapper();
}
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
- return new ConfigChangeResult(resultCode, adminActionRequired);
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ IdentityMapperCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ if (configuration.isEnabled())
+ {
+ // Get the name of the class and make sure we can instantiate it as an
+ // identity mapper.
+ String className = configuration.getMapperClass();
+ try
+ {
+ loadMapper(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
+ return false;
+ }
+ }
+
+ // If we've gotten here, then it's fine.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ IdentityMapperCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Get the existing mapper if it's already enabled.
+ IdentityMapper existingMapper = identityMappers.get(configuration.dn());
+
+
+ // If the new configuration has the mapper disabled, then disable it if it
+ // is enabled, or do nothing if it's already disabled.
+ if (! configuration.isEnabled())
+ {
+ if (existingMapper != null)
+ {
+ DirectoryServer.deregisterIdentityMapper(configuration.dn());
+
+ IdentityMapper identityMapper =
+ identityMappers.remove(configuration.dn());
+ if (identityMapper != null)
+ {
+ identityMapper.finalizeIdentityMapper();
+ }
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+ // Get the class for the identity mapper. If the mapper is already enabled,
+ // then we shouldn't do anything with it although if the class has changed
+ // then we'll at least need to indicate that administrative action is
+ // required. If the mapper is disabled, then instantiate the class and
+ // initialize and register it as an identity mapper.
+ String className = configuration.getMapperClass();
+ if (existingMapper != null)
+ {
+ if (! className.equals(existingMapper.getClass().getName()))
+ {
+ adminActionRequired = true;
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ IdentityMapper identityMapper = null;
+ try
+ {
+ identityMapper = loadMapper(className, configuration);
+ }
+ catch (InitializationException ie)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(ie.getMessage());
+ }
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ identityMappers.put(configuration.dn(), identityMapper);
+ DirectoryServer.registerIdentityMapper(configuration.dn(),
+ identityMapper);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * Loads the specified class, instantiates it as an identity mapper, and
+ * optionally initializes that instance.
+ *
+ * @param className The fully-qualified name of the identity mapper
+ * class to load, instantiate, and initialize.
+ * @param configuration The configuration to use to initialize the identity
+ * mapper, or {@code null} if the identity mapper
+ * should not be initialized.
+ *
+ * @return The possibly initialized identity mapper.
+ *
+ * @throws InitializationException If a problem occurred while attempting to
+ * initialize the identity mapper.
+ */
+ private IdentityMapper loadMapper(String className,
+ IdentityMapperCfg configuration)
+ throws InitializationException
+ {
+ try
+ {
+ IdentityMapperCfgDefn definition =
+ IdentityMapperCfgDefn.getInstance();
+ ClassPropertyDefinition propertyDefinition =
+ definition.getMapperClassPropertyDefinition();
+ Class<? extends IdentityMapper> mapperClass =
+ propertyDefinition.loadClass(className, IdentityMapper.class);
+ IdentityMapper mapper = mapperClass.newInstance();
+
+ if (configuration != null)
+ {
+ Method method =
+ mapper.getClass().getMethod("initializeIdentityMapper",
+ configuration.definition().getServerConfigurationClass());
+ method.invoke(mapper, configuration);
+ }
+
+ return mapper;
+ }
+ catch (Exception e)
+ {
+ int msgID = MSGID_CONFIG_IDMAPPER_INITIALIZATION_FAILED;
+ String message = getMessage(msgID, className,
+ String.valueOf(configuration.dn()),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
}
}
diff --git a/opends/src/server/org/opends/server/core/KeyManagerProviderConfigManager.java b/opends/src/server/org/opends/server/core/KeyManagerProviderConfigManager.java
index 5a64fd5..599899e 100644
--- a/opends/src/server/org/opends/server/core/KeyManagerProviderConfigManager.java
+++ b/opends/src/server/org/opends/server/core/KeyManagerProviderConfigManager.java
@@ -61,6 +61,7 @@
import static org.opends.server.util.ServerConstants.*;
+
/**
* This class defines a utility that will be used to manage the set of
* key manager providers defined in the Directory Server. It will initialize
@@ -271,8 +272,7 @@
Class providerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- providerClass = Class.forName(classNameAttr.pendingValue());
+ providerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -290,8 +290,7 @@
try
{
- KeyManagerProvider provider =
- (KeyManagerProvider) providerClass.newInstance();
+ providerClass.newInstance();
}
catch(Exception e)
{
@@ -515,8 +514,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class providerClass = Class.forName(className);
+ Class providerClass = DirectoryServer.loadClass(className);
provider = (KeyManagerProvider) providerClass.newInstance();
}
catch (Exception e)
@@ -643,8 +641,7 @@
Class providerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- providerClass = Class.forName(classNameAttr.pendingValue());
+ providerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -870,8 +867,7 @@
KeyManagerProvider provider;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class providerClass = Class.forName(className);
+ Class providerClass = DirectoryServer.loadClass(className);
provider = (KeyManagerProvider) providerClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/LoggerConfigManager.java b/opends/src/server/org/opends/server/core/LoggerConfigManager.java
index 00d0f0e..eb54351 100644
--- a/opends/src/server/org/opends/server/core/LoggerConfigManager.java
+++ b/opends/src/server/org/opends/server/core/LoggerConfigManager.java
@@ -344,8 +344,7 @@
Class loggerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- loggerClass = Class.forName(classNameAttr.pendingValue());
+ loggerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -658,8 +657,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class loggerClass = Class.forName(className);
+ Class loggerClass = DirectoryServer.loadClass(className);
accessLogger = (AccessLogger) loggerClass.newInstance();
}
catch (Exception e)
@@ -707,8 +705,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class loggerClass = Class.forName(className);
+ Class loggerClass = DirectoryServer.loadClass(className);
errorLogger = (ErrorLogger) loggerClass.newInstance();
}
catch (Exception e)
@@ -857,8 +854,7 @@
Class loggerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- loggerClass = Class.forName(classNameAttr.pendingValue());
+ loggerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -1122,8 +1118,7 @@
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class loggerClass = Class.forName(className);
+ Class loggerClass = DirectoryServer.loadClass(className);
accessLogger = (AccessLogger) loggerClass.newInstance();
}
catch (Exception e)
@@ -1176,8 +1171,7 @@
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class loggerClass = Class.forName(className);
+ Class loggerClass = DirectoryServer.loadClass(className);
errorLogger = (ErrorLogger) loggerClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/MonitorConfigManager.java b/opends/src/server/org/opends/server/core/MonitorConfigManager.java
index ad6b8b8..8c885cc 100644
--- a/opends/src/server/org/opends/server/core/MonitorConfigManager.java
+++ b/opends/src/server/org/opends/server/core/MonitorConfigManager.java
@@ -272,8 +272,7 @@
Class monitorClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- monitorClass = Class.forName(classNameAttr.pendingValue());
+ monitorClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -513,8 +512,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class monitorClass = Class.forName(className);
+ Class monitorClass = DirectoryServer.loadClass(className);
monitor = (MonitorProvider) monitorClass.newInstance();
}
catch (Exception e)
@@ -641,8 +639,7 @@
Class monitorClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- monitorClass = Class.forName(classNameAttr.pendingValue());
+ monitorClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -862,8 +859,7 @@
MonitorProvider monitor;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class monitorClass = Class.forName(className);
+ Class monitorClass = DirectoryServer.loadClass(className);
monitor = (MonitorProvider) monitorClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/PasswordGeneratorConfigManager.java b/opends/src/server/org/opends/server/core/PasswordGeneratorConfigManager.java
index 9263f1b..3acb597 100644
--- a/opends/src/server/org/opends/server/core/PasswordGeneratorConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PasswordGeneratorConfigManager.java
@@ -59,7 +59,6 @@
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
@@ -273,8 +272,7 @@
Class generatorClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- generatorClass = Class.forName(classNameAttr.pendingValue());
+ generatorClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -519,8 +517,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class generatorClass = Class.forName(className);
+ Class generatorClass = DirectoryServer.loadClass(className);
generator = (PasswordGenerator) generatorClass.newInstance();
}
catch (Exception e)
@@ -647,8 +644,7 @@
Class generatorClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- generatorClass = Class.forName(classNameAttr.pendingValue());
+ generatorClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -868,8 +864,7 @@
PasswordGenerator generator;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class generatorClass = Class.forName(className);
+ Class generatorClass = DirectoryServer.loadClass(className);
generator = (PasswordGenerator) generatorClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/PasswordPolicy.java b/opends/src/server/org/opends/server/core/PasswordPolicy.java
index abf8cbd..c58270f 100644
--- a/opends/src/server/org/opends/server/core/PasswordPolicy.java
+++ b/opends/src/server/org/opends/server/core/PasswordPolicy.java
@@ -39,6 +39,7 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
+import org.opends.server.admin.std.server.PasswordValidatorCfg;
import org.opends.server.api.AccountStatusNotificationHandler;
import org.opends.server.api.PasswordGenerator;
import org.opends.server.api.PasswordStorageScheme;
@@ -144,8 +145,11 @@
new ConcurrentHashMap<DN, AccountStatusNotificationHandler>();
// The set of password validators that will be used with this password policy.
- private ConcurrentHashMap<DN,PasswordValidator> passwordValidators =
- new ConcurrentHashMap<DN,PasswordValidator>();
+ private ConcurrentHashMap<DN,
+ PasswordValidator<? extends PasswordValidatorCfg>>
+ passwordValidators =
+ new ConcurrentHashMap<DN,PasswordValidator<? extends
+ PasswordValidatorCfg>>();
// The set of default password storage schemes for this password policy.
private CopyOnWriteArrayList<PasswordStorageScheme> defaultStorageSchemes =
@@ -435,12 +439,16 @@
(DNConfigAttribute) configEntry.getConfigAttribute(validatorStub);
if (validatorAttr != null)
{
- ConcurrentHashMap<DN,PasswordValidator> validators =
- new ConcurrentHashMap<DN,PasswordValidator>();
+ ConcurrentHashMap<DN,
+ PasswordValidator<? extends PasswordValidatorCfg>>
+ validators =
+ new ConcurrentHashMap<DN,
+ PasswordValidator<? extends
+ PasswordValidatorCfg>>();
for (DN validatorDN : validatorAttr.pendingValues())
{
- PasswordValidator validator =
- DirectoryServer.getPasswordValidator(validatorDN);
+ PasswordValidator<? extends PasswordValidatorCfg>
+ validator = DirectoryServer.getPasswordValidator(validatorDN);
if (validator == null)
{
msgID = MSGID_PWPOLICY_NO_SUCH_VALIDATOR;
@@ -1553,7 +1561,9 @@
*
* @return The set of password validators for this password policy.
*/
- public ConcurrentHashMap<DN,PasswordValidator> getPasswordValidators()
+ public ConcurrentHashMap<DN,
+ PasswordValidator<? extends PasswordValidatorCfg>>
+ getPasswordValidators()
{
return passwordValidators;
}
diff --git a/opends/src/server/org/opends/server/core/PasswordPolicyState.java b/opends/src/server/org/opends/server/core/PasswordPolicyState.java
index e13717b..a518cc8 100644
--- a/opends/src/server/org/opends/server/core/PasswordPolicyState.java
+++ b/opends/src/server/org/opends/server/core/PasswordPolicyState.java
@@ -38,6 +38,7 @@
import java.util.List;
import java.util.Set;
+import org.opends.server.admin.std.server.PasswordValidatorCfg;
import org.opends.server.api.AccountStatusNotificationHandler;
import org.opends.server.api.PasswordGenerator;
import org.opends.server.api.PasswordStorageScheme;
@@ -3209,7 +3210,7 @@
{
for (DN validatorDN : passwordPolicy.getPasswordValidators().keySet())
{
- PasswordValidator validator =
+ PasswordValidator<? extends PasswordValidatorCfg> validator =
passwordPolicy.getPasswordValidators().get(validatorDN);
if (! validator.passwordIsAcceptable(newPassword, currentPasswords,
diff --git a/opends/src/server/org/opends/server/core/PasswordStorageSchemeConfigManager.java b/opends/src/server/org/opends/server/core/PasswordStorageSchemeConfigManager.java
index 263c3dd..da4632f 100644
--- a/opends/src/server/org/opends/server/core/PasswordStorageSchemeConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PasswordStorageSchemeConfigManager.java
@@ -272,8 +272,7 @@
Class schemeClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- schemeClass = Class.forName(classNameAttr.pendingValue());
+ schemeClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -519,8 +518,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class schemeClass = Class.forName(className);
+ Class schemeClass = DirectoryServer.loadClass(className);
scheme = (PasswordStorageScheme) schemeClass.newInstance();
}
catch (Exception e)
@@ -647,8 +645,7 @@
Class schemeClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- schemeClass = Class.forName(classNameAttr.pendingValue());
+ schemeClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -869,8 +866,7 @@
PasswordStorageScheme storageScheme;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class schemeClass = Class.forName(className);
+ Class schemeClass = DirectoryServer.loadClass(className);
storageScheme = (PasswordStorageScheme) schemeClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/PasswordValidatorConfigManager.java b/opends/src/server/org/opends/server/core/PasswordValidatorConfigManager.java
index e79619f..eec576b 100644
--- a/opends/src/server/org/opends/server/core/PasswordValidatorConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PasswordValidatorConfigManager.java
@@ -28,22 +28,21 @@
+import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
-import org.opends.server.api.ConfigAddListener;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.api.ConfigHandler;
-import org.opends.server.api.ConfigurableComponent;
+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.std.meta.PasswordValidatorCfgDefn;
+import org.opends.server.admin.std.server.PasswordValidatorCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.api.PasswordValidator;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.ErrorLogCategory;
@@ -51,36 +50,30 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
/**
- * This class defines a utility that will be used to manage the set of password
- * validators defined in the Directory Server. It will initialize the
+ * This class defines a utility that will be used to manage the set of
+ * password validators defined in the Directory Server. It will initialize the
* validators when the server starts, and then will manage any additions,
* removals, or modifications to any password validators while the server is
* running.
*/
public class PasswordValidatorConfigManager
- implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
+ implements ConfigurationChangeListener<PasswordValidatorCfg>,
+ ConfigurationAddListener<PasswordValidatorCfg>,
+ ConfigurationDeleteListener<PasswordValidatorCfg>
+
{
-
-
-
- // A mapping between the DNs of the config entries and the associated password
- // validators.
+ // A mapping between the DNs of the config entries and the associated
+ // password validators.
private ConcurrentHashMap<DN,PasswordValidator> passwordValidators;
- // The configuration handler for the Directory Server.
- private ConfigHandler configHandler;
-
/**
@@ -88,7 +81,6 @@
*/
public PasswordValidatorConfigManager()
{
- configHandler = DirectoryServer.getConfigHandler();
passwordValidators = new ConcurrentHashMap<DN,PasswordValidator>();
}
@@ -109,856 +101,325 @@
public void initializePasswordValidators()
throws ConfigException, InitializationException
{
- // First, get the configuration base entry.
- ConfigEntry baseEntry;
- try
+ // 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 password validator entries are added or removed.
+ rootConfiguration.addPasswordValidatorAddListener(this);
+ rootConfiguration.addPasswordValidatorDeleteListener(this);
+
+
+ //Initialize the existing password validators.
+ for (String validatorName : rootConfiguration.listPasswordValidators())
{
- DN validatorBase = DN.decode(DN_PWVALIDATOR_CONFIG_BASE);
- baseEntry = configHandler.getConfigEntry(validatorBase);
- }
- catch (Exception e)
- {
- if (debugEnabled())
+ PasswordValidatorCfg validatorConfiguration =
+ rootConfiguration.getPasswordValidator(validatorName);
+ validatorConfiguration.addChangeListener(this);
+
+ if (validatorConfiguration.isEnabled())
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_CANNOT_GET_BASE;
- String message = getMessage(msgID, String.valueOf(e));
- throw new ConfigException(msgID, message, e);
- }
-
- if (baseEntry == null)
- {
- // The password validator base entry does not exist. This is not
- // acceptable, so throw an exception.
- int msgID = MSGID_CONFIG_PWVALIDATOR_BASE_DOES_NOT_EXIST;
- String message = getMessage(msgID);
- throw new ConfigException(msgID, message);
- }
-
-
- // Register add and delete listeners with the validator base entry. We
- // don't care about modifications to it.
- baseEntry.registerAddListener(this);
- baseEntry.registerDeleteListener(this);
-
-
- // See if the base entry has any children. If not, then we don't need to do
- // anything else.
- if (! baseEntry.hasChildren())
- {
- return;
- }
-
-
- // Iterate through the child entries and process them as password validator
- // configuration entries.
- for (ConfigEntry childEntry : baseEntry.getChildren().values())
- {
- childEntry.registerChangeListener(this);
-
- StringBuilder unacceptableReason = new StringBuilder();
- if (! configAddIsAcceptable(childEntry, unacceptableReason))
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_PWVALIDATOR_ENTRY_UNACCEPTABLE,
- childEntry.getDN().toString(), unacceptableReason.toString());
- continue;
- }
-
- try
- {
- ConfigChangeResult result = applyConfigurationAdd(childEntry);
- if (result.getResultCode() != ResultCode.SUCCESS)
+ String className = validatorConfiguration.getValidatorClass();
+ try
{
- StringBuilder buffer = new StringBuilder();
-
- List<String> resultMessages = result.getMessages();
- if ((resultMessages == null) || (resultMessages.isEmpty()))
- {
- buffer.append(getMessage(MSGID_CONFIG_UNKNOWN_UNACCEPTABLE_REASON));
- }
- else
- {
- Iterator<String> iterator = resultMessages.iterator();
-
- buffer.append(iterator.next());
- while (iterator.hasNext())
- {
- buffer.append(EOL);
- buffer.append(iterator.next());
- }
- }
-
+ PasswordValidator<? extends PasswordValidatorCfg>
+ validator = loadValidator(className, validatorConfiguration);
+ passwordValidators.put(validatorConfiguration.dn(), validator);
+ DirectoryServer.registerPasswordValidator(validatorConfiguration.dn(),
+ validator);
+ }
+ catch (InitializationException ie)
+ {
logError(ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_PWVALIDATOR_CANNOT_CREATE_VALIDATOR,
- childEntry.getDN().toString(), buffer.toString());
+ ie.getMessage(), ie.getMessageID());
+ continue;
}
}
- catch (Exception e)
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_PWVALIDATOR_CANNOT_CREATE_VALIDATOR,
- childEntry.getDN().toString(), String.valueOf(e));
- }
}
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * modification is acceptable to this change listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested update.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed change is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configChangeIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationAddAcceptable(
+ PasswordValidatorCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that the entry has an appropriate objectclass for a password
- // validator.
- if (! configEntry.hasObjectClass(OC_PASSWORD_VALIDATOR))
+ if (configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the validator class name.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_PWVALIDATOR_CLASS,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_CLASS_NAME),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
+ // Get the name of the class and make sure we can instantiate it as a
+ // password validator.
+ String className = configuration.getValidatorClass();
+ try
{
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
+ loadValidator(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
return false;
}
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class validatorClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- validatorClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- try
- {
- PasswordValidator validator =
- (PasswordValidator) validatorClass.newInstance();
- }
- catch(Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS;
- String message = getMessage(msgID, validatorClass.getName(),
- String.valueOf(configEntry.getDN()),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // See if this password validator should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_PWVALIDATOR_ENABLED,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the password validator entry appears to be
- // acceptable.
+ // If we've gotten here, then it's fine.
return true;
}
/**
- * Attempts to apply a new configuration to this Directory Server component
- * based on the provided changed entry.
- *
- * @param configEntry The configuration entry that containing the updated
- * configuration for this component.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationAdd(
+ PasswordValidatorCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
+ configuration.addChangeListener(this);
- // Make sure that the entry has an appropriate objectclass for a password
- // validator.
- if (! configEntry.hasObjectClass(OC_PASSWORD_VALIDATOR))
+ if (! configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_OBJECTCLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
+ PasswordValidator<? extends PasswordValidatorCfg>
+ passwordValidator = null;
- // Get the corresponding password validator if it is active.
- PasswordValidator validator = passwordValidators.get(configEntryDN);
-
-
- // See if this validator should be enabled or disabled.
- boolean needsEnabled = false;
- BooleanConfigAttribute enabledAttr;
+ // Get the name of the class and make sure we can instantiate it as a
+ // password validator.
+ String className = configuration.getValidatorClass();
try
{
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_PWVALIDATOR_ENABLED,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- if (enabledAttr.activeValue())
- {
- if (validator == null)
- {
- needsEnabled = true;
- }
- else
- {
- // The validator is already active, so no action is required.
- }
- }
- else
- {
- if (validator == null)
- {
- // The validator is already disabled, so no action is required and we
- // can short-circuit out of this processing.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- // The validator is active, so it needs to be disabled. Do this and
- // return that we were successful.
- passwordValidators.remove(configEntryDN);
- validator.finalizePasswordValidator();
-
- DirectoryServer.deregisterPasswordValidator(configEntryDN);
-
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
+ passwordValidator = loadValidator(className, configuration);
}
- catch (Exception e)
+ catch (InitializationException ie)
{
- if (debugEnabled())
+ if (resultCode == ResultCode.SUCCESS)
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the validator class name. If it has
- // changed, then we will not try to dynamically apply it.
- String className;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_PWVALIDATOR_CLASS,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_CLASS_NAME),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- className = classNameAttr.pendingValue();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- boolean classChanged = false;
- String oldClassName = null;
- if (validator != null)
- {
- oldClassName = validator.getClass().getName();
- classChanged = (! className.equals(oldClassName));
- }
-
-
- if (classChanged)
- {
- // This will not be applied dynamically. Add a message to the response
- // and indicate that admin action is required.
- adminActionRequired = true;
- messages.add(getMessage(MSGID_CONFIG_PWVALIDATOR_CLASS_ACTION_REQUIRED,
- String.valueOf(oldClassName),
- String.valueOf(className),
- String.valueOf(configEntryDN)));
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- if (needsEnabled)
- {
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class validatorClass = Class.forName(className);
- validator = (PasswordValidator) validatorClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
}
- try
- {
- validator.initializePasswordValidator(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
-
- passwordValidators.put(configEntryDN, validator);
- DirectoryServer.registerPasswordValidator(configEntryDN, validator);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ messages.add(ie.getMessage());
}
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ passwordValidators.put(configuration.dn(), passwordValidator);
+ DirectoryServer.registerPasswordValidator(configuration.dn(),
+ passwordValidator);
+ }
- // If we've gotten here, then there haven't been any changes to anything
- // that we care about.
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * add is acceptable to this add listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested add.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed entry is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configAddIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationDeleteAcceptable(
+ PasswordValidatorCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that no entry already exists with the specified DN.
- DN configEntryDN = configEntry.getDN();
- if (passwordValidators.containsKey(configEntryDN))
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_EXISTS;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry has an appropriate objectclass for a password
- // validator.
- if (! configEntry.hasObjectClass(OC_PASSWORD_VALIDATOR))
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the password validator class.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_PWVALIDATOR_CLASS,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_CLASS_NAME),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class validatorClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- validatorClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- PasswordValidator validator;
- try
- {
- validator = (PasswordValidator) validatorClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS;
- String message = getMessage(msgID, validatorClass.getName(),
- String.valueOf(configEntryDN),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If the validator is a configurable component, then make sure that
- // its configuration is valid.
- if (validator instanceof ConfigurableComponent)
- {
- ConfigurableComponent cc = (ConfigurableComponent) validator;
- LinkedList<String> errorMessages = new LinkedList<String>();
- if (! cc.hasAcceptableConfiguration(configEntry, errorMessages))
- {
- if (errorMessages.isEmpty())
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_UNACCEPTABLE_CONFIG;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
- else
- {
- Iterator<String> iterator = errorMessages.iterator();
- unacceptableReason.append(iterator.next());
- while (iterator.hasNext())
- {
- unacceptableReason.append(" ");
- unacceptableReason.append(iterator.next());
- }
- }
-
- return false;
- }
- }
-
-
- // See if this validator should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_PWVALIDATOR_ENABLED,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the validator entry appears to be acceptable.
+ // FIXME -- We should try to perform some check to determine whether the
+ // password validator is in use.
return true;
}
/**
- * Attempts to apply a new configuration based on the provided added entry.
- *
- * @param configEntry The new configuration entry that contains the
- * configuration to apply.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationDelete(
+ PasswordValidatorCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ DirectoryServer.deregisterPasswordValidator(configuration.dn());
+
+ PasswordValidator passwordValidator =
+ passwordValidators.remove(configuration.dn());
+ if (passwordValidator != null)
+ {
+ passwordValidator.finalizePasswordValidator();
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ PasswordValidatorCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ if (configuration.isEnabled())
+ {
+ // Get the name of the class and make sure we can instantiate it as a
+ // password validator.
+ String className = configuration.getValidatorClass();
+ try
+ {
+ loadValidator(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
+ return false;
+ }
+ }
+
+ // If we've gotten here, then it's fine.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ PasswordValidatorCfg configuration)
+ {
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
- // Make sure that the entry has an appropriate objectclass for a password
- // validator.
- if (! configEntry.hasObjectClass(OC_PASSWORD_VALIDATOR))
+ // Get the existing validator if it's already enabled.
+ PasswordValidator existingValidator =
+ passwordValidators.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())
{
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_OBJECTCLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
+ if (existingValidator != null)
+ {
+ DirectoryServer.deregisterPasswordValidator(configuration.dn());
+
+ PasswordValidator passwordValidator =
+ passwordValidators.remove(configuration.dn());
+ if (passwordValidator != null)
+ {
+ passwordValidator.finalizePasswordValidator();
+ }
+ }
+
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
- // See if this validator should be enabled or disabled.
- BooleanConfigAttribute enabledAttr;
- try
+ // Get the class for the password validator. If the validator is already
+ // enabled, then we shouldn't do anything with it although if the class has
+ // changed then we'll at least need to indicate that administrative action
+ // is required. If the validator is disabled, then instantiate the class
+ // and initialize and register it as a password validator.
+ String className = configuration.getValidatorClass();
+ if (existingValidator != null)
{
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_PWVALIDATOR_ENABLED,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
+ if (! className.equals(existingValidator.getClass().getName()))
{
- // The attribute doesn't exist, so it will be disabled by default.
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.SUCCESS;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else if (! enabledAttr.activeValue())
- {
- // It is explicitly configured as disabled, so we don't need to do
- // anything.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
+ adminActionRequired = true;
}
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
-
- // Make sure that the entry specifies the validator class name.
- String className;
+ PasswordValidator<? extends PasswordValidatorCfg>
+ passwordValidator = null;
try
{
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_PWVALIDATOR_CLASS,
- getMessage(MSGID_CONFIG_PWVALIDATOR_DESCRIPTION_CLASS_NAME),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
+ passwordValidator = loadValidator(className, configuration);
+ }
+ catch (InitializationException ie)
+ {
+ if (resultCode == ResultCode.SUCCESS)
{
- int msgID = MSGID_CONFIG_PWVALIDATOR_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
+ resultCode = DirectoryServer.getServerErrorResultCode();
}
- className = classNameAttr.pendingValue();
+ messages.add(ie.getMessage());
+ }
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ passwordValidators.put(configuration.dn(), passwordValidator);
+ DirectoryServer.registerPasswordValidator(configuration.dn(),
+ passwordValidator);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * Loads the specified class, instantiates it as a password validator, and
+ * optionally initializes that instance.
+ *
+ * @param className The fully-qualified name of the password validator
+ * class to load, instantiate, and initialize.
+ * @param configuration The configuration to use to initialize the
+ * password validator, or {@code null} if the
+ * password validator should not be initialized.
+ *
+ * @return The possibly initialized password validator.
+ *
+ * @throws InitializationException If a problem occurred while attempting to
+ * initialize the password validator.
+ */
+ private PasswordValidator<? extends PasswordValidatorCfg>
+ loadValidator(String className,
+ PasswordValidatorCfg configuration)
+ throws InitializationException
+ {
+ try
+ {
+ PasswordValidatorCfgDefn definition =
+ PasswordValidatorCfgDefn.getInstance();
+ ClassPropertyDefinition propertyDefinition =
+ definition.getValidatorClassPropertyDefinition();
+ Class<? extends PasswordValidator> validatorClass =
+ propertyDefinition.loadClass(className, PasswordValidator.class);
+ PasswordValidator<? extends PasswordValidatorCfg> validator =
+ (PasswordValidator<? extends PasswordValidatorCfg>)
+ validatorClass.newInstance();
+
+ if (configuration != null)
+ {
+ Method method =
+ validator.getClass().getMethod("initializePasswordValidator",
+ configuration.definition().getServerConfigurationClass());
+ method.invoke(validator, configuration);
+ }
+
+ return validator;
}
catch (Exception e)
{
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Load and initialize the validator class, and register it with the
- // Directory Server.
- PasswordValidator validator;
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class validatorClass = Class.forName(className);
- validator = (PasswordValidator) validatorClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PWVALIDATOR_INVALID_CLASS;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
- try
- {
- validator.initializePasswordValidator(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
int msgID = MSGID_CONFIG_PWVALIDATOR_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ String message = getMessage(msgID, className,
+ String.valueOf(configuration.dn()),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
}
-
-
- passwordValidators.put(configEntryDN, validator);
- DirectoryServer.registerPasswordValidator(configEntryDN, validator);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
- * Indicates whether it is acceptable to remove the provided configuration
- * entry.
- *
- * @param configEntry The configuration entry that will be removed
- * from the configuration.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed delete is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry may be removed from the
- * configuration, or <CODE>false</CODE> if not.
- */
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- // A delete should always be acceptable, so just return true.
- return true;
- }
-
-
-
- /**
- * Attempts to apply a new configuration based on the provided deleted entry.
- *
- * @param configEntry The new configuration entry that has been deleted.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry)
- {
- DN configEntryDN = configEntry.getDN();
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
-
-
- // See if the entry is registered as a password validator. If so,
- // deregister it and stop the validator.
- PasswordValidator validator = passwordValidators.remove(configEntryDN);
- if (validator != null)
- {
- DirectoryServer.deregisterPasswordValidator(configEntryDN);
-
- validator.finalizePasswordValidator();
- }
-
-
- return new ConfigChangeResult(resultCode, adminActionRequired);
}
}
diff --git a/opends/src/server/org/opends/server/core/PluginConfigManager.java b/opends/src/server/org/opends/server/core/PluginConfigManager.java
index 43bd420..50c7afa 100644
--- a/opends/src/server/org/opends/server/core/PluginConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -28,17 +28,24 @@
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
+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.PluginCfgDefn;
+import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConfigAddListener;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.IntermediateResponsePluginResult;
import org.opends.server.api.plugin.LDIFPluginResult;
@@ -52,11 +59,7 @@
import org.opends.server.api.plugin.SearchEntryPluginResult;
import org.opends.server.api.plugin.SearchReferencePluginResult;
import org.opends.server.api.plugin.StartupPluginResult;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.MultiChoiceConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
@@ -68,11 +71,9 @@
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -92,11 +93,10 @@
* also provides methods for invoking all the plugins of a given type.
*/
public class PluginConfigManager
- implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
+ implements ConfigurationAddListener<PluginCfg>,
+ ConfigurationDeleteListener<PluginCfg>,
+ ConfigurationChangeListener<PluginCfg>
{
-
-
-
// Arrays for holding the plugins of each type.
private DirectoryServerPlugin[] startupPlugins;
private DirectoryServerPlugin[] shutdownPlugins;
@@ -147,7 +147,9 @@
// The mapping between the DN of a plugin entry and the plugin instance loaded
// from that entry.
- private ConcurrentHashMap<DN,DirectoryServerPlugin> registeredPlugins;
+ private ConcurrentHashMap<DN,
+ DirectoryServerPlugin<? extends PluginCfg>>
+ registeredPlugins;
// The lock that will provide threadsafe access to the sets of registered
// plugins.
@@ -208,7 +210,8 @@
searchResultReferencePlugins = new DirectoryServerPlugin[0];
intermediateResponsePlugins = new DirectoryServerPlugin[0];
registeredPlugins =
- new ConcurrentHashMap<DN,DirectoryServerPlugin>();
+ new ConcurrentHashMap<DN,
+ DirectoryServerPlugin<? extends PluginCfg>>();
}
@@ -238,298 +241,186 @@
registeredPlugins.clear();
- // Get the configuration entry that is the root of all the plugins in the
- // server.
- ConfigEntry pluginRoot;
+ // 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 plugin entries are added or removed.
+ rootConfiguration.addPluginAddListener(this);
+ rootConfiguration.addPluginDeleteListener(this);
+
+
+ //Initialize the existing plugins.
+ for (String pluginName : rootConfiguration.listPlugins())
+ {
+ PluginCfg pluginConfiguration =
+ rootConfiguration.getPlugin(pluginName);
+
+ if (! pluginConfiguration.isEnabled())
+ {
+ continue;
+ }
+
+ // Create a set of plugin types for the plugin.
+ HashSet<PluginType> initTypes = new HashSet<PluginType>();
+ for (PluginCfgDefn.PluginType pluginType :
+ pluginConfiguration.getPluginType())
+ {
+ PluginType t = getPluginType(pluginType);
+ if ((pluginTypes == null) || pluginTypes.contains(t))
+ {
+ initTypes.add(t);
+ }
+ }
+
+ if (initTypes.isEmpty())
+ {
+ continue;
+ }
+
+ pluginConfiguration.addChangeListener(this);
+
+ try
+ {
+ DirectoryServerPlugin<? extends PluginCfg> plugin =
+ loadPlugin(pluginConfiguration.getPluginClass(), initTypes,
+ pluginConfiguration);
+ registerPlugin(plugin, pluginConfiguration.dn(), initTypes);
+ }
+ catch (InitializationException ie)
+ {
+ logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
+ ie.getMessage(), ie.getMessageID());
+ continue;
+ }
+ }
+ }
+
+
+
+ /**
+ * Loads the specified class, instantiates it as a plugin, and optionally
+ * initializes that plugin.
+ *
+ * @param className The fully-qualified name of the plugin class to
+ * load, instantiate, and initialize.
+ * @param pluginTypes The set of plugin types for the plugins to
+ * initialize, or {@code null} to initialize all types
+ * of plugins defined in the server configuration. In
+ * general, this should only be non-null for cases in
+ * which the server is running in a special mode that
+ * only uses a minimal set of plugins (e.g., LDIF
+ * import or export).
+ * @param configuration The configuration to use to initialize the plugin,
+ * or {@code null} if the plugin should not be
+ * initialized.
+ *
+ * @return The possibly initialized plugin.
+ *
+ * @throws InitializationException If a problem occurred while attempting to
+ * initialize the plugin.
+ */
+ private DirectoryServerPlugin<? extends PluginCfg>
+ loadPlugin(String className, Set<PluginType> pluginTypes,
+ PluginCfg configuration)
+ throws InitializationException
+ {
try
{
- DN pluginRootDN = DN.decode(DN_PLUGIN_BASE);
- pluginRoot = DirectoryServer.getConfigEntry(pluginRootDN);
+ PluginCfgDefn definition =
+ PluginCfgDefn.getInstance();
+ ClassPropertyDefinition propertyDefinition =
+ definition.getPluginClassPropertyDefinition();
+ Class<? extends DirectoryServerPlugin> pluginClass =
+ propertyDefinition.loadClass(className, DirectoryServerPlugin.class);
+ DirectoryServerPlugin<? extends PluginCfg> plugin =
+ (DirectoryServerPlugin<? extends PluginCfg>)
+ pluginClass.newInstance();
+
+ if (configuration != null)
+ {
+ Method method =
+ plugin.getClass().getMethod("initializePlugin", Set.class,
+ configuration.definition().getServerConfigurationClass());
+ method.invoke(plugin, pluginTypes, configuration);
+ }
+
+ return plugin;
}
catch (Exception e)
{
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_CONFIG_BASE;
- String message = getMessage(msgID, stackTraceToSingleLineString(e));
- throw new ConfigException(msgID, message, e);
+ int msgID = MSGID_CONFIG_PLUGIN_CANNOT_INITIALIZE;
+ String message = getMessage(msgID, className,
+ String.valueOf(configuration.dn()),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
}
+ }
- // If the configuration root entry is null, then assume it doesn't exist.
- // In that case, then fail. At least that entry must exist in the
- // configuration, even if there are no plugins defined below it.
- if (pluginRoot == null)
+
+ /**
+ * Gets the OpenDS plugin type object that corresponds to the configuration
+ * counterpart.
+ *
+ * @param configPluginType The configuration plugin type for which to
+ * retrieve the OpenDS plugin type.
+ */
+ private PluginType getPluginType(PluginCfgDefn.PluginType
+ configPluginType)
+ {
+ switch (configPluginType)
{
- int msgID = MSGID_CONFIG_PLUGIN_BASE_DOES_NOT_EXIST;
- String message = getMessage(msgID);
- throw new ConfigException(msgID, message);
- }
-
-
- // Register add and delete listeners for the base entry so that we can be
- // notified of added or removed plugins.
- pluginRoot.registerAddListener(this);
- pluginRoot.registerDeleteListener(this);
-
-
- // Iterate through the set of immediate children below the plugin config
- // root.
-parsePluginEntry:
- for (ConfigEntry entry : pluginRoot.getChildren().values())
- {
- DN entryDN = entry.getDN();
-
-
- // Register as a change listener for this backend entry so that we will
- // be notified of any changes that may be made to it.
- entry.registerChangeListener(this);
-
-
- // Check to see if this entry appears to contain a plugin configuration.
- // If not, then log a warning and skip it.
- try
- {
- SearchFilter filter =
- SearchFilter.createFilterFromString("(objectClass=" +
- OC_PLUGIN + ")");
- if (! filter.matchesEntry(entry.getEntry()))
- {
- int msgID = MSGID_CONFIG_PLUGIN_ENTRY_DOES_NOT_HAVE_PLUGIN_CONFIG;
- String message = getMessage(msgID, String.valueOf(entryDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_WARNING, message, msgID);
- continue;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_ERROR_INTERACTING_WITH_PLUGIN_ENTRY;
- String message = getMessage(msgID, String.valueOf(entryDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_WARNING, message, msgID);
- continue;
- }
-
-
- // See if the entry contains an attribute that indicates whether the
- // plugin should be enabled. If it does not, or if it is not set to
- // "true", then skip it.
- int msgID = MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_ENABLED;
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_PLUGIN_ENABLED, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute enabledAttr =
- (BooleanConfigAttribute) entry.getConfigAttribute(enabledStub);
- if (enabledAttr == null)
- {
- // The attribute is not present, so this plugin will be disabled.
- // Log a message and continue.
- msgID = MSGID_CONFIG_PLUGIN_NO_ENABLED_ATTR;
- String message = getMessage(msgID, String.valueOf(entryDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_WARNING, message, msgID);
- continue;
- }
- else if (! enabledAttr.activeValue())
- {
- // The plugin is explicitly disabled. Log a mild warning and
- // continue.
- msgID = MSGID_CONFIG_PLUGIN_DISABLED;
- String message = getMessage(msgID, String.valueOf(entryDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.INFORMATIONAL, message, msgID);
- continue;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_PLUGIN_UNABLE_TO_DETERMINE_ENABLED_STATE;
- String message = getMessage(msgID, String.valueOf(entryDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
-
- // Get the set of plugin types for this entry. There must be at least one
- // plugin type specified, and all plugin type names must be valid.
- HashSet<PluginType> types = new HashSet<PluginType>();
- msgID = MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_PLUGIN_TYPE;
- MultiChoiceConfigAttribute typesStub =
- new MultiChoiceConfigAttribute(ATTR_PLUGIN_TYPE, getMessage(msgID),
- true, true, true,
- PluginType.getPluginTypeNames());
- try
- {
- MultiChoiceConfigAttribute typesAttr =
- (MultiChoiceConfigAttribute) entry.getConfigAttribute(typesStub);
- if ((typesAttr == null) || typesAttr.activeValues().isEmpty())
- {
- msgID = MSGID_CONFIG_PLUGIN_NO_PLUGIN_TYPES;
- String message = getMessage(msgID, String.valueOf(entryDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_ERROR, message, msgID);
- continue;
- }
- else
- {
- for (String s : typesAttr.activeValues())
- {
- PluginType t = PluginType.forName(s.toLowerCase());
- if (t == null)
- {
- msgID = MSGID_CONFIG_PLUGIN_INVALID_PLUGIN_TYPE;
- String message = getMessage(msgID, String.valueOf(entryDN), s);
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_ERROR, message, msgID);
- continue parsePluginEntry;
- }
- else
- {
- if ((pluginTypes == null) || pluginTypes.contains(t))
- {
- types.add(t);
- }
- }
- }
-
- if (types.isEmpty())
- {
- // This means that the plugin doesn't have any of the types that
- // we are interested in so we don't need to initialize it.
- continue;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_PLUGIN_TYPES;
- String message = getMessage(msgID, String.valueOf(entryDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
-
- // FIXME -- We need configuration attributes that can be used to define
- // the order in which plugins are loaded and/or executed.
-
-
- // See if the entry contains an attribute that specifies the class name
- // for the plugin implementation. If it does, then load it and make sure
- // that it's a valid plugin implementation. If there is no such
- // attribute, the specified class cannot be loaded, or it does not contain
- // a valid plugin implementation, then log an error and skip it.
- String className;
- msgID = MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_CLASS;
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_PLUGIN_CLASS, getMessage(msgID),
- true, false, true);
- try
- {
- StringConfigAttribute classAttr =
- (StringConfigAttribute) entry.getConfigAttribute(classStub);
- if (classAttr == null)
- {
- msgID = MSGID_CONFIG_PLUGIN_NO_CLASS_ATTR;
- String message = getMessage(msgID, String.valueOf(entryDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_ERROR, message, msgID);
- continue;
- }
- else
- {
- className = classAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_CLASS;
- String message = getMessage(msgID, String.valueOf(entryDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
- DirectoryServerPlugin plugin;
- try
- {
- // FIXME --Should we use a custom class loader for this?
- Class pluginClass = Class.forName(className);
- plugin = (DirectoryServerPlugin) pluginClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_PLUGIN_CANNOT_INSTANTIATE;
- String message = getMessage(msgID, String.valueOf(className),
- String.valueOf(entryDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
-
- // Perform the necessary initialization for the plugin entry.
- try
- {
- plugin.initializeInternal(entryDN, types);
- plugin.initializePlugin(types, entry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_PLUGIN_CANNOT_INITIALIZE;
- String message = getMessage(msgID, String.valueOf(className),
- String.valueOf(entryDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- continue;
- }
-
-
- // Register the plugin with the server.
- registerPlugin(plugin, entryDN, types);
+ case STARTUP: return PluginType.STARTUP;
+ case SHUTDOWN: return PluginType.SHUTDOWN;
+ case POSTCONNECT: return PluginType.POST_CONNECT;
+ case POSTDISCONNECT: return PluginType.POST_DISCONNECT;
+ case LDIFIMPORT: return PluginType.LDIF_IMPORT;
+ case LDIFEXPORT: return PluginType.LDIF_EXPORT;
+ case PREPARSEABANDON: return PluginType.PRE_PARSE_ABANDON;
+ case PREPARSEADD: return PluginType.PRE_PARSE_ADD;
+ case PREPARSEBIND: return PluginType.PRE_PARSE_BIND;
+ case PREPARSECOMPARE: return PluginType.PRE_PARSE_COMPARE;
+ case PREPARSEDELETE: return PluginType.PRE_PARSE_DELETE;
+ case PREPARSEEXTENDED: return PluginType.PRE_PARSE_EXTENDED;
+ case PREPARSEMODIFY: return PluginType.PRE_PARSE_MODIFY;
+ case PREPARSEMODIFYDN: return PluginType.PRE_PARSE_MODIFY_DN;
+ case PREPARSESEARCH: return PluginType.PRE_PARSE_SEARCH;
+ case PREPARSEUNBIND: return PluginType.PRE_PARSE_UNBIND;
+ case PREOPERATIONADD: return PluginType.PRE_OPERATION_ADD;
+ case PREOPERATIONBIND: return PluginType.PRE_OPERATION_BIND;
+ case PREOPERATIONCOMPARE: return PluginType.PRE_OPERATION_COMPARE;
+ case PREOPERATIONDELETE: return PluginType.PRE_OPERATION_DELETE;
+ case PREOPERATIONEXTENDED: return PluginType.PRE_OPERATION_EXTENDED;
+ case PREOPERATIONMODIFY: return PluginType.PRE_OPERATION_MODIFY;
+ case PREOPERATIONMODIFYDN: return PluginType.PRE_OPERATION_MODIFY_DN;
+ case PREOPERATIONSEARCH: return PluginType.PRE_OPERATION_SEARCH;
+ case POSTOPERATIONABANDON: return PluginType.POST_OPERATION_ABANDON;
+ case POSTOPERATIONADD: return PluginType.POST_OPERATION_ADD;
+ case POSTOPERATIONBIND: return PluginType.POST_OPERATION_BIND;
+ case POSTOPERATIONCOMPARE: return PluginType.POST_OPERATION_COMPARE;
+ case POSTOPERATIONDELETE: return PluginType.POST_OPERATION_DELETE;
+ case POSTOPERATIONEXTENDED: return PluginType.POST_OPERATION_EXTENDED;
+ case POSTOPERATIONMODIFY: return PluginType.POST_OPERATION_MODIFY;
+ case POSTOPERATIONMODIFYDN: return PluginType.POST_OPERATION_MODIFY_DN;
+ case POSTOPERATIONSEARCH: return PluginType.POST_OPERATION_SEARCH;
+ case POSTOPERATIONUNBIND: return PluginType.POST_OPERATION_UNBIND;
+ case POSTRESPONSEADD: return PluginType.POST_RESPONSE_ADD;
+ case POSTRESPONSEBIND: return PluginType.POST_RESPONSE_BIND;
+ case POSTRESPONSECOMPARE: return PluginType.POST_RESPONSE_COMPARE;
+ case POSTRESPONSEDELETE: return PluginType.POST_RESPONSE_DELETE;
+ case POSTRESPONSEEXTENDED: return PluginType.POST_RESPONSE_EXTENDED;
+ case POSTRESPONSEMODIFY: return PluginType.POST_RESPONSE_MODIFY;
+ case POSTRESPONSEMODIFYDN: return PluginType.POST_RESPONSE_MODIFY_DN;
+ case POSTRESPONSESEARCH: return PluginType.POST_RESPONSE_SEARCH;
+ case SEARCHRESULTENTRY: return PluginType.SEARCH_RESULT_ENTRY;
+ case SEARCHRESULTREFERENCE: return PluginType.SEARCH_RESULT_REFERENCE;
+ case INTERMEDIATERESPONSE: return PluginType.INTERMEDIATE_RESPONSE;
+ default: return null;
}
}
@@ -544,7 +435,7 @@
try
{
- Iterator<DirectoryServerPlugin> iterator =
+ Iterator<DirectoryServerPlugin<? extends PluginCfg>> iterator =
registeredPlugins.values().iterator();
while (iterator.hasNext())
{
@@ -578,7 +469,9 @@
* @return The set of plugins that have been registered with the Directory
* Server.
*/
- public ConcurrentHashMap<DN,DirectoryServerPlugin> getRegisteredPlugins()
+ public ConcurrentHashMap<DN,
+ DirectoryServerPlugin<? extends PluginCfg>>
+ getRegisteredPlugins()
{
return registeredPlugins;
}
@@ -602,540 +495,6 @@
/**
- * Indicates whether the configuration entry that will result from a proposed
- * modification is acceptable to this change listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested update.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed change is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
- */
- public boolean configChangeIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- // Make sure that the entry has an appropriate objectclass for a plugin.
- if (! configEntry.hasObjectClass(OC_PLUGIN))
- {
- int msgID = MSGID_CONFIG_PLUGIN_ENTRY_DOES_NOT_HAVE_PLUGIN_CONFIG;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the plugin class name.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_PLUGIN_CLASS,
- getMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_CLASS),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_PLUGIN_NO_CLASS_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_CLASS;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class pluginClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- pluginClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_CLASS;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- try
- {
- DirectoryServerPlugin plugin =
- (DirectoryServerPlugin) pluginClass.newInstance();
- }
- catch(Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_INSTANTIATE;
- String message = getMessage(msgID, pluginClass.getName(),
- String.valueOf(configEntry.getDN()),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // See if this plugin should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_PLUGIN_ENABLED,
- getMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_PLUGIN_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_UNABLE_TO_DETERMINE_ENABLED_STATE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // See the plugin types specified for this plugin and make sure that they
- // are valid.
- MultiChoiceConfigAttribute typesAttr;
- try
- {
- MultiChoiceConfigAttribute typesStub =
- new MultiChoiceConfigAttribute(ATTR_PLUGIN_TYPE,
- getMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_PLUGIN_TYPE),
- true, true, true, PluginType.getPluginTypeNames());
- typesAttr = (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(typesStub);
-
- if (typesAttr == null)
- {
- int msgID = MSGID_CONFIG_PLUGIN_NO_PLUGIN_TYPES;
- String message = getMessage(msgID, String.valueOf(configEntry.getDN()));
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_PLUGIN_TYPES;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the plugin entry appears to be acceptable.
- return true;
- }
-
-
-
- /**
- * Attempts to apply a new configuration to this Directory Server component
- * based on the provided changed entry.
- *
- * @param configEntry The configuration entry that containing the updated
- * configuration for this component.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry)
- {
- DN configEntryDN = configEntry.getDN();
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Make sure that the entry has an appropriate objectclass for a plugin.
- if (! configEntry.hasObjectClass(OC_PLUGIN))
- {
- int msgID = MSGID_CONFIG_PLUGIN_ENTRY_DOES_NOT_HAVE_PLUGIN_CONFIG;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Get the corresponding plugin if it is active.
- DirectoryServerPlugin plugin = registeredPlugins.get(configEntryDN);
-
-
- // See if this plugin should be enabled or disabled.
- boolean needsEnabled = false;
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_PLUGIN_ENABLED,
- getMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_PLUGIN_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- if (enabledAttr.activeValue())
- {
- if (plugin == null)
- {
- needsEnabled = true;
- }
- else
- {
- // The plugin is already active, so no action is required.
- }
- }
- else
- {
- if (plugin == null)
- {
- // The plugin is already disabled, so no action is required and we
- // can short-circuit out of this processing.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- // The plugin is active, so it needs to be disabled. Do this and
- // return that we were successful.
- deregisterPlugin(configEntryDN);
- plugin.finalizePlugin();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_UNABLE_TO_DETERMINE_ENABLED_STATE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the set of plugin types. If it has
- // changed, then we will not try to dynamically apply it.
- HashSet<PluginType> pluginTypes = new HashSet<PluginType>();
- try
- {
- MultiChoiceConfigAttribute typesStub =
- new MultiChoiceConfigAttribute(ATTR_PLUGIN_TYPE,
- getMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_PLUGIN_TYPE),
- true, true, true, PluginType.getPluginTypeNames());
- MultiChoiceConfigAttribute typesAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(typesStub);
- if (typesAttr == null)
- {
- int msgID = MSGID_CONFIG_PLUGIN_NO_PLUGIN_TYPES;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- for (String s : typesAttr.activeValues())
- {
- PluginType t = PluginType.forName(s.toLowerCase());
- if (t == null)
- {
- int msgID = MSGID_CONFIG_PLUGIN_INVALID_PLUGIN_TYPE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN), s));
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- pluginTypes.add(t);
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_PLUGIN_TYPES;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the plugin class name. If it has
- // changed, then we will not try to dynamically apply it.
- String className;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_PLUGIN_CLASS,
- getMessage(MSGID_CONFIG_PLUGIN_ATTR_DESCRIPTION_CLASS),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_PLUGIN_NO_CLASS_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- className = classNameAttr.pendingValue();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_GET_CLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- boolean classChanged = false;
- String oldClassName = null;
- if (plugin != null)
- {
- oldClassName = plugin.getClass().getName();
- classChanged = (! className.equals(oldClassName));
- }
-
-
- if (classChanged)
- {
- // This will not be applied dynamically. Add a message to the response
- // and indicate that admin action is required.
- adminActionRequired = true;
- messages.add(getMessage(MSGID_CONFIG_PLUGIN_CLASS_ACTION_REQUIRED,
- String.valueOf(oldClassName),
- String.valueOf(className),
- String.valueOf(configEntryDN)));
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- if (needsEnabled)
- {
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class pluginClass = Class.forName(className);
- plugin = (DirectoryServerPlugin) pluginClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_INSTANTIATE;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- try
- {
- plugin.initializeInternal(configEntryDN, pluginTypes);
- plugin.initializePlugin(pluginTypes, configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_PLUGIN_CANNOT_INITIALIZE;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
-
- registerPlugin(plugin, configEntryDN, pluginTypes);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // If we've gotten here, then there haven't been any changes to anything
- // that we care about.
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
- * Indicates whether the configuration entry that will result from a proposed
- * add is acceptable to this add listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested add.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed entry is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
- */
- public boolean configAddIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- // NYI
- return false;
- }
-
-
-
- /**
- * Attempts to apply a new configuration based on the provided added entry.
- *
- * @param configEntry The new configuration entry that contains the
- * configuration to apply.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry)
- {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // NYI
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
- * Indicates whether it is acceptable to remove the provided configuration
- * entry.
- *
- * @param configEntry The configuration entry that will be removed
- * from the configuration.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed delete is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry may be removed from the
- * configuration, or <CODE>false</CODE> if not.
- */
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- // NYI
- return false;
- }
-
-
-
- /**
- * Attempts to apply a new configuration based on the provided deleted entry.
- *
- * @param configEntry The new configuration entry that has been deleted.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry)
- {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // NYI
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
* Registers the provided plugin with this plugin config manager and ensures
* that it will be invoked in the specified ways.
*
@@ -1145,8 +504,9 @@
* @param pluginTypes The plugin types that will be used to control the
* points at which the provided plugin is invoked.
*/
- private void registerPlugin(DirectoryServerPlugin plugin, DN pluginEntryDN,
- HashSet<PluginType> pluginTypes)
+ private void registerPlugin(
+ DirectoryServerPlugin<? extends PluginCfg> plugin,
+ DN pluginEntryDN, Set<PluginType> pluginTypes)
{
pluginLock.lock();
@@ -1368,9 +728,10 @@
{
pluginLock.lock();
+ DirectoryServerPlugin<? extends PluginCfg> plugin;
try
{
- DirectoryServerPlugin plugin = registeredPlugins.remove(configEntryDN);
+ plugin = registeredPlugins.remove(configEntryDN);
if (plugin == null)
{
return;
@@ -1556,6 +917,8 @@
{
pluginLock.unlock();
}
+
+ plugin.finalizePlugin();
}
@@ -5118,5 +4481,239 @@
return result;
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(PluginCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ if (configuration.isEnabled())
+ {
+ // Create a set of plugin types for the plugin.
+ HashSet<PluginType> pluginTypes = new HashSet<PluginType>();
+ for (PluginCfgDefn.PluginType pluginType :
+ configuration.getPluginType())
+ {
+ pluginTypes.add(getPluginType(pluginType));
+ }
+
+ // Get the name of the class and make sure we can instantiate it as a
+ // plugin.
+ String className = configuration.getPluginClass();
+ try
+ {
+ loadPlugin(className, pluginTypes, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
+ return false;
+ }
+ }
+
+ // If we've gotten here, then it's fine.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(
+ PluginCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ configuration.addChangeListener(this);
+
+ if (! configuration.isEnabled())
+ {
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ // Create a set of plugin types for the plugin.
+ HashSet<PluginType> pluginTypes = new HashSet<PluginType>();
+ for (PluginCfgDefn.PluginType pluginType :
+ configuration.getPluginType())
+ {
+ pluginTypes.add(getPluginType(pluginType));
+ }
+
+ // Get the name of the class and make sure we can instantiate it as a
+ // plugin.
+ DirectoryServerPlugin<? extends PluginCfg> plugin = null;
+ String className = configuration.getPluginClass();
+ try
+ {
+ plugin = loadPlugin(className, pluginTypes, configuration);
+ }
+ catch (InitializationException ie)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(ie.getMessage());
+ }
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ registerPlugin(plugin, configuration.dn(), pluginTypes);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(
+ PluginCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ // We will always allow plugins to be removed.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(
+ PluginCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ deregisterPlugin(configuration.dn());
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ PluginCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ if (configuration.isEnabled())
+ {
+ // Create a set of plugin types for the plugin.
+ HashSet<PluginType> pluginTypes = new HashSet<PluginType>();
+ for (PluginCfgDefn.PluginType pluginType :
+ configuration.getPluginType())
+ {
+ pluginTypes.add(getPluginType(pluginType));
+ }
+
+ // Get the name of the class and make sure we can instantiate it as a
+ // plugin.
+ String className = configuration.getPluginClass();
+ try
+ {
+ loadPlugin(className, pluginTypes, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
+ return false;
+ }
+ }
+
+ // If we've gotten here, then it's fine.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ PluginCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Get the existing plugin if it's already enabled.
+ DirectoryServerPlugin existingPlugin =
+ registeredPlugins.get(configuration.dn());
+
+
+ // If the new configuration has the plugin disabled, then deregister it if
+ // it is enabled, or do nothing if it's already disabled.
+ if (! configuration.isEnabled())
+ {
+ if (existingPlugin != null)
+ {
+ deregisterPlugin(configuration.dn());
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+ // Get the class for the identity mapper. If the mapper is already enabled,
+ // then we shouldn't do anything with it although if the class has changed
+ // then we'll at least need to indicate that administrative action is
+ // required. If the mapper is disabled, then instantiate the class and
+ // initialize and register it as an identity mapper.
+ String className = configuration.getPluginClass();
+ if (existingPlugin != null)
+ {
+ if (! className.equals(existingPlugin.getClass().getName()))
+ {
+ adminActionRequired = true;
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ // Create a set of plugin types for the plugin.
+ HashSet<PluginType> pluginTypes = new HashSet<PluginType>();
+ for (PluginCfgDefn.PluginType pluginType :
+ configuration.getPluginType())
+ {
+ pluginTypes.add(getPluginType(pluginType));
+ }
+
+ DirectoryServerPlugin<? extends PluginCfg> plugin = null;
+ try
+ {
+ plugin = loadPlugin(className, pluginTypes, configuration);
+ }
+ catch (InitializationException ie)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(ie.getMessage());
+ }
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ registerPlugin(plugin, configuration.dn(), pluginTypes);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
}
diff --git a/opends/src/server/org/opends/server/core/SASLConfigManager.java b/opends/src/server/org/opends/server/core/SASLConfigManager.java
index acbffcc..f46d42a 100644
--- a/opends/src/server/org/opends/server/core/SASLConfigManager.java
+++ b/opends/src/server/org/opends/server/core/SASLConfigManager.java
@@ -28,22 +28,21 @@
+import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
-import org.opends.server.api.ConfigAddListener;
-import org.opends.server.api.ConfigChangeListener;
-import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.api.ConfigHandler;
-import org.opends.server.api.ConfigurableComponent;
+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.std.meta.SASLMechanismHandlerCfgDefn;
+import org.opends.server.admin.std.server.SASLMechanismHandlerCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.api.SASLMechanismHandler;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.ErrorLogCategory;
@@ -51,14 +50,9 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -67,37 +61,34 @@
* This class defines a utility that will be used to manage the set of SASL
* mechanism handlers defined in the Directory Server. It will initialize the
* handlers when the server starts, and then will manage any additions,
- * removals, or modifications of any SASL mechanism handlers while the server is
+ * removals, or modifications to any SASL mechanism handlers while the server is
* running.
*/
-public class SASLConfigManager
- implements ConfigChangeListener, ConfigAddListener, ConfigDeleteListener
+public class SASLConfigManager implements
+ ConfigurationChangeListener<SASLMechanismHandlerCfg>,
+ ConfigurationAddListener<SASLMechanismHandlerCfg>,
+ ConfigurationDeleteListener<SASLMechanismHandlerCfg>
+
{
-
-
-
- // A mapping between the DNs of the config entries and the associated SASL
+ // A mapping between the DNs of the config entries and the
+ // associated SASL
// mechanism handlers.
private ConcurrentHashMap<DN,SASLMechanismHandler> handlers;
- // The configuration handler for the Directory Server.
- private ConfigHandler configHandler;
-
/**
- * Creates a new instance of this SASL mechanism config manager.
+ * Creates a new instance of this SASL mechanism handler config manager.
*/
public SASLConfigManager()
{
- configHandler = DirectoryServer.getConfigHandler();
- handlers = new ConcurrentHashMap<DN,SASLMechanismHandler>();
+ handlers = new ConcurrentHashMap<DN,SASLMechanismHandler>();
}
/**
- * Initializes all SASL mechanism handlers currently defined in the Directory
+ * Initializes all SASL mechanism hanlders currently defined in the Directory
* Server configuration. This should only be called at Directory Server
* startup.
*
@@ -105,854 +96,315 @@
* mechanism handler initialization process to fail.
*
* @throws InitializationException If a problem occurs while initializing
- * the SASL mechanism handler that is
- * not related to the server configuration.
+ * the SASL mechanism handlers that is not
+ * related to the server configuration.
*/
public void initializeSASLMechanismHandlers()
throws ConfigException, InitializationException
{
- // First, get the configuration base entry.
- ConfigEntry baseEntry;
- try
+ // 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 SASL mechanism handler entries are added or
+ // removed.
+ rootConfiguration.addSASLMechanismHandlerAddListener(this);
+ rootConfiguration.addSASLMechanismHandlerDeleteListener(this);
+
+
+ //Initialize the existing SASL mechanism handlers.
+ for (String handlerName : rootConfiguration.listSASLMechanismHandlers())
{
- DN saslBase = DN.decode(DN_SASL_CONFIG_BASE);
- baseEntry = configHandler.getConfigEntry(saslBase);
- }
- catch (Exception e)
- {
- if (debugEnabled())
+ SASLMechanismHandlerCfg handlerConfiguration =
+ rootConfiguration.getSASLMechanismHandler(handlerName);
+ handlerConfiguration.addChangeListener(this);
+
+ if (handlerConfiguration.isEnabled())
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_CANNOT_GET_BASE;
- String message = getMessage(msgID, String.valueOf(e));
- throw new ConfigException(msgID, message, e);
- }
-
- if (baseEntry == null)
- {
- // The SASL mechanism handler base entry does not exist. This is not
- // acceptable, so throw an exception.
- int msgID = MSGID_CONFIG_SASL_BASE_DOES_NOT_EXIST;
- String message = getMessage(msgID);
- throw new ConfigException(msgID, message);
- }
-
-
- // Register add and delete listeners with the SASL mechanism base entry.
- // We don't care about modifications to it.
- baseEntry.registerAddListener(this);
- baseEntry.registerDeleteListener(this);
-
-
- // See if the base entry has any children. If not, then we don't need to do
- // anything else.
- if (! baseEntry.hasChildren())
- {
- return;
- }
-
-
- // Iterate through the child entries and process them as SASL mechanism
- // handler configuration entries.
- for (ConfigEntry childEntry : baseEntry.getChildren().values())
- {
- childEntry.registerChangeListener(this);
-
- StringBuilder unacceptableReason = new StringBuilder();
- if (! configAddIsAcceptable(childEntry, unacceptableReason))
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_SASL_ENTRY_UNACCEPTABLE,
- childEntry.getDN().toString(), unacceptableReason.toString());
- continue;
- }
-
- try
- {
- ConfigChangeResult result = applyConfigurationAdd(childEntry);
- if (result.getResultCode() != ResultCode.SUCCESS)
+ String className = handlerConfiguration.getHandlerClass();
+ try
{
- StringBuilder buffer = new StringBuilder();
-
- List<String> resultMessages = result.getMessages();
- if ((resultMessages == null) || (resultMessages.isEmpty()))
- {
- buffer.append(getMessage(MSGID_CONFIG_UNKNOWN_UNACCEPTABLE_REASON));
- }
- else
- {
- Iterator<String> iterator = resultMessages.iterator();
-
- buffer.append(iterator.next());
- while (iterator.hasNext())
- {
- buffer.append(EOL);
- buffer.append(iterator.next());
- }
- }
-
+ SASLMechanismHandler handler = loadHandler(className,
+ handlerConfiguration);
+ handlers.put(handlerConfiguration.dn(), handler);
+ }
+ catch (InitializationException ie)
+ {
logError(ErrorLogCategory.CONFIGURATION,
ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_SASL_CANNOT_CREATE_HANDLER,
- childEntry.getDN().toString(), buffer.toString());
+ ie.getMessage(), ie.getMessageID());
+ continue;
}
}
- catch (Exception e)
- {
- logError(ErrorLogCategory.CONFIGURATION, ErrorLogSeverity.SEVERE_ERROR,
- MSGID_CONFIG_SASL_CANNOT_CREATE_HANDLER,
- childEntry.getDN().toString(), String.valueOf(e));
- }
}
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * modification is acceptable to this change listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested update.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed change is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configChangeIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationAddAcceptable(
+ SASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that the entry has an appropriate objectclass for a SASL
- // mechanism handler.
- if (! configEntry.hasObjectClass(OC_SASL_MECHANISM_HANDLER))
+ if (configuration.isEnabled())
{
- int msgID = MSGID_CONFIG_SASL_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the handler class name.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_SASL_CLASS,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_CLASS_NAME),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
+ // Get the name of the class and make sure we can instantiate it as a SASL
+ // mechanism handler.
+ String className = configuration.getHandlerClass();
+ try
{
- int msgID = MSGID_CONFIG_SASL_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
+ loadHandler(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
return false;
}
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class handlerClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- handlerClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- try
- {
- SASLMechanismHandler handler =
- (SASLMechanismHandler) handlerClass.newInstance();
- }
- catch(Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS;
- String message = getMessage(msgID, handlerClass.getName(),
- String.valueOf(configEntry.getDN()),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // See if this SASL mechanism handler should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_SASL_ENABLED,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_SASL_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the SASL mechanism handler entry appears to be
- // acceptable.
+ // If we've gotten here, then it's fine.
return true;
}
/**
- * Attempts to apply a new configuration to this Directory Server component
- * based on the provided changed entry.
- *
- * @param configEntry The configuration entry that containing the updated
- * configuration for this component.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationAdd(
+ SASLMechanismHandlerCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
+ configuration.addChangeListener(this);
- // Make sure that the entry has an appropriate objectclass for a SASL
+ if (! configuration.isEnabled())
+ {
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ SASLMechanismHandler handler = null;
+
+ // Get the name of the class and make sure we can instantiate it as a SASL
// mechanism handler.
- if (! configEntry.hasObjectClass(OC_SASL_MECHANISM_HANDLER))
- {
- int msgID = MSGID_CONFIG_SASL_INVALID_OBJECTCLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Get the corresponding SASL mechanism handler if it is active.
- SASLMechanismHandler handler = handlers.get(configEntryDN);
-
-
- // See if this handler should be enabled or disabled.
- boolean needsEnabled = false;
- BooleanConfigAttribute enabledAttr;
+ String className = configuration.getHandlerClass();
try
{
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_SASL_ENABLED,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_ENABLED), false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_SASL_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- if (enabledAttr.activeValue())
- {
- if (handler == null)
- {
- needsEnabled = true;
- }
- else
- {
- // The handler is already active, so no action is required.
- }
- }
- else
- {
- if (handler == null)
- {
- // The handler is already disabled, so no action is required and we
- // can short-circuit out of this processing.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else
- {
- // The handler is active, so it needs to be disabled. Do this and
- // return that we were successful.
- handlers.remove(configEntryDN);
- handler.finalizeSASLMechanismHandler();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
+ handler = loadHandler(className, configuration);
}
- catch (Exception e)
+ catch (InitializationException ie)
{
- if (debugEnabled())
+ if (resultCode == ResultCode.SUCCESS)
{
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the handler class name. If it has
- // changed, then we will not try to dynamically apply it.
- String className;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_SASL_CLASS,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_CLASS_NAME),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_SASL_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- className = classNameAttr.pendingValue();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- boolean classChanged = false;
- String oldClassName = null;
- if (handler != null)
- {
- oldClassName = handler.getClass().getName();
- classChanged = (! className.equals(oldClassName));
- }
-
-
- if (classChanged)
- {
- // This will not be applied dynamically. Add a message to the response
- // and indicate that admin action is required.
- adminActionRequired = true;
- messages.add(getMessage(MSGID_CONFIG_SASL_CLASS_ACTION_REQUIRED,
- String.valueOf(oldClassName),
- String.valueOf(className),
- String.valueOf(configEntryDN)));
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- if (needsEnabled)
- {
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class handlerClass = Class.forName(className);
- handler = (SASLMechanismHandler) handlerClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
}
- try
- {
- handler.initializeSASLMechanismHandler(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className,
- String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
-
- handlers.put(configEntryDN, handler);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ messages.add(ie.getMessage());
}
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ handlers.put(configuration.dn(), handler);
+ }
- // If we've gotten here, then there haven't been any changes to anything
- // that we care about.
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
/**
- * Indicates whether the configuration entry that will result from a proposed
- * add is acceptable to this add listener.
- *
- * @param configEntry The configuration entry that will result from
- * the requested add.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed entry is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry contains an acceptable
- * configuration, or <CODE>false</CODE> if it does not.
+ * {@inheritDoc}
*/
- public boolean configAddIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
+ public boolean isConfigurationDeleteAcceptable(
+ SASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
{
- // Make sure that no entry already exists with the specified DN.
- DN configEntryDN = configEntry.getDN();
- if (handlers.containsKey(configEntryDN))
- {
- int msgID = MSGID_CONFIG_SASL_EXISTS;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry has an appropriate objectclass for a SASL
- // mechanism handler.
- if (! configEntry.hasObjectClass(OC_SASL_MECHANISM_HANDLER))
- {
- int msgID = MSGID_CONFIG_SASL_INVALID_OBJECTCLASS;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
-
-
- // Make sure that the entry specifies the SASL mechanism handler class.
- StringConfigAttribute classNameAttr;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_SASL_CLASS,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_CLASS_NAME),
- true, false, true);
- classNameAttr = (StringConfigAttribute)
- configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_SASL_NO_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- Class handlerClass;
- try
- {
- // FIXME -- Should this be done with a custom class loader?
- handlerClass = Class.forName(classNameAttr.pendingValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS_NAME;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
- SASLMechanismHandler handler;
- try
- {
- handler = (SASLMechanismHandler) handlerClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS;
- String message = getMessage(msgID, handlerClass.getName(),
- String.valueOf(configEntryDN),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If the handler is a configurable component, then make sure that its
- // configuration is valid.
- if (handler instanceof ConfigurableComponent)
- {
- ConfigurableComponent cc = (ConfigurableComponent) handler;
- LinkedList<String> errorMessages = new LinkedList<String>();
- if (! cc.hasAcceptableConfiguration(configEntry, errorMessages))
- {
- if (errorMessages.isEmpty())
- {
- int msgID = MSGID_CONFIG_SASL_UNACCEPTABLE_CONFIG;
- unacceptableReason.append(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
- else
- {
- Iterator<String> iterator = errorMessages.iterator();
- unacceptableReason.append(iterator.next());
- while (iterator.hasNext())
- {
- unacceptableReason.append(" ");
- unacceptableReason.append(iterator.next());
- }
- }
-
- return false;
- }
- }
-
-
- // See if this handler should be enabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_SASL_ENABLED,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- int msgID = MSGID_CONFIG_SASL_NO_ENABLED_ATTR;
- String message = getMessage(msgID, configEntry.getDN().toString());
- unacceptableReason.append(message);
- return false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_ENABLED_VALUE;
- String message = getMessage(msgID, configEntry.getDN().toString(),
- String.valueOf(e));
- unacceptableReason.append(message);
- return false;
- }
-
-
- // If we've gotten here then the handler entry appears to be acceptable.
+ // FIXME -- We should try to perform some check to determine whether the
+ // SASL mechanism handler is in use.
return true;
}
/**
- * Attempts to apply a new configuration based on the provided added entry.
- *
- * @param configEntry The new configuration entry that contains the
- * configuration to apply.
- *
- * @return Information about the result of processing the configuration
- * change.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry)
+ public ConfigChangeResult applyConfigurationDelete(
+ SASLMechanismHandlerCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
-
- // Make sure that the entry has an appropriate objectclass for a SASL
- // mechanism handler.
- if (! configEntry.hasObjectClass(OC_SASL_MECHANISM_HANDLER))
- {
- int msgID = MSGID_CONFIG_SASL_INVALID_OBJECTCLASS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.UNWILLING_TO_PERFORM;
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // See if this handler should be enabled or disabled.
- BooleanConfigAttribute enabledAttr;
- try
- {
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_SASL_ENABLED,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_ENABLED),
- false);
- enabledAttr = (BooleanConfigAttribute)
- configEntry.getConfigAttribute(enabledStub);
-
- if (enabledAttr == null)
- {
- // The attribute doesn't exist, so it will be disabled by default.
- int msgID = MSGID_CONFIG_SASL_NO_ENABLED_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.SUCCESS;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- else if (! enabledAttr.activeValue())
- {
- // It is explicitly configured as disabled, so we don't need to do
- // anything.
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_ENABLED_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Make sure that the entry specifies the handler class name.
- String className;
- try
- {
- StringConfigAttribute classStub =
- new StringConfigAttribute(ATTR_SASL_CLASS,
- getMessage(MSGID_CONFIG_SASL_DESCRIPTION_CLASS_NAME),
- true, false, true);
- StringConfigAttribute classNameAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(classStub);
-
- if (classNameAttr == null)
- {
- int msgID = MSGID_CONFIG_SASL_NO_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- return new ConfigChangeResult(resultCode, adminActionRequired,
- messages);
- }
-
- className = classNameAttr.pendingValue();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS_NAME;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- // Load and initialize the handler class, and register it with the Directory
- // Server.
- SASLMechanismHandler handler;
- try
- {
- // FIXME -- Should this be done with a dynamic class loader?
- Class handlerClass = Class.forName(className);
- handler = (SASLMechanismHandler) handlerClass.newInstance();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INVALID_CLASS;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
- try
- {
- handler.initializeSASLMechanismHandler(configEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_CONFIG_SASL_INITIALIZATION_FAILED;
- messages.add(getMessage(msgID, className, String.valueOf(configEntryDN),
- String.valueOf(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- handlers.put(configEntryDN, handler);
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
- * Indicates whether it is acceptable to remove the provided configuration
- * entry.
- *
- * @param configEntry The configuration entry that will be removed
- * from the configuration.
- * @param unacceptableReason A buffer to which this method can append a
- * human-readable message explaining why the
- * proposed delete is not acceptable.
- *
- * @return <CODE>true</CODE> if the proposed entry may be removed from the
- * configuration, or <CODE>false</CODE> if not.
- */
- public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
- StringBuilder unacceptableReason)
- {
- // A delete should always be acceptable, so just return true.
- return true;
- }
-
-
-
- /**
- * Attempts to apply a new configuration based on the provided deleted entry.
- *
- * @param configEntry The new configuration entry that has been deleted.
- *
- * @return Information about the result of processing the configuration
- * change.
- */
- public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry)
- {
- DN configEntryDN = configEntry.getDN();
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
-
-
- // See if the entry is registered as a SASL mechanism handler. If so,
- // deregister it and stop the handler.
- SASLMechanismHandler handler = handlers.remove(configEntryDN);
+ SASLMechanismHandler handler = handlers.remove(configuration.dn());
if (handler != null)
{
handler.finalizeSASLMechanismHandler();
}
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
- return new ConfigChangeResult(resultCode, adminActionRequired);
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ SASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ if (configuration.isEnabled())
+ {
+ // Get the name of the class and make sure we can instantiate it as a SASL
+ // mechanism handler.
+ String className = configuration.getHandlerClass();
+ try
+ {
+ loadHandler(className, null);
+ }
+ catch (InitializationException ie)
+ {
+ unacceptableReasons.add(ie.getMessage());
+ return false;
+ }
+ }
+
+ // If we've gotten here, then it's fine.
+ return true;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ SASLMechanismHandlerCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Get the existing handler if it's already enabled.
+ SASLMechanismHandler existingHandler = handlers.get(configuration.dn());
+
+
+ // If the new configuration has the handler disabled, then disable it if it
+ // is enabled, or do nothing if it's already disabled.
+ if (! configuration.isEnabled())
+ {
+ if (existingHandler != null)
+ {
+ SASLMechanismHandler handler = handlers.remove(configuration.dn());
+ if (handler != null)
+ {
+ handler.finalizeSASLMechanismHandler();
+ }
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+ // Get the class for the SASL handler. If the handler is already enabled,
+ // then we shouldn't do anything with it although if the class has changed
+ // then we'll at least need to indicate that administrative action is
+ // required. If the handler is disabled, then instantiate the class and
+ // initialize and register it as a SASL mechanism handler.
+ String className = configuration.getHandlerClass();
+ if (existingHandler != null)
+ {
+ if (! className.equals(existingHandler.getClass().getName()))
+ {
+ adminActionRequired = true;
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ SASLMechanismHandler handler = null;
+ try
+ {
+ handler = loadHandler(className, configuration);
+ }
+ catch (InitializationException ie)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ messages.add(ie.getMessage());
+ }
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ handlers.put(configuration.dn(), handler);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+
+
+ /**
+ * Loads the specified class, instantiates it as a SASL mechanism hanlder, and
+ * optionally initializes that instance.
+ *
+ * @param className The fully-qualified name of the SASL mechanism
+ * handler class to load, instantiate, and initialize.
+ * @param configuration The configuration to use to initialize the handler,
+ * or {@code null} if the SASL mechanism handler should
+ * not be initialized.
+ *
+ * @return The possibly initialized SASL mechanism handler.
+ *
+ * @throws InitializationException If a problem occurred while attempting to
+ * initialize the SASL mechanism handler.
+ */
+ private SASLMechanismHandler loadHandler(String className,
+ SASLMechanismHandlerCfg
+ configuration)
+ throws InitializationException
+ {
+ try
+ {
+ SASLMechanismHandlerCfgDefn definition =
+ SASLMechanismHandlerCfgDefn.getInstance();
+ ClassPropertyDefinition propertyDefinition =
+ definition.getHandlerClassPropertyDefinition();
+ Class<? extends SASLMechanismHandler> handlerClass =
+ propertyDefinition.loadClass(className, SASLMechanismHandler.class);
+ SASLMechanismHandler handler = handlerClass.newInstance();
+
+ if (configuration != null)
+ {
+ Method method =
+ handler.getClass().getMethod("initializeSASLMechanismHandler",
+ configuration.definition().getServerConfigurationClass());
+ method.invoke(handler, configuration);
+ }
+
+ return handler;
+ }
+ catch (Exception e)
+ {
+ int msgID = MSGID_CONFIG_SASL_INITIALIZATION_FAILED;
+ String message = getMessage(msgID, className,
+ String.valueOf(configuration.dn()),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
}
}
diff --git a/opends/src/server/org/opends/server/core/SchemaConfigManager.java b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
index 5233b27..d1c3347 100644
--- a/opends/src/server/org/opends/server/core/SchemaConfigManager.java
+++ b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -333,8 +333,7 @@
MatchingRule matchingRule;
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class matchingRuleClass = Class.forName(className);
+ Class matchingRuleClass = DirectoryServer.loadClass(className);
matchingRule = (MatchingRule) matchingRuleClass.newInstance();
}
catch (Exception e)
@@ -577,8 +576,7 @@
AttributeSyntax syntax;
try
{
- // FIXME -- Should we use a custom class loader for this?
- Class syntaxClass = Class.forName(className);
+ Class syntaxClass = DirectoryServer.loadClass(className);
syntax = (AttributeSyntax) syntaxClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/core/SynchronizationProviderConfigManager.java b/opends/src/server/org/opends/server/core/SynchronizationProviderConfigManager.java
index afb8067..d8186e9 100644
--- a/opends/src/server/org/opends/server/core/SynchronizationProviderConfigManager.java
+++ b/opends/src/server/org/opends/server/core/SynchronizationProviderConfigManager.java
@@ -274,8 +274,7 @@
Class providerClass;
try
{
- // FIXME -- Should we use a custom class loader for this?
- providerClass = Class.forName(providerClassName);
+ providerClass = DirectoryServer.loadClass(providerClassName);
}
catch (Exception e)
{
@@ -485,8 +484,7 @@
Class providerClass;
try
{
- // FIXME -- Should we use a custom class loader for this?
- providerClass = Class.forName(className);
+ providerClass = DirectoryServer.loadClass(className);
}
catch (Exception e)
{
@@ -687,8 +685,7 @@
Class providerClass = null;
try
{
- // FIXME -- Should we use a custom class loader for this?
- providerClass = Class.forName(className);
+ providerClass = DirectoryServer.loadClass(className);
}
catch (Exception e)
{
diff --git a/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java b/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java
index c43e32d..e093d72 100644
--- a/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java
+++ b/opends/src/server/org/opends/server/core/TrustManagerProviderConfigManager.java
@@ -59,7 +59,6 @@
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
@@ -273,8 +272,7 @@
Class providerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- providerClass = Class.forName(classNameAttr.pendingValue());
+ providerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -517,8 +515,7 @@
{
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class providerClass = Class.forName(className);
+ Class providerClass = DirectoryServer.loadClass(className);
provider = (TrustManagerProvider) providerClass.newInstance();
}
catch (Exception e)
@@ -645,8 +642,7 @@
Class providerClass;
try
{
- // FIXME -- Should this be done with a custom class loader?
- providerClass = Class.forName(classNameAttr.pendingValue());
+ providerClass = DirectoryServer.loadClass(classNameAttr.pendingValue());
}
catch (Exception e)
{
@@ -872,8 +868,7 @@
TrustManagerProvider provider;
try
{
- // FIXME -- Should this be done with a dynamic class loader?
- Class providerClass = Class.forName(className);
+ Class providerClass = DirectoryServer.loadClass(className);
provider = (TrustManagerProvider) providerClass.newInstance();
}
catch (Exception e)
diff --git a/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
index 0dcc837..403086d 100644
--- a/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
@@ -28,8 +28,8 @@
+import org.opends.server.admin.std.server.SASLMechanismHandlerCfg;
import org.opends.server.api.SASLMechanismHandler;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
@@ -55,11 +55,8 @@
* then that trace information will be written to the server error log.
*/
public class AnonymousSASLMechanismHandler
- extends SASLMechanismHandler
+ extends SASLMechanismHandler<SASLMechanismHandlerCfg>
{
-
-
-
/**
* Creates a new instance of this SASL mechanism handler. No initialization
* should be done in this method, as it should all be performed in the
@@ -68,7 +65,6 @@
public AnonymousSASLMechanismHandler()
{
super();
-
}
@@ -77,7 +73,8 @@
* {@inheritDoc}
*/
@Override()
- public void initializeSASLMechanismHandler(ConfigEntry configEntry)
+ public void initializeSASLMechanismHandler(SASLMechanismHandlerCfg
+ configuration)
throws ConfigException, InitializationException
{
// No real implementation is required. Simply register with the Directory
diff --git a/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
index a81d685..27fc571 100644
--- a/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandler.java
@@ -33,19 +33,16 @@
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.CramMD5SASLMechanismHandlerCfg;
import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.IdentityMapper;
import org.opends.server.api.SASLMechanismHandler;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PasswordPolicyState;
@@ -60,7 +57,6 @@
import org.opends.server.types.LockManager;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -85,24 +81,22 @@
* draft-ietf-sasl-crammd5-05.
*/
public class CRAMMD5SASLMechanismHandler
- extends SASLMechanismHandler
- implements ConfigurableComponent
+ extends SASLMechanismHandler<CramMD5SASLMechanismHandlerCfg>
+ implements ConfigurationChangeListener<
+ CramMD5SASLMechanismHandlerCfg>
{
-
-
-
// An array filled with the inner pad byte.
private byte[] iPad;
// An array filled with the outer pad byte.
private byte[] oPad;
+ // The current configuration for this SASL mechanism handler.
+ private CramMD5SASLMechanismHandlerCfg currentConfig;
+
// The DN of the configuration entry for this SASL mechanism handler.
private DN configEntryDN;
- // The DN of the identity mapper configuration entry.
- private DN identityMapperDN;
-
// The identity mapper that will be used to map ID strings to user entries.
private IdentityMapper identityMapper;
@@ -127,7 +121,6 @@
public CRAMMD5SASLMechanismHandler()
{
super();
-
}
@@ -136,10 +129,14 @@
* {@inheritDoc}
*/
@Override()
- public void initializeSASLMechanismHandler(ConfigEntry configEntry)
+ public void initializeSASLMechanismHandler(
+ CramMD5SASLMechanismHandlerCfg configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration.addCramMD5ChangeListener(this);
+
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
// Initialize the variables needed for the MD5 digest creation.
@@ -171,53 +168,18 @@
// Get the identity mapper that should be used to find users.
- int msgID = MSGID_SASLCRAMMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (identityMapper == null)
{
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLCRAMMD5_NO_IDENTITY_MAPPER_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- else
- {
- identityMapperDN = mapperAttr.activeValue();
- identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
- if (identityMapper == null)
- {
- msgID = MSGID_SASLCRAMMD5_NO_SUCH_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(identityMapperDN),
- String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLCRAMMD5_CANNOT_GET_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ int msgID = MSGID_SASLCRAMMD5_NO_SUCH_IDENTITY_MAPPER;
+ String message = getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
}
DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_CRAM_MD5, this);
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -228,7 +190,7 @@
@Override()
public void finalizeSASLMechanismHandler()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeCramMD5ChangeListener(this);
DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_CRAM_MD5);
}
@@ -624,206 +586,6 @@
/**
- * Retrieves the DN of the configuration entry with which this component is
- * associated.
- *
- * @return The DN of the configuration entry with which this component is
- * associated.
- */
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated with this
- * configurable component.
- *
- * @return The set of configuration attributes that are associated with this
- * configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_SASLCRAMMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- attrList.add(new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID),
- true, false, false, identityMapperDN));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided list.
- *
- * @param configEntry The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons A list that can be used to hold messages about
- * why the provided entry does not have an
- * acceptable configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- // Look at the identity mapper configuration.
- int msgID = MSGID_SASLCRAMMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLCRAMMD5_NO_IDENTITY_MAPPER_ATTR;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- return false;
- }
-
- DN mapperDN = mapperAttr.pendingValue();
- if (! mapperDN.equals(identityMapperDN))
- {
- IdentityMapper mapper = DirectoryServer.getIdentityMapper(mapperDN);
- if (mapper == null)
- {
- msgID = MSGID_SASLCRAMMD5_NO_SUCH_IDENTITY_MAPPER;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(mapperDN),
- String.valueOf(configEntryDN)));
- return false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLCRAMMD5_CANNOT_GET_IDENTITY_MAPPER;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // If we've gotten to this point, then everything must be OK.
- return true;
- }
-
-
-
- /**
- * Makes a best-effort attempt to apply the configuration contained in the
- * provided entry. Information about the result of this processing should be
- * added to the provided message list. Information should always be added to
- * this list if a configuration change could not be applied. If detailed
- * results are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not changed) should
- * also be included.
- *
- * @param configEntry The entry containing the new configuration to
- * apply for this component.
- * @param detailedResults Indicates whether detailed information about the
- * processing should be added to the list.
- *
- * @return Information about the result of the configuration update.
- */
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
- {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Look at the identity mapper configuration.
- DN newIdentityMapperDN = null;
- IdentityMapper newIdentityMapper = null;
- int msgID = MSGID_SASLCRAMMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLCRAMMD5_NO_IDENTITY_MAPPER_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
-
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- else
- {
- newIdentityMapperDN = mapperAttr.pendingValue();
- if (! newIdentityMapperDN.equals(identityMapperDN))
- {
- newIdentityMapper =
- DirectoryServer.getIdentityMapper(newIdentityMapperDN);
- if (newIdentityMapper == null)
- {
- msgID = MSGID_SASLCRAMMD5_NO_SUCH_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(newIdentityMapperDN),
- String.valueOf(configEntryDN)));
-
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLCRAMMD5_CANNOT_GET_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
-
- // If everything has been successful, then apply any changes that were made.
- if (resultCode == ResultCode.SUCCESS)
- {
- if ((newIdentityMapperDN != null) && (identityMapper != null))
- {
- identityMapperDN = newIdentityMapperDN;
- identityMapper = newIdentityMapper;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLCRAMMD5_UPDATED_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(identityMapperDN)));
- }
- }
- }
-
-
- // Return the result to the caller.
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
* {@inheritDoc}
*/
@Override()
@@ -844,5 +606,73 @@
// This may be considered a secure mechanism.
return true;
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ CramMD5SASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ boolean configAcceptable = true;
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ int msgID = MSGID_SASLCRAMMD5_NO_SUCH_IDENTITY_MAPPER;
+ unacceptableReasons.add(getMessage(msgID,
+ String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ configAcceptable = false;
+ }
+
+
+ return configAcceptable;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ CramMD5SASLMechanismHandlerCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ }
+
+ int msgID = MSGID_SASLCRAMMD5_NO_SUCH_IDENTITY_MAPPER;
+ messages.add(getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ }
+
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ identityMapper = newIdentityMapper;
+ currentConfig = configuration;
+ }
+
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
}
diff --git a/opends/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandler.java
index 960c3ad..8b67146 100644
--- a/opends/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandler.java
@@ -35,22 +35,18 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.DigestMD5SASLMechanismHandlerCfg;
import org.opends.server.api.Backend;
import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.IdentityMapper;
import org.opends.server.api.SASLMechanismHandler;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PasswordPolicyState;
@@ -71,7 +67,6 @@
import org.opends.server.types.ResultCode;
import org.opends.server.util.Base64;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -97,18 +92,16 @@
* updates from draft-ietf-sasl-rfc2831bis-06.
*/
public class DigestMD5SASLMechanismHandler
- extends SASLMechanismHandler
- implements ConfigurableComponent
+ extends SASLMechanismHandler<DigestMD5SASLMechanismHandlerCfg>
+ implements ConfigurationChangeListener<
+ DigestMD5SASLMechanismHandlerCfg>
{
-
-
+ // The current configuration for this SASL mechanism handler.
+ private DigestMD5SASLMechanismHandlerCfg currentConfig;
// The DN of the configuration entry for this SASL mechanism handler.
private DN configEntryDN;
- // The DN of the identity mapper configuration entry.
- private DN identityMapperDN;
-
// The identity mapper that will be used to map ID strings to user entries.
private IdentityMapper identityMapper;
@@ -122,9 +115,6 @@
// The random number generator that we will use to create the nonce.
private SecureRandom randomGenerator;
- // The realm that the server should use, if one has been specified.
- private String realm;
-
/**
@@ -135,7 +125,6 @@
public DigestMD5SASLMechanismHandler()
{
super();
-
}
@@ -144,10 +133,14 @@
* {@inheritDoc}
*/
@Override()
- public void initializeSASLMechanismHandler(ConfigEntry configEntry)
+ public void initializeSASLMechanismHandler(
+ DigestMD5SASLMechanismHandlerCfg configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration.addDigestMD5ChangeListener(this);
+
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
// Initialize the variables needed for the MD5 digest creation.
@@ -172,83 +165,19 @@
// Get the identity mapper that should be used to find users.
- int msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (identityMapper == null)
{
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLDIGESTMD5_NO_IDENTITY_MAPPER_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- else
- {
- identityMapperDN = mapperAttr.activeValue();
- identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
- if (identityMapper == null)
- {
- msgID = MSGID_SASLDIGESTMD5_NO_SUCH_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(identityMapperDN),
- String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLDIGESTMD5_CANNOT_GET_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the realm to use, if any.
- realm = null;
- msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_REALM;
- StringConfigAttribute realmStub =
- new StringConfigAttribute(ATTR_DIGESTMD5_REALM, getMessage(msgID),
- false, false, false);
- try
- {
- StringConfigAttribute realmAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(realmStub);
- if (realmAttr != null)
- {
- realm = realmAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLDIGESTMD5_CANNOT_GET_REALM;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ int msgID = MSGID_SASLDIGESTMD5_NO_SUCH_IDENTITY_MAPPER;
+ String message = getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
}
DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_DIGEST_MD5,
this);
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -259,7 +188,7 @@
@Override()
public void finalizeSASLMechanismHandler()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeDigestMD5ChangeListener(this);
DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_DIGEST_MD5);
}
@@ -272,6 +201,11 @@
@Override()
public void processSASLBind(BindOperation bindOperation)
{
+ DigestMD5SASLMechanismHandlerCfg config = currentConfig;
+ IdentityMapper identityMapper = this.identityMapper;
+ String realm = config.getRealm();
+
+
// The DIGEST-MD5 bind process uses two stages. See if the client provided
// any credentials. If not, then this is an initial authentication so we
// will send a challenge to the client.
@@ -1628,307 +1562,6 @@
/**
- * Retrieves the DN of the configuration entry with which this component is
- * associated.
- *
- * @return The DN of the configuration entry with which this component is
- * associated.
- */
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated with this
- * configurable component.
- *
- * @return The set of configuration attributes that are associated with this
- * configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- attrList.add(new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID),
- true, false, false, identityMapperDN));
-
- msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_REALM;
- attrList.add(new StringConfigAttribute(ATTR_DIGESTMD5_REALM,
- getMessage(msgID), false, false,
- false, realm));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided list.
- *
- * @param configEntry The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons A list that can be used to hold messages about
- * why the provided entry does not have an
- * acceptable configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- // Look at the identity mapper configuration.
- int msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLDIGESTMD5_NO_IDENTITY_MAPPER_ATTR;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- return false;
- }
-
- DN mapperDN = mapperAttr.pendingValue();
- if (! mapperDN.equals(identityMapperDN))
- {
- IdentityMapper mapper = DirectoryServer.getIdentityMapper(mapperDN);
- if (mapper == null)
- {
- msgID = MSGID_SASLDIGESTMD5_NO_SUCH_IDENTITY_MAPPER;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(mapperDN),
- String.valueOf(configEntryDN)));
- return false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLDIGESTMD5_CANNOT_GET_IDENTITY_MAPPER;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // Look at the realm configuration.
- msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_REALM;
- StringConfigAttribute realmStub =
- new StringConfigAttribute(ATTR_DIGESTMD5_REALM, getMessage(msgID),
- false, false, false);
- try
- {
- StringConfigAttribute realmAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(realmStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLDIGESTMD5_CANNOT_GET_REALM;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // If we've gotten to this point, then everything must be OK.
- return true;
- }
-
-
-
- /**
- * Makes a best-effort attempt to apply the configuration contained in the
- * provided entry. Information about the result of this processing should be
- * added to the provided message list. Information should always be added to
- * this list if a configuration change could not be applied. If detailed
- * results are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not changed) should
- * also be included.
- *
- * @param configEntry The entry containing the new configuration to
- * apply for this component.
- * @param detailedResults Indicates whether detailed information about the
- * processing should be added to the list.
- *
- * @return Information about the result of the configuration update.
- */
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
- {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Look at the identity mapper configuration.
- DN newIdentityMapperDN = null;
- IdentityMapper newIdentityMapper = null;
- int msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLDIGESTMD5_NO_IDENTITY_MAPPER_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
-
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- else
- {
- newIdentityMapperDN = mapperAttr.pendingValue();
- if (! newIdentityMapperDN.equals(identityMapperDN))
- {
- newIdentityMapper =
- DirectoryServer.getIdentityMapper(newIdentityMapperDN);
- if (newIdentityMapper == null)
- {
- msgID = MSGID_SASLDIGESTMD5_NO_SUCH_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(newIdentityMapperDN),
- String.valueOf(configEntryDN)));
-
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLDIGESTMD5_CANNOT_GET_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
-
- // Look at the realm configuration.
- String newRealm = null;
- msgID = MSGID_SASLDIGESTMD5_DESCRIPTION_REALM;
- StringConfigAttribute realmStub =
- new StringConfigAttribute(ATTR_DIGESTMD5_REALM, getMessage(msgID),
- false, false, false);
- try
- {
- StringConfigAttribute realmAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(realmStub);
- if (realmAttr != null)
- {
- newRealm = realmAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLDIGESTMD5_CANNOT_GET_REALM;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
-
- // If everything has been successful, then apply any changes that were made.
- if (resultCode == ResultCode.SUCCESS)
- {
- if ((newIdentityMapperDN != null) && (newIdentityMapper != null))
- {
- identityMapperDN = newIdentityMapperDN;
- identityMapper = newIdentityMapper;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLDIGESTMD5_UPDATED_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(identityMapperDN)));
- }
- }
-
- if (realm == null)
- {
- if (newRealm != null)
- {
- realm = newRealm;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLDIGESTMD5_UPDATED_NEW_REALM;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(realm)));
- }
- }
- }
- else if (newRealm == null)
- {
- realm = null;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLDIGESTMD5_UPDATED_NO_REALM;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- }
- else
- {
- if (! realm.equals(newRealm))
- {
- realm = newRealm;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLDIGESTMD5_UPDATED_NEW_REALM;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(realm)));
- }
- }
- }
- }
-
-
- // Return the result to the caller.
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
* {@inheritDoc}
*/
@Override()
@@ -1949,5 +1582,73 @@
// This may be considered a secure mechanism.
return true;
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ DigestMD5SASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ boolean configAcceptable = true;
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ int msgID = MSGID_SASLDIGESTMD5_NO_SUCH_IDENTITY_MAPPER;
+ unacceptableReasons.add(getMessage(msgID,
+ String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ configAcceptable = false;
+ }
+
+
+ return configAcceptable;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ DigestMD5SASLMechanismHandlerCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ }
+
+ int msgID = MSGID_SASLDIGESTMD5_NO_SUCH_IDENTITY_MAPPER;
+ messages.add(getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ }
+
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ identityMapper = newIdentityMapper;
+ currentConfig = configuration;
+ }
+
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
}
diff --git a/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java b/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
index ac9a3d9..451ea65 100644
--- a/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
+++ b/opends/src/server/org/opends/server/extensions/ExactMatchIdentityMapper.java
@@ -29,25 +29,22 @@
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.SortedSet;
-import org.opends.server.api.ConfigurableComponent;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.ExactMatchIdentityMapperCfg;
import org.opends.server.api.IdentityMapper;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
-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.LDAPFilter;
import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DirectoryException;
@@ -55,13 +52,10 @@
import org.opends.server.types.Entry;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
import static org.opends.server.messages.ExtensionsMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.StaticUtils.*;
@@ -78,160 +72,69 @@
* attribute) the ID value.
*/
public class ExactMatchIdentityMapper
- extends IdentityMapper
- implements ConfigurableComponent
+ extends IdentityMapper<ExactMatchIdentityMapperCfg>
+ implements ConfigurationChangeListener<
+ ExactMatchIdentityMapperCfg>
{
-
-
-
- // The set of search base DNs that will be used to find a matching user.
- private ASN1OctetString[] rawSearchBases;
+ // The set of attribute types to use when performing lookups.
+ private AttributeType[] attributeTypes;
// The DN of the configuration entry for this identity mapper.
private DN configEntryDN;
+ // The current configuration for this identity mapper.
+ private ExactMatchIdentityMapperCfg currentConfig;
+
// The set of attributes to return in search result entries.
private LinkedHashSet<String> requestedAttributes;
- // The set of attributes that will be searched to find a matching user.
- private String[] rawMatchAttributes;
-
/**
- * Initializes this identity mapper based on the information in the provided
- * configuration entry.
- *
- * @param configEntry The configuration entry that contains the information
- * to use to initialize this identity mapper.
- *
- * @throws ConfigException If an unrecoverable problem arises in the
- * process of performing the initialization.
- *
- * @throws InitializationException If a problem occurs during initialization
- * that is not related to the server
- * configuration.
+ * Creates a new instance of this exact match identity mapper. All
+ * initialization should be performed in the {@code initializeIdentityMapper}
+ * method.
*/
- public void initializeIdentityMapper(ConfigEntry configEntry)
+ public ExactMatchIdentityMapper()
+ {
+ super();
+
+ // Don't do any initialization here.
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeIdentityMapper(
+ ExactMatchIdentityMapperCfg configuration)
throws ConfigException, InitializationException
{
- configEntryDN = configEntry.getDN();
+ configuration.addExactMatchChangeListener(this);
+
+ currentConfig = configuration;
+ configEntryDN = currentConfig.dn();
- // Get the set of attributes that should be checked to see if they have a
- // value equal to the identity string. We will only accept attributes that
- // have been defined in the server schema.
- int msgID = MSGID_EXACTMAP_DESCRIPTION_MATCH_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_MATCH_ATTRIBUTE, getMessage(msgID),
- true, true, false);
- try
+ // Get the attribute types to use for the searches.
+ SortedSet<String> attrNames = currentConfig.getMatchAttribute();
+ attributeTypes = new AttributeType[attrNames.size()];
+ int i=0;
+ for (String name : attrNames)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
+ AttributeType type = DirectoryServer.getAttributeType(toLowerCase(name),
+ false);
+ if (type == null)
{
- msgID = MSGID_EXACTMAP_NO_MATCH_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
+ int msgID = MSGID_EXACTMAP_UNKNOWN_ATTR;
+ String message = getMessage(msgID, String.valueOf(configEntryDN),
+ name);
throw new ConfigException(msgID, message);
}
- else
- {
- List<String> attrNames = attrAttr.activeValues();
- if (attrNames.size() == 0)
- {
- msgID = MSGID_EXACTMAP_NO_MATCH_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- rawMatchAttributes = new String[attrNames.size()];
- for (int i=0; i < rawMatchAttributes.length; i++)
- {
- String name = attrNames.get(i);
- String lowerName = toLowerCase(name);
- AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
- if (attrType == null)
- {
- msgID = MSGID_EXACTMAP_UNKNOWN_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- lowerName);
- throw new ConfigException(msgID, message);
- }
-
- rawMatchAttributes[i] = name;
- }
- }
+ attributeTypes[i++] = type;
}
- catch(ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_EXACTMAP_CANNOT_DETERMINE_MATCH_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
-
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Get the set of base DNs that should be used for the searches. If none
- // are provided, then use the root DSE.
- msgID = MSGID_EXACTMAP_DESCRIPTION_SEARCH_BASE;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_MATCH_BASE, getMessage(msgID), false, true,
- false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr == null)
- {
- // This is fine -- just use the root DSE.
- rawSearchBases = new ASN1OctetString[] { new ASN1OctetString() };
- }
- else
- {
- List<DN> baseDNs = baseAttr.activeValues();
- if (baseDNs.size() == 0)
- {
- // This is fine -- just use the root DSE.
- rawSearchBases = new ASN1OctetString[] { new ASN1OctetString() };
- }
- else
- {
- rawSearchBases = new ASN1OctetString[baseDNs.size()];
- for (int i=0; i < rawSearchBases.length; i++)
- {
- rawSearchBases[i] = new ASN1OctetString(baseDNs.get(i).toString());
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_EXACTMAP_CANNOT_DETERMINE_MATCH_BASE;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
-
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Register with the Directory Server as a configurable component.
- DirectoryServer.registerConfigurableComponent(this);
// Create the attribute list to include in search requests. We want to
@@ -248,8 +151,7 @@
*/
public void finalizeIdentityMapper()
{
- // Deregister with the server as a configurable component.
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeExactMatchChangeListener(this);
}
@@ -272,31 +174,28 @@
public Entry getEntryForID(String id)
throws DirectoryException
{
- // Get the attribute type and base DN arrays as local variables to protect
- // against concurrent modifications.
- String[] matchAttrs = rawMatchAttributes;
- ASN1OctetString[] matchBases = rawSearchBases;
+ ExactMatchIdentityMapperCfg config = currentConfig;
+ AttributeType[] attributeTypes = this.attributeTypes;
// Construct the search filter to use to make the determination.
- LDAPFilter filter;
- if (matchAttrs.length == 1)
+ SearchFilter filter;
+ if (attributeTypes.length == 1)
{
- filter = LDAPFilter.createEqualityFilter(matchAttrs[0],
- new ASN1OctetString(id));
+ AttributeValue value = new AttributeValue(attributeTypes[0], id);
+ filter = SearchFilter.createEqualityFilter(attributeTypes[0], value);
}
else
{
- ArrayList<LDAPFilter> filterComponents =
- new ArrayList<LDAPFilter>(matchAttrs.length);
-
- ASN1OctetString idOS = new ASN1OctetString(id);
- for (String s : matchAttrs)
+ ArrayList<SearchFilter> filterComps =
+ new ArrayList<SearchFilter>(attributeTypes.length);
+ for (AttributeType t : attributeTypes)
{
- filterComponents.add(LDAPFilter.createEqualityFilter(s, idOS));
+ AttributeValue value = new AttributeValue(t, id);
+ filterComps.add(SearchFilter.createEqualityFilter(t, value));
}
- filter = LDAPFilter.createORFilter(filterComponents);
+ filter = SearchFilter.createORFilter(filterComps);
}
@@ -304,13 +203,19 @@
// to find any matching entries. Since we'll only allow a single match,
// then use size and time limits to constrain costly searches resulting from
// non-unique or inefficient criteria.
+ Collection<DN> baseDNs = config.getMatchBaseDN();
+ if ((baseDNs == null) || baseDNs.isEmpty())
+ {
+ baseDNs = DirectoryServer.getPublicNamingContexts().keySet();
+ }
+
SearchResultEntry matchingEntry = null;
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- for (ASN1OctetString rawBase : matchBases)
+ for (DN baseDN : baseDNs)
{
InternalSearchOperation internalSearch =
- conn.processSearch(rawBase, SearchScope.WHOLE_SUBTREE,
+ conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE,
DereferencePolicy.NEVER_DEREF_ALIASES, 1, 10,
false, filter, requestedAttributes);
@@ -390,168 +295,26 @@
/**
- * Retrieves the DN of the configuration entry with which this component is
- * associated.
- *
- * @return The DN of the configuration entry with which this component is
- * associated.
+ * {@inheritDoc}
*/
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated with this
- * configurable component.
- *
- * @return The set of configuration attributes that are associated with this
- * configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- String[] attrs = rawMatchAttributes;
- ArrayList<String> matchAttrs = new ArrayList<String>(attrs.length);
- for (String s : attrs)
- {
- matchAttrs.add(s);
- }
-
- String description = getMessage(MSGID_EXACTMAP_DESCRIPTION_MATCH_ATTR);
- attrList.add(new StringConfigAttribute(ATTR_MATCH_ATTRIBUTE, description,
- true, true, false, matchAttrs));
-
-
- ASN1OctetString[] bases = rawSearchBases;
- ArrayList<DN> baseDNs = new ArrayList<DN>(bases.length);
- for (ASN1OctetString dn : bases)
- {
- try
- {
- baseDNs.add(DN.decode(dn));
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- // This should never happen.
- }
- }
-
- description = getMessage(MSGID_EXACTMAP_DESCRIPTION_SEARCH_BASE);
- attrList.add(new DNConfigAttribute(ATTR_MATCH_BASE, description, false,
- true, false, baseDNs));
-
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided list.
- *
- * @param configEntry The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons A list that can be used to hold messages about
- * why the provided entry does not have an
- * acceptable configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
+ public boolean isConfigurationChangeAcceptable(
+ ExactMatchIdentityMapperCfg configuration,
+ List<String> unacceptableReasons)
{
boolean configAcceptable = true;
-
- // Make sure that the entry has a valid set of match attributes.
- int msgID = MSGID_EXACTMAP_DESCRIPTION_MATCH_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_MATCH_ATTRIBUTE, getMessage(msgID),
- true, true, false);
- try
+ // Make sure that the set of attribute types is acceptable.
+ SortedSet<String> attributeNames = configuration.getMatchAttribute();
+ for (String name : attributeNames)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
+ AttributeType t = DirectoryServer.getAttributeType(toLowerCase(name),
+ false);
+ if (t == null)
{
- msgID = MSGID_EXACTMAP_NO_MATCH_ATTR;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
+ int msgID = MSGID_EXACTMAP_UNKNOWN_ATTR;
+ unacceptableReasons.add(getMessage(msgID, configuration.dn(), name));
configAcceptable = false;
}
- else
- {
- List<String> attrNames = attrAttr.activeValues();
- if (attrNames.size() == 0)
- {
- msgID = MSGID_EXACTMAP_NO_MATCH_ATTR;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- configAcceptable = false;
- }
-
- for (String attrName : attrNames)
- {
- String lowerName = toLowerCase(attrName);
- AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
- if (attrType == null)
- {
- msgID = MSGID_EXACTMAP_UNKNOWN_ATTR;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN),
- attrName));
- configAcceptable = false;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_EXACTMAP_CANNOT_DETERMINE_MATCH_ATTR;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configAcceptable = false;
- }
-
-
- // Make sure that the entry has a valid set of base DNs.
- msgID = MSGID_EXACTMAP_DESCRIPTION_SEARCH_BASE;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_MATCH_BASE, getMessage(msgID), false, true,
- false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_EXACTMAP_CANNOT_DETERMINE_MATCH_BASE;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configAcceptable = false;
}
@@ -561,186 +324,47 @@
/**
- * Makes a best-effort attempt to apply the configuration contained in the
- * provided entry. Information about the result of this processing should be
- * added to the provided message list. Information should always be added to
- * this list if a configuration change could not be applied. If detailed
- * results are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not changed) should
- * also be included.
- *
- * @param configEntry The entry containing the new configuration to
- * apply for this component.
- * @param detailedResults Indicates whether detailed information about the
- * processing should be added to the list.
- *
- * @return Information about the result of the configuration update.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
+ public ConfigChangeResult applyConfigurationChange(
+ ExactMatchIdentityMapperCfg configuration)
{
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
- // Get the set of match attributes.
- int msgID = MSGID_EXACTMAP_DESCRIPTION_MATCH_ATTR;
- String[] newMatchAttrs = null;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_MATCH_ATTRIBUTE, getMessage(msgID),
- true, true, false);
- try
+ // Get the attribute types to use for the searches.
+ SortedSet<String> attrNames = configuration.getMatchAttribute();
+ AttributeType[] newAttributeTypes = new AttributeType[attrNames.size()];
+ int i=0;
+ for (String name : attrNames)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
+ AttributeType type = DirectoryServer.getAttributeType(toLowerCase(name),
+ false);
+ if (type == null)
{
- msgID = MSGID_EXACTMAP_NO_MATCH_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
-
if (resultCode == ResultCode.SUCCESS)
{
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
}
- }
- else
- {
- List<String> attrNames = attrAttr.activeValues();
- if (attrNames.size() == 0)
- {
- msgID = MSGID_EXACTMAP_NO_MATCH_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- }
- else
- {
- newMatchAttrs = new String[attrNames.size()];
- for (int i=0; i < newMatchAttrs.length; i++)
- {
- String name = attrNames.get(i);
- String lowerName = toLowerCase(name);
- AttributeType t = DirectoryServer.getAttributeType(lowerName);
- if (t == null)
- {
- msgID = MSGID_EXACTMAP_UNKNOWN_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(attrNames.get(i))));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- }
- else
- {
- newMatchAttrs[i] = name;
- }
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
+ int msgID = MSGID_EXACTMAP_UNKNOWN_ATTR;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN), name));
}
- msgID = MSGID_EXACTMAP_CANNOT_DETERMINE_MATCH_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
+ newAttributeTypes[i++] = type;
}
- // Get the new set of base DNs.
- msgID = MSGID_EXACTMAP_DESCRIPTION_SEARCH_BASE;
- ASN1OctetString[] newBases = null;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_MATCH_BASE, getMessage(msgID), false, true,
- false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr == null)
- {
- // This is fine -- just use the root DSE.
- newBases = new ASN1OctetString[] { new ASN1OctetString() };
- }
- else
- {
- List<DN> baseDNs = baseAttr.pendingValues();
- if ((baseDNs == null) || baseDNs.isEmpty())
- {
- // This is fine -- just use the root DSE.
- newBases = new ASN1OctetString[] { new ASN1OctetString() };
- }
- else
- {
- newBases = new ASN1OctetString[baseDNs.size()];
- for (int i=0; i < newBases.length; i++)
- {
- newBases[i] = new ASN1OctetString(baseDNs.get(i).toString());
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_EXACTMAP_CANNOT_DETERMINE_MATCH_BASE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
-
- // If everything checks out, then apply the changes.
if (resultCode == ResultCode.SUCCESS)
{
- if (! Arrays.equals(rawMatchAttributes, newMatchAttrs))
- {
- rawMatchAttributes = newMatchAttrs;
-
- if (detailedResults)
- {
- msgID = MSGID_EXACTMAP_UPDATED_MATCH_ATTRS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- }
-
- if (! Arrays.equals(rawSearchBases, newBases))
- {
- rawSearchBases = newBases;
-
- if (detailedResults)
- {
- msgID = MSGID_EXACTMAP_UPDATED_MATCH_BASES;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- }
+ attributeTypes = newAttributeTypes;
+ currentConfig = configuration;
}
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
}
diff --git a/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
index 4588528..cea4f35 100644
--- a/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/ExternalSASLMechanismHandler.java
@@ -29,21 +29,15 @@
import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.ExternalSASLMechanismHandlerCfg;
import org.opends.server.api.CertificateMapper;
import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.ConnectionSecurityProvider;
import org.opends.server.api.SASLMechanismHandler;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.MultiChoiceConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.asn1.ASN1OctetString;
@@ -78,29 +72,10 @@
* other places to find and evaluate this external authentication information.
*/
public class ExternalSASLMechanismHandler
- extends SASLMechanismHandler
- implements ConfigurableComponent
+ extends SASLMechanismHandler<ExternalSASLMechanismHandlerCfg>
+ implements ConfigurationChangeListener<
+ ExternalSASLMechanismHandlerCfg>
{
-
-
-
- /**
- * The set of value strings that may be used for the peer certificate
- * validation policy.
- */
- private static final HashSet<String> validationValueStrings;
-
- static
- {
- validationValueStrings = new HashSet<String>(3);
- validationValueStrings.add(CertificateValidationPolicy.ALWAYS.toString());
- validationValueStrings.add(CertificateValidationPolicy.NEVER.toString());
- validationValueStrings.add(
- CertificateValidationPolicy.IFPRESENT.toString());
- }
-
-
-
// The attribute type that should hold the certificates to use for the
// validation.
private AttributeType certificateAttributeType;
@@ -109,12 +84,12 @@
// client with a certificate in the user's entry.
private CertificateValidationPolicy validationPolicy;
- // The DN of the configuration entry for the associated certificate mapper.
- private DN certificateMapperDN;
-
// The DN of the configuration entry for this SASL mechanism handler.
private DN configEntryDN;
+ // The current configuration for this SASL mechanism handler.
+ private ExternalSASLMechanismHandlerCfg currentConfig;
+
/**
@@ -125,7 +100,6 @@
public ExternalSASLMechanismHandler()
{
super();
-
}
@@ -134,136 +108,65 @@
* {@inheritDoc}
*/
@Override()
- public void initializeSASLMechanismHandler(ConfigEntry configEntry)
+ public void initializeSASLMechanismHandler(
+ ExternalSASLMechanismHandlerCfg configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration.addExternalChangeListener(this);
+
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
// See if we should attempt to validate client certificates against those in
// the corresponding user's entry.
- validationPolicy = CertificateValidationPolicy.NEVER;
- int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
- MultiChoiceConfigAttribute validateStub =
- new MultiChoiceConfigAttribute(ATTR_CLIENT_CERT_VALIDATION_POLICY,
- getMessage(msgID), false, false, false,
- validationValueStrings);
- try
+ switch (configuration.getCertificateValidationPolicy())
{
- MultiChoiceConfigAttribute validateAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(validateStub);
- if (validateAttr != null)
- {
- validationPolicy = CertificateValidationPolicy.policyForName(
- validateAttr.activeValue());
- if (validationPolicy == null)
- {
- msgID = MSGID_SASLEXTERNAL_INVALID_VALIDATION_VALUE;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- validateAttr.activeValue());
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_VALIDATION_POLICY;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ case NEVER:
+ validationPolicy = CertificateValidationPolicy.NEVER;
+ break;
+ case IFPRESENT:
+ validationPolicy = CertificateValidationPolicy.IFPRESENT;
+ break;
+ case ALWAYS:
+ validationPolicy = CertificateValidationPolicy.ALWAYS;
+ break;
}
// Get the attribute type to use for validating the certificates. If none
// is provided, then default to the userCertificate type.
- String attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
- StringConfigAttribute certAttributeStub =
- new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
- getMessage(msgID), false, false, false);
- try
+ String attrTypeName = configuration.getCertificateAttribute();
+ if (attrTypeName == null)
{
- StringConfigAttribute certAttributeAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(certAttributeStub);
- if (certAttributeAttr != null)
- {
- attrTypeName = toLowerCase(certAttributeAttr.activeValue());
- }
+ attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
- certificateAttributeType = DirectoryServer.getAttributeType(attrTypeName);
+ certificateAttributeType =
+ DirectoryServer.getAttributeType(toLowerCase(attrTypeName), false);
if (certificateAttributeType == null)
{
- msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
+ int msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
String message = getMessage(msgID, String.valueOf(attrTypeName),
String.valueOf(configEntryDN));
throw new ConfigException(msgID, message);
}
- // Get the DN of the certificate mapper to use with this handler.
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
- DNConfigAttribute certMapperStub =
- new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID), true,
- false, false);
- try
+ // Make sure that the configured certificate mapper is valid.
+ CertificateMapper certificateMapper =
+ DirectoryServer.getCertificateMapper(
+ configuration.getCertificateMapperDN());
+ if (certificateMapper == null)
{
- DNConfigAttribute certMapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(certMapperStub);
- if (certMapperAttr == null)
- {
- msgID = MSGID_SASLEXTERNAL_NO_CERTIFICATE_MAPPER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- else
- {
- certificateMapperDN = certMapperAttr.activeValue();
- CertificateMapper mapper =
- DirectoryServer.getCertificateMapper(certificateMapperDN);
- if (mapper == null)
- {
- msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(certificateMapperDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_MAPPER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
+ int msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
+ String message =
+ getMessage(msgID, String.valueOf(configEntryDN),
+ String.valueOf(configuration.getCertificateMapperDN()));
throw new ConfigException(msgID, message);
}
DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_EXTERNAL, this);
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -274,7 +177,7 @@
@Override()
public void finalizeSASLMechanismHandler()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeExternalChangeListener(this);
DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_EXTERNAL);
}
@@ -287,6 +190,11 @@
@Override()
public void processSASLBind(BindOperation bindOperation)
{
+ ExternalSASLMechanismHandlerCfg config = currentConfig;
+ AttributeType certificateAttributeType = this.certificateAttributeType;
+ CertificateValidationPolicy validationPolicy = this.validationPolicy;
+
+
// Get the client connection used for the bind request, and get the
// security manager for that connection. If either are null, then fail.
ClientConnection clientConnection = bindOperation.getClientConnection();
@@ -346,6 +254,7 @@
// Get the certificate mapper to use to map the certificate to a user entry.
+ DN certificateMapperDN = config.getCertificateMapperDN();
CertificateMapper certificateMapper =
DirectoryServer.getCertificateMapper(certificateMapperDN);
if (certificateMapper == null)
@@ -526,401 +435,6 @@
/**
- * Retrieves the DN of the configuration entry with which this component is
- * associated.
- *
- * @return The DN of the configuration entry with which this component is
- * associated.
- */
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated with this
- * configurable component.
- *
- * @return The set of configuration attributes that are associated with this
- * configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
- attrList.add(new MultiChoiceConfigAttribute(
- ATTR_CLIENT_CERT_VALIDATION_POLICY, getMessage(msgID),
- false, false, false, validationValueStrings,
- validationPolicy.toString()));
-
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
- String certTypeStr = certificateAttributeType.getNameOrOID();
- attrList.add(new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
- getMessage(msgID), false, false,
- false, certTypeStr));
-
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
- attrList.add(new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID),
- true, false, false,
- certificateMapperDN));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided list.
- *
- * @param configEntry The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons A list that can be used to hold messages about
- * why the provided entry does not have an
- * acceptable configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- // Look at the validation policy configuration.
- int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
- MultiChoiceConfigAttribute validateStub =
- new MultiChoiceConfigAttribute(ATTR_CLIENT_CERT_VALIDATION_POLICY,
- getMessage(msgID), false, false, false,
- validationValueStrings);
- try
- {
- MultiChoiceConfigAttribute validateAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(validateStub);
- if (validateAttr != null)
- {
- if (CertificateValidationPolicy.policyForName(
- validateAttr.activeValue())== null)
- {
- msgID = MSGID_SASLEXTERNAL_INVALID_VALIDATION_VALUE;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN),
- validateAttr.activeValue()));
- return false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_VALIDATION_POLICY;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // Look at the certificate attribute type configuration.
- String attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
- StringConfigAttribute certAttributeStub =
- new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
- getMessage(msgID), false, false, false);
- try
- {
- StringConfigAttribute certAttributeAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(certAttributeStub);
- if (certAttributeAttr != null)
- {
- attrTypeName = toLowerCase(certAttributeAttr.activeValue());
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_ATTR;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
- if (DirectoryServer.getAttributeType(attrTypeName) == null)
- {
- msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(attrTypeName),
- String.valueOf(configEntryDN)));
- return false;
- }
-
-
- // Look at the certificate mapper DN.
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
- DNConfigAttribute certMapperStub =
- new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID), true,
- false, false);
- try
- {
- DNConfigAttribute certMapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(certMapperStub);
- if (certMapperAttr == null)
- {
- msgID = MSGID_SASLEXTERNAL_NO_CERTIFICATE_MAPPER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- unacceptableReasons.add(message);
- return false;
- }
- else
- {
- DN certMapperDN = certMapperAttr.activeValue();
- CertificateMapper mapper =
- DirectoryServer.getCertificateMapper(certMapperDN);
- if (mapper == null)
- {
- msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(certMapperDN));
- unacceptableReasons.add(message);
- return false;
- }
- }
- }
- catch (Exception e)
- {
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_MAPPER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- return false;
- }
-
-
- // If we've gotten to this point, then everything must be OK.
- return true;
- }
-
-
-
- /**
- * Makes a best-effort attempt to apply the configuration contained in the
- * provided entry. Information about the result of this processing should be
- * added to the provided message list. Information should always be added to
- * this list if a configuration change could not be applied. If detailed
- * results are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not changed) should
- * also be included.
- *
- * @param configEntry The entry containing the new configuration to
- * apply for this component.
- * @param detailedResults Indicates whether detailed information about the
- * processing should be added to the list.
- *
- * @return Information about the result of the configuration update.
- */
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
- {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Look at the validation policy configuration.
- CertificateValidationPolicy newValidationPolicy =
- CertificateValidationPolicy.NEVER;
- int msgID = MSGID_SASLEXTERNAL_DESCRIPTION_VALIDATION_POLICY;
- MultiChoiceConfigAttribute validateStub =
- new MultiChoiceConfigAttribute(ATTR_CLIENT_CERT_VALIDATION_POLICY,
- getMessage(msgID), false, false, false,
- validationValueStrings);
- try
- {
- MultiChoiceConfigAttribute validateAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(validateStub);
- if (validateAttr != null)
- {
- newValidationPolicy = CertificateValidationPolicy.policyForName(
- validateAttr.activeValue());
- if (newValidationPolicy == null)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
-
- msgID = MSGID_SASLEXTERNAL_INVALID_VALIDATION_VALUE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- validateAttr.activeValue()));
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
-
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_VALIDATION_POLICY;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
-
- // Look at the certificate attribute type configuration.
- String attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERTIFICATE_ATTRIBUTE;
- StringConfigAttribute certAttributeStub =
- new StringConfigAttribute(ATTR_VALIDATION_CERT_ATTRIBUTE,
- getMessage(msgID), false, false, false);
- try
- {
- StringConfigAttribute certAttributeAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(certAttributeStub);
- if (certAttributeAttr != null)
- {
- attrTypeName = toLowerCase(certAttributeAttr.activeValue());
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- AttributeType newCertType = DirectoryServer.getAttributeType(attrTypeName);
- if (newCertType == null)
- {
- msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(attrTypeName),
- String.valueOf(configEntryDN)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- }
- }
-
-
- // Look at the certificate mapper DN.
- DN newCertificateMapperDN = null;
- msgID = MSGID_SASLEXTERNAL_DESCRIPTION_CERT_MAPPER_DN;
- DNConfigAttribute certMapperStub =
- new DNConfigAttribute(ATTR_CERTMAPPER_DN, getMessage(msgID), true,
- false, false);
- try
- {
- DNConfigAttribute certMapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(certMapperStub);
- if (certMapperAttr == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
-
- msgID = MSGID_SASLEXTERNAL_NO_CERTIFICATE_MAPPER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- else
- {
- newCertificateMapperDN = certMapperAttr.activeValue();
- CertificateMapper mapper =
- DirectoryServer.getCertificateMapper(newCertificateMapperDN);
- if (mapper == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
-
- msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(newCertificateMapperDN)));
- }
- }
- }
- catch (Exception e)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
-
- msgID = MSGID_SASLEXTERNAL_CANNOT_GET_CERT_MAPPER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
-
- // If everything has been successful, then apply any changes that were made.
- if (resultCode == ResultCode.SUCCESS)
- {
- if (newValidationPolicy != validationPolicy)
- {
- validationPolicy = newValidationPolicy;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLEXTERNAL_UPDATED_VALIDATION_POLICY;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(validationPolicy)));
- }
- }
-
- if (! certificateAttributeType.equals(newCertType))
- {
- certificateAttributeType = newCertType;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLEXTERNAL_UPDATED_CERT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- certificateAttributeType.getNameOrOID()));
- }
- }
-
- if (! newCertificateMapperDN.equals(certificateMapperDN))
- {
- certificateMapperDN = newCertificateMapperDN;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLEXTERNAL_UPDATED_CERT_MAPPER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(newCertificateMapperDN)));
- }
- }
- }
-
-
- // Return the result to the caller.
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
* {@inheritDoc}
*/
@Override()
@@ -941,5 +455,114 @@
// This may be considered a secure mechanism.
return true;
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ ExternalSASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ boolean configAcceptable = true;
+
+ // Get the attribute type to use for validating the certificates. If none
+ // is provided, then default to the userCertificate type.
+ String attrTypeName = configuration.getCertificateAttribute();
+ if (attrTypeName != null)
+ {
+ attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
+ }
+ AttributeType newCertificateType =
+ DirectoryServer.getAttributeType(toLowerCase(attrTypeName), false);
+ if (newCertificateType == null)
+ {
+ int msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
+ unacceptableReasons.add(getMessage(msgID, String.valueOf(attrTypeName),
+ String.valueOf(configEntryDN)));
+ configAcceptable = false;
+ }
+
+
+ // Make sure that the configured certificate mapper is valid.
+ CertificateMapper certificateMapper =
+ DirectoryServer.getCertificateMapper(
+ configuration.getCertificateMapperDN());
+ if (certificateMapper == null)
+ {
+ int msgID = MSGID_SASLEXTERNAL_INVALID_CERTIFICATE_MAPPER_DN;
+ unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
+ String.valueOf(configuration.getCertificateMapperDN())));
+ configAcceptable = false;
+ }
+
+
+ return configAcceptable;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ ExternalSASLMechanismHandlerCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // See if we should attempt to validate client certificates against those in
+ // the corresponding user's entry.
+ CertificateValidationPolicy newValidationPolicy =
+ CertificateValidationPolicy.ALWAYS;
+ switch (configuration.getCertificateValidationPolicy())
+ {
+ case NEVER:
+ newValidationPolicy = CertificateValidationPolicy.NEVER;
+ break;
+ case IFPRESENT:
+ newValidationPolicy = CertificateValidationPolicy.IFPRESENT;
+ break;
+ case ALWAYS:
+ newValidationPolicy = CertificateValidationPolicy.ALWAYS;
+ break;
+ }
+
+
+ // Get the attribute type to use for validating the certificates. If none
+ // is provided, then default to the userCertificate type.
+ String attrTypeName = configuration.getCertificateAttribute();
+ if (attrTypeName == null)
+ {
+ attrTypeName = DEFAULT_VALIDATION_CERT_ATTRIBUTE;
+ }
+ AttributeType newCertificateType =
+ DirectoryServer.getAttributeType(toLowerCase(attrTypeName), false);
+ if (newCertificateType == null)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
+ }
+
+ int msgID = MSGID_SASLEXTERNAL_UNKNOWN_CERT_ATTR;
+ messages.add(getMessage(msgID, String.valueOf(attrTypeName),
+ String.valueOf(configEntryDN)));
+ }
+
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ validationPolicy = newValidationPolicy;
+ certificateAttributeType = newCertificateType;
+ currentConfig = configuration;
+ }
+
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
}
diff --git a/opends/src/server/org/opends/server/extensions/FileBasedKeyManagerProvider.java b/opends/src/server/org/opends/server/extensions/FileBasedKeyManagerProvider.java
index 12076b7..78e2110 100644
--- a/opends/src/server/org/opends/server/extensions/FileBasedKeyManagerProvider.java
+++ b/opends/src/server/org/opends/server/extensions/FileBasedKeyManagerProvider.java
@@ -42,6 +42,7 @@
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
+import org.opends.server.admin.std.server.FileBasedKeyManagerCfg;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.KeyManagerProvider;
import org.opends.server.config.ConfigAttribute;
@@ -70,7 +71,7 @@
* file located on the Directory Server filesystem.
*/
public class FileBasedKeyManagerProvider
- extends KeyManagerProvider
+ extends KeyManagerProvider<FileBasedKeyManagerCfg>
implements ConfigurableComponent
{
@@ -483,9 +484,158 @@
+
+
/**
- * Performs any finalization that may be necessary for this key manager
- * provider.
+ * {@inheritDoc}
+ */
+ @Override
+ public void initializeKeyManagerProvider(
+ FileBasedKeyManagerCfg configuration)
+ throws ConfigException, InitializationException {
+ // Store the DN of the configuration entry.
+ configEntryDN = configuration.dn();
+
+ // Get the path to the key store file.
+ keyStoreFile = configuration.getKeyStoreFile();
+ try {
+ File f = getFileForPath(keyStoreFile);
+ if (!(f.exists() && f.isFile())) {
+ int msgID = MSGID_FILE_KEYMANAGER_NO_SUCH_FILE;
+ String message = getMessage(msgID, String
+ .valueOf(keyStoreFile), String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+ } catch (SecurityException e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_FILE_KEYMANAGER_CANNOT_DETERMINE_FILE;
+ String message = getMessage(msgID, String
+ .valueOf(configEntryDN), stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
+
+ // Get the keystore type. If none is specified, then use the
+ // default type.
+ if (configuration.getKeyStoreType() != null) {
+ try {
+ KeyStore.getInstance(configuration.getKeyStoreType());
+ keyStoreType = configuration.getKeyStoreType();
+ } catch (KeyStoreException kse) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, kse);
+ }
+
+ int msgID = MSGID_FILE_KEYMANAGER_INVALID_TYPE;
+ String message = getMessage(msgID, String
+ .valueOf(configuration.getKeyStoreType()), String
+ .valueOf(configEntryDN),
+ stackTraceToSingleLineString(kse));
+ throw new InitializationException(msgID, message);
+ }
+ } else {
+ keyStoreType = KeyStore.getDefaultType();
+ }
+
+ // Get the PIN needed to access the contents of the keystore file.
+ //
+ // We will offer several places to look for the PIN, and we will
+ // do so in the following order:
+ //
+ // - In a specified Java property
+ // - In a specified environment variable
+ // - In a specified file on the server filesystem.
+ // - As the value of a configuration attribute.
+ //
+ // In any case, the PIN must be in the clear.
+ keyStorePIN = null;
+ keyStorePINEnVar = null;
+ keyStorePINFile = null;
+ keyStorePINProperty = null;
+
+ if (configuration.getKeyStorePinProperty() != null) {
+ String propertyName = configuration.getKeyStorePinProperty();
+ String pinStr = System.getProperty(propertyName);
+
+ if (pinStr == null) {
+ int msgID = MSGID_FILE_KEYMANAGER_PIN_PROPERTY_NOT_SET;
+ String message = getMessage(msgID, String
+ .valueOf(propertyName), String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ keyStorePIN = pinStr.toCharArray();
+ keyStorePINProperty = propertyName;
+ } else if (configuration.getKeyStorePinEnvironmentVariable() != null) {
+ String enVarName = configuration
+ .getKeyStorePinEnvironmentVariable();
+ String pinStr = System.getenv(enVarName);
+
+ if (pinStr == null) {
+ int msgID = MSGID_FILE_KEYMANAGER_PIN_ENVAR_NOT_SET;
+ String message = getMessage(msgID, String.valueOf(enVarName),
+ String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ keyStorePIN = pinStr.toCharArray();
+ keyStorePINEnVar = enVarName;
+ } else if (configuration.getKeyStorePinFile() != null) {
+ String fileName = configuration.getKeyStorePinFile();
+ File pinFile = getFileForPath(fileName);
+
+ if (!pinFile.exists()) {
+ int msgID = MSGID_FILE_KEYMANAGER_PIN_NO_SUCH_FILE;
+ String message = getMessage(msgID, String.valueOf(fileName),
+ String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ String pinStr;
+ try {
+ BufferedReader br = new BufferedReader(
+ new FileReader(pinFile));
+ pinStr = br.readLine();
+ br.close();
+ } catch (IOException ioe) {
+ int msgID = MSGID_FILE_KEYMANAGER_PIN_FILE_CANNOT_READ;
+ String message = getMessage(msgID, String.valueOf(fileName),
+ String.valueOf(configEntryDN),
+ stackTraceToSingleLineString(ioe));
+ throw new InitializationException(msgID, message, ioe);
+ }
+
+ if (pinStr == null) {
+ int msgID = MSGID_FILE_KEYMANAGER_PIN_FILE_EMPTY;
+ String message = getMessage(msgID, String.valueOf(fileName),
+ String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ keyStorePIN = pinStr.toCharArray();
+ keyStorePINFile = fileName;
+ } else if (configuration.getKeyStorePin() != null) {
+ keyStorePIN = configuration.getKeyStorePin().toCharArray();
+ } else {
+ // Pin wasn't defined anywhere.
+ int msgID = MSGID_FILE_KEYMANAGER_NO_PIN;
+ String message = getMessage(msgID, String
+ .valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
+ }
+
+ DirectoryServer.registerConfigurableComponent(this);
+ }
+
+
+
+ /**
+ * Performs any finalization that may be necessary for this key
+ * manager provider.
*/
public void finalizeKeyManagerProvider()
{
diff --git a/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java b/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
index 48601e9..35417b3 100644
--- a/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
+++ b/opends/src/server/org/opends/server/extensions/FingerprintCertificateMapper.java
@@ -33,19 +33,13 @@
import java.security.cert.X509Certificate;
import javax.security.auth.x500.X500Principal;
import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
+import java.util.Collection;
import java.util.List;
-import java.util.Set;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.FingerprintCertificateMapperCfg;
import org.opends.server.api.CertificateMapper;
-import org.opends.server.api.ConfigurableComponent;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.MultiChoiceConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -61,7 +55,6 @@
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -78,43 +71,24 @@
* exactly one matching user entry for the mapping to be successful.
*/
public class FingerprintCertificateMapper
- extends CertificateMapper
- implements ConfigurableComponent
+ extends CertificateMapper<FingerprintCertificateMapperCfg>
+ implements ConfigurationChangeListener<
+ FingerprintCertificateMapperCfg>
{
-
-
-
- /**
- * The set of allowed fingerprint algorithms.
- */
- private static final Set<String> FINGERPRINT_ALGORITHMS;
-
-
-
// The attribute type that will be used to map the certificate's fingerprint.
private AttributeType fingerprintAttributeType;
// The DN of the configuration entry for this certificate mapper.
private DN configEntryDN;
- // The set of base DNs below which the search will be performed.
- private DN[] baseDNs;
+ // The current configuration for this certificate mapper.
+ private FingerprintCertificateMapperCfg currentConfig;
// The algorithm that will be used to generate the fingerprint.
private String fingerprintAlgorithm;
- static
- {
- LinkedHashSet<String> algorithmSet = new LinkedHashSet<String>(2);
- algorithmSet.add("md5");
- algorithmSet.add("sha1");
- FINGERPRINT_ALGORITHMS = algorithmSet;
- }
-
-
-
/**
* Creates a new instance of this certificate mapper. Note that all actual
* initialization should be done in the
@@ -123,7 +97,6 @@
public FingerprintCertificateMapper()
{
super();
-
}
@@ -131,128 +104,39 @@
/**
* {@inheritDoc}
*/
- public void initializeCertificateMapper(ConfigEntry configEntry)
+ public void initializeCertificateMapper(
+ FingerprintCertificateMapperCfg configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration.addFingerprintChangeListener(this);
+
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
+
// Get the attribute type that will be used to hold the fingerprint.
- int msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_FINGERPRINT_ATTR,
- getMessage(msgID), true, false, false);
- try
+ String attrName = configuration.getFingerprintAttribute();
+ fingerprintAttributeType =
+ DirectoryServer.getAttributeType(toLowerCase(attrName), false);
+ if (fingerprintAttributeType == null)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
- {
- msgID = MSGID_FCM_NO_FINGERPRINT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_FINGERPRINT_ATTR);
- throw new ConfigException(msgID, message);
- }
- else
- {
- String attrName = attrAttr.pendingValue();
- String lowerName = toLowerCase(attrName);
- fingerprintAttributeType =
- DirectoryServer.getAttributeType(lowerName, false);
- if (fingerprintAttributeType == null)
- {
- msgID = MSGID_FCM_NO_SUCH_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- attrName);
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_FCM_CANNOT_GET_FINGERPRINT_ATTR;
+ int msgID = MSGID_FCM_NO_SUCH_ATTR;
String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ attrName);
+ throw new ConfigException(msgID, message);
}
- // Get the fingerprint algorithm.
- msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ALGORITHM;
- MultiChoiceConfigAttribute algorithmStub =
- new MultiChoiceConfigAttribute(ATTR_CERTIFICATE_FINGERPRINT_ALGORITHM,
- getMessage(msgID), true, false, false,
- FINGERPRINT_ALGORITHMS);
- try
+ // Get the algorithm that will be used to generate the fingerprint.
+ switch (configuration.getFingerprintAlgorithm())
{
- MultiChoiceConfigAttribute algorithmAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(algorithmStub);
- if (algorithmAttr == null)
- {
- msgID = MSGID_FCM_NO_FINGERPRINT_ALGORITHM;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_FINGERPRINT_ALGORITHM);
- throw new ConfigException(msgID, message);
- }
- else
- {
- fingerprintAlgorithm = algorithmAttr.pendingValue();
- }
+ case MD5:
+ fingerprintAlgorithm = "MD5";
+ break;
+ case SHA1:
+ fingerprintAlgorithm = "SHA1";
+ break;
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_FCM_CANNOT_GET_FINGERPRINT_ALGORITHM;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Get the set of base DNs below which to perform the searches.
- baseDNs = null;
- msgID = MSGID_FCM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- baseDNs = new DN[dnList.size()];
- dnList.toArray(baseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_FCM_CANNOT_GET_BASE_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -262,7 +146,7 @@
*/
public void finalizeCertificateMapper()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeFingerprintChangeListener(this);
}
@@ -273,6 +157,10 @@
public Entry mapCertificateToUser(Certificate[] certificateChain)
throws DirectoryException
{
+ FingerprintCertificateMapperCfg config = currentConfig;
+ AttributeType fingerprintAttributeType = this.fingerprintAttributeType;
+ String fingerprintAlgorithm = this.fingerprintAlgorithm;
+
// Make sure that a peer certificate was provided.
if ((certificateChain == null) || (certificateChain.length == 0))
{
@@ -340,11 +228,10 @@
// If we have an explicit set of base DNs, then use it. Otherwise, use the
// set of public naming contexts in the server.
- DN[] bases = baseDNs;
- if (bases == null)
+ Collection<DN> baseDNs = config.getUserBaseDN();
+ if ((baseDNs == null) || baseDNs.isEmpty())
{
- bases = new DN[0];
- bases = DirectoryServer.getPublicNamingContexts().keySet().toArray(bases);
+ baseDNs = DirectoryServer.getPublicNamingContexts().keySet();
}
@@ -353,7 +240,7 @@
Entry userEntry = null;
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- for (DN baseDN : bases)
+ for (DN baseDN : baseDNs)
{
InternalSearchOperation searchOperation =
conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE, filter);
@@ -384,201 +271,24 @@
/**
- * Retrieves the DN of the configuration entry with which this
- * component is associated.
- *
- * @return The DN of the configuration entry with which this
- * component is associated.
+ * {@inheritDoc}
*/
- public DN getConfigurableComponentEntryDN()
+ public boolean isConfigurationChangeAcceptable(
+ FingerprintCertificateMapperCfg configuration,
+ List<String> unacceptableReasons)
{
- return configEntryDN;
- }
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated
- * with this configurable component.
- *
- * @return The set of configuration attributes that are associated
- * with this configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ATTR;
- attrList.add(new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR,
- getMessage(msgID), true, false, false,
- fingerprintAttributeType.getNameOrOID()));
-
- msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ALGORITHM;
- attrList.add(new MultiChoiceConfigAttribute(
- ATTR_CERTIFICATE_FINGERPRINT_ALGORITHM,
- getMessage(msgID), true, false, false,
- FINGERPRINT_ALGORITHMS, fingerprintAlgorithm));
-
- LinkedList<DN> dnList = new LinkedList<DN>();
- if (baseDNs != null)
- {
- for (DN baseDN : baseDNs)
- {
- dnList.add(baseDN);
- }
- }
-
- msgID = MSGID_FCM_DESCRIPTION_BASE_DN;
- attrList.add(new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false,
- dnList));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an
- * acceptable configuration for this component. If it does not,
- * then detailed information about the problem(s) should be added to
- * the provided list.
- *
- * @param configEntry The configuration entry for which to
- * make the determination.
- * @param unacceptableReasons A list that can be used to hold
- * messages about why the provided
- * entry does not have an acceptable
- * configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an
- * acceptable configuration for this component, or
- * <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- DN configEntryDN = configEntry.getDN();
boolean configAcceptable = true;
-
- // Get the attribute type that will be used to hold the fingerprint.
- AttributeType newFingerprintType = null;
- int msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_FINGERPRINT_ATTR,
- getMessage(msgID), true, false, false);
- try
+ // Make sure that the fingerprint attribute is defined in the server schema.
+ String attrName = configuration.getFingerprintAttribute();
+ AttributeType newFingerprintType =
+ DirectoryServer.getAttributeType(toLowerCase(attrName),
+ false);
+ if (newFingerprintType == null)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
- {
- msgID = MSGID_FCM_NO_FINGERPRINT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_FINGERPRINT_ATTR);
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
- else
- {
- String attrName = attrAttr.pendingValue();
- String lowerName = toLowerCase(attrName);
- newFingerprintType =
- DirectoryServer.getAttributeType(lowerName, false);
- if (newFingerprintType == null)
- {
- msgID = MSGID_FCM_NO_SUCH_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- attrName);
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_FCM_CANNOT_GET_FINGERPRINT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
-
-
- // Get the fingerprint algorithm.
- String newFingerprintAlgorithm = null;
- msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ALGORITHM;
- MultiChoiceConfigAttribute algorithmStub =
- new MultiChoiceConfigAttribute(ATTR_CERTIFICATE_FINGERPRINT_ALGORITHM,
- getMessage(msgID), true, false, false,
- FINGERPRINT_ALGORITHMS);
- try
- {
- MultiChoiceConfigAttribute algorithmAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(algorithmStub);
- if (algorithmAttr == null)
- {
- msgID = MSGID_FCM_NO_FINGERPRINT_ALGORITHM;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_FINGERPRINT_ALGORITHM);
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
- else
- {
- newFingerprintAlgorithm = algorithmAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_FCM_CANNOT_GET_FINGERPRINT_ALGORITHM;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
-
-
- // Get the set of base DNs below which to perform the searches.
- DN[] newBaseDNs = null;
- msgID = MSGID_FCM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- newBaseDNs = new DN[dnList.size()];
- dnList.toArray(newBaseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_FCM_CANNOT_GET_BASE_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
+ unacceptableReasons.add(getMessage(MSGID_FCM_NO_SUCH_ATTR,
+ String.valueOf(configEntryDN),
+ attrName));
configAcceptable = false;
}
@@ -589,170 +299,43 @@
/**
- * Makes a best-effort attempt to apply the configuration contained
- * in the provided entry. Information about the result of this
- * processing should be added to the provided message list.
- * Information should always be added to this list if a
- * configuration change could not be applied. If detailed results
- * are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not
- * changed) should also be included.
- *
- * @param configEntry The entry containing the new
- * configuration to apply for this
- * component.
- * @param detailedResults Indicates whether detailed information
- * about the processing should be added to
- * the list.
- *
- * @return Information about the result of the configuration
- * update.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
+ public ConfigChangeResult applyConfigurationChange(
+ FingerprintCertificateMapperCfg configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
- ArrayList<String> messages = new ArrayList<String>();
boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
- // Get the attribute type that will be used to hold the fingerprint.
- AttributeType newFingerprintType = null;
- int msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_FINGERPRINT_ATTR,
- getMessage(msgID), true, false, false);
- try
+ // Make sure that the fingerprint attribute is defined in the server schema.
+ String attrName = configuration.getFingerprintAttribute();
+ AttributeType newFingerprintType =
+ DirectoryServer.getAttributeType(toLowerCase(attrName),
+ false);
+ if (newFingerprintType == null)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
-
- msgID = MSGID_FCM_NO_FINGERPRINT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_FINGERPRINT_ATTR));
- }
- else
- {
- String attrName = attrAttr.pendingValue();
- String lowerName = toLowerCase(attrName);
- newFingerprintType =
- DirectoryServer.getAttributeType(lowerName, false);
- if (newFingerprintType == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
- }
-
- msgID = MSGID_FCM_NO_SUCH_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- attrName));
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
if (resultCode == ResultCode.SUCCESS)
{
- resultCode = DirectoryServer.getServerErrorResultCode();
+ resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
}
- msgID = MSGID_FCM_CANNOT_GET_FINGERPRINT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
+ messages.add(getMessage(MSGID_FCM_NO_SUCH_ATTR,
+ String.valueOf(configEntryDN), attrName));
}
- // Get the fingerprint algorithm.
+ // Get the algorithm that will be used to generate the fingerprint.
String newFingerprintAlgorithm = null;
- msgID = MSGID_FCM_DESCRIPTION_FINGERPRINT_ALGORITHM;
- MultiChoiceConfigAttribute algorithmStub =
- new MultiChoiceConfigAttribute(ATTR_CERTIFICATE_FINGERPRINT_ALGORITHM,
- getMessage(msgID), true, false, false,
- FINGERPRINT_ALGORITHMS);
- try
+ switch (configuration.getFingerprintAlgorithm())
{
- MultiChoiceConfigAttribute algorithmAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(algorithmStub);
- if (algorithmAttr == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
-
- msgID = MSGID_FCM_NO_FINGERPRINT_ALGORITHM;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_FINGERPRINT_ALGORITHM));
- }
- else
- {
- newFingerprintAlgorithm = algorithmAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- msgID = MSGID_FCM_CANNOT_GET_FINGERPRINT_ALGORITHM;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
-
- // Get the set of base DNs below which to perform the searches.
- DN[] newBaseDNs = null;
- msgID = MSGID_FCM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- newBaseDNs = new DN[dnList.size()];
- dnList.toArray(newBaseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- msgID = MSGID_FCM_CANNOT_GET_BASE_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
+ case MD5:
+ newFingerprintAlgorithm = "MD5";
+ break;
+ case SHA1:
+ newFingerprintAlgorithm = "SHA1";
+ break;
}
@@ -760,10 +343,11 @@
{
fingerprintAttributeType = newFingerprintType;
fingerprintAlgorithm = newFingerprintAlgorithm;
- baseDNs = newBaseDNs;
+ currentConfig = configuration;
}
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
}
diff --git a/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
index f9a7480..aba77e2 100644
--- a/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/GSSAPISASLMechanismHandler.java
@@ -33,18 +33,14 @@
import java.io.FileWriter;
import java.net.InetAddress;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.GSSAPISASLMechanismHandlerCfg;
import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.IdentityMapper;
import org.opends.server.api.SASLMechanismHandler;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.AuthenticationInfo;
@@ -55,7 +51,6 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -71,33 +66,21 @@
* clients through Kerberos over GSSAPI.
*/
public class GSSAPISASLMechanismHandler
- extends SASLMechanismHandler
- implements ConfigurableComponent
+ extends SASLMechanismHandler<GSSAPISASLMechanismHandlerCfg>
+ implements ConfigurationChangeListener<
+ GSSAPISASLMechanismHandlerCfg>
{
-
-
-
// The DN of the configuration entry for this SASL mechanism handler.
private DN configEntryDN;
- // The DN of the identity mapper configuration entry.
- private DN identityMapperDN;
+ // The current configuration for this SASL mechanism handler.
+ private GSSAPISASLMechanismHandlerCfg currentConfig;
// The identity mapper that will be used to map the Kerberos principal to a
// directory user.
private IdentityMapper identityMapper;
- // The address of the KDC to use for Kerberos authentication.
- private String kdcAddress;
-
- // The path to the keytab file to use to obtain the server key.
- private String keyTabFile;
-
- // The default realm to use for Kerberos authentication.
- private String realm;
-
- // The fully-qualified DNS name to use for the Directory Server system. This
- // is factored into the authentication process.
+ // The fully-qualified domain name for the server system.
private String serverFQDN;
@@ -110,7 +93,6 @@
public GSSAPISASLMechanismHandler()
{
super();
-
}
@@ -119,183 +101,50 @@
* {@inheritDoc}
*/
@Override()
- public void initializeSASLMechanismHandler(ConfigEntry configEntry)
+ public void initializeSASLMechanismHandler(
+ GSSAPISASLMechanismHandlerCfg configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration.addGSSAPIChangeListener(this);
+
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
// Get the identity mapper that should be used to find users.
- int msgID = MSGID_SASLGSSAPI_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (identityMapper == null)
{
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLGSSAPI_NO_IDENTITY_MAPPER_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- else
- {
- identityMapperDN = mapperAttr.activeValue();
- identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
- if (identityMapper == null)
- {
- msgID = MSGID_SASLGSSAPI_NO_SUCH_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(identityMapperDN),
- String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ int msgID = MSGID_SASLGSSAPI_NO_SUCH_IDENTITY_MAPPER;
+ String message = getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
}
// Determine the fully-qualified hostname for this system. It may be
// provided, but if not, then try to determine it programmatically.
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_SERVER_FQDN;
- StringConfigAttribute serverFQDNStub =
- new StringConfigAttribute(ATTR_SERVER_FQDN, getMessage(msgID), false,
- false, false);
- try
+ serverFQDN = configuration.getServerFqdn();
+ if (serverFQDN == null)
{
- StringConfigAttribute serverFQDNAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(serverFQDNStub);
- if (serverFQDNAttr == null)
+ try
{
- // No value was provided, so try to figure it out for ourselves.
serverFQDN = InetAddress.getLocalHost().getCanonicalHostName();
}
- else
+ catch (Exception e)
{
- serverFQDN = serverFQDNAttr.activeValue();
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_SASLGSSAPI_CANNOT_GET_SERVER_FQDN;
+ String message = getMessage(msgID, String.valueOf(configEntryDN),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
}
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_SERVER_FQDN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the address of the KDC to use. If it is not provided, then
- // we'll assume that the underlying OS has a valid config file.
- kdcAddress = null;
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_KDC_ADDRESS;
- StringConfigAttribute kdcStub =
- new StringConfigAttribute(ATTR_GSSAPI_KDC, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute kdcAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(kdcStub);
- if (kdcAttr != null)
- {
- kdcAddress = kdcAttr.activeValue();
- System.setProperty(KRBV_PROPERTY_KDC, kdcAddress);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_KDC_ADDRESS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the default realm to use. If it is not provided, then we'll
- // assume that the underlying OS has a valid config file.
- realm = null;
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_REALM;
- StringConfigAttribute realmStub =
- new StringConfigAttribute(ATTR_GSSAPI_REALM, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute realmAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(realmStub);
- if (realmAttr != null)
- {
- realm = realmAttr.activeValue();
- System.setProperty(KRBV_PROPERTY_REALM, realm);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_REALM;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the path of the keytab file to use. If it is not provided,
- // then we'll let Java use the system default keytab.
- keyTabFile = null;
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_KEYTAB_FILE;
- StringConfigAttribute keyTabStub =
- new StringConfigAttribute(ATTR_GSSAPI_KEYTAB_FILE, getMessage(msgID),
- false, false, false);
- try
- {
- StringConfigAttribute keyTabAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(keyTabStub);
- if (keyTabAttr != null)
- {
- keyTabFile = keyTabAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_KEYTAB_FILE;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
// Since we're going to be using JAAS behind the scenes, we need to have a
@@ -316,6 +165,7 @@
w.write(" com.sun.security.auth.module.Krb5LoginModule required " +
"storeKey=true useKeyTab=true ");
+ String keyTabFile = configuration.getKeytab();
if (keyTabFile != null)
{
w.write("keyTab=\"" + keyTabFile + "\" ");
@@ -325,6 +175,8 @@
// FIXME -- Can we get away from hard-coding a protocol here?
w.write("principal=\"ldap/" + serverFQDN);
+
+ String realm = configuration.getRealm();
if (realm != null)
{
w.write("@" + realm);
@@ -341,7 +193,12 @@
}
catch (Exception e)
{
- msgID = MSGID_SASLGSSAPI_CANNOT_CREATE_JAAS_CONFIG;
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_SASLGSSAPI_CANNOT_CREATE_JAAS_CONFIG;
String message = getMessage(msgID, stackTraceToSingleLineString(e));
throw new InitializationException(msgID, message, e);
}
@@ -351,7 +208,6 @@
DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_GSSAPI, this);
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -362,7 +218,7 @@
@Override()
public void finalizeSASLMechanismHandler()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeGSSAPIChangeListener(this);
DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_GSSAPI);
}
@@ -489,526 +345,6 @@
/**
- * Retrieves the DN of the configuration entry with which this component is
- * associated.
- *
- * @return The DN of the configuration entry with which this component is
- * associated.
- */
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated with this
- * configurable component.
- *
- * @return The set of configuration attributes that are associated with this
- * configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_SASLGSSAPI_DESCRIPTION_IDENTITY_MAPPER_DN;
- attrList.add(new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID),
- true, false, false, identityMapperDN));
-
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_SERVER_FQDN;
- attrList.add(new StringConfigAttribute(ATTR_SERVER_FQDN, getMessage(msgID),
- false, false, false, serverFQDN));
-
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_KDC_ADDRESS;
- attrList.add(new StringConfigAttribute(ATTR_GSSAPI_KDC, getMessage(msgID),
- false, false, false, kdcAddress));
-
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_REALM;
- attrList.add(new StringConfigAttribute(ATTR_GSSAPI_REALM, getMessage(msgID),
- false, false, false, realm));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided list.
- *
- * @param configEntry The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons A list that can be used to hold messages about
- * why the provided entry does not have an
- * acceptable configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- // Look at the identity mapper configuration
- int msgID = MSGID_SASLGSSAPI_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLGSSAPI_NO_IDENTITY_MAPPER_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- unacceptableReasons.add(message);
- return false;
- }
- else
- {
- DN mapperDN = mapperAttr.activeValue();
- IdentityMapper mapper =
- DirectoryServer.getIdentityMapper(mapperDN);
- if (mapper == null)
- {
- msgID = MSGID_SASLGSSAPI_NO_SUCH_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(mapperDN),
- String.valueOf(configEntryDN));
- unacceptableReasons.add(message);
- return false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- return false;
- }
-
-
- // Look a the server FQDN configuration.
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_SERVER_FQDN;
- StringConfigAttribute serverFQDNStub =
- new StringConfigAttribute(ATTR_SERVER_FQDN, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute serverFQDNAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(serverFQDNStub);
-
- // FIXME -- Should we try to resolve the value if one is provided?
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_SERVER_FQDN;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // Look at the KDC configuration.
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_KDC_ADDRESS;
- StringConfigAttribute kdcStub =
- new StringConfigAttribute(ATTR_GSSAPI_KDC, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute kdcAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(kdcStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_KDC_ADDRESS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // Look at the realm configuration.
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_REALM;
- StringConfigAttribute realmStub =
- new StringConfigAttribute(ATTR_GSSAPI_REALM, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute realmAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(realmStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_REALM;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // If we've gotten to this point, then everything must be OK.
- return true;
- }
-
-
-
- /**
- * Makes a best-effort attempt to apply the configuration contained in the
- * provided entry. Information about the result of this processing should be
- * added to the provided message list. Information should always be added to
- * this list if a configuration change could not be applied. If detailed
- * results are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not changed) should
- * also be included.
- *
- * @param configEntry The entry containing the new configuration to
- * apply for this component.
- * @param detailedResults Indicates whether detailed information about the
- * processing should be added to the list.
- *
- * @return Information about the result of the configuration update.
- */
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
- {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Look at the identity mapper configuration
- DN newIdentityMapperDN = null;
- IdentityMapper newIdentityMapper = null;
- int msgID = MSGID_SASLGSSAPI_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLGSSAPI_NO_IDENTITY_MAPPER_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
- }
- else
- {
- newIdentityMapperDN = mapperAttr.activeValue();
- newIdentityMapper =
- DirectoryServer.getIdentityMapper(newIdentityMapperDN);
- if (newIdentityMapper == null)
- {
- msgID = MSGID_SASLGSSAPI_NO_SUCH_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(newIdentityMapperDN),
- String.valueOf(configEntryDN)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
-
- // Look at the server FQDN configuration.
- String newServerFQDN = null;
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_SERVER_FQDN;
- StringConfigAttribute serverFQDNStub =
- new StringConfigAttribute(ATTR_SERVER_FQDN, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute serverFQDNAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(serverFQDNStub);
- if (serverFQDNAttr == null)
- {
- newServerFQDN = InetAddress.getLocalHost().getCanonicalHostName();
- }
- else
- {
- newServerFQDN = serverFQDNAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_SERVER_FQDN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
-
- // Look at the KDC configuration.
- String newKDC = null;
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_KDC_ADDRESS;
- StringConfigAttribute kdcStub =
- new StringConfigAttribute(ATTR_GSSAPI_KDC, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute kdcAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(kdcStub);
- if (kdcAttr != null)
- {
- newKDC = kdcAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_KDC_ADDRESS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
-
- // Look at the realm configuration.
- String newRealm = null;
- msgID = MSGID_SASLGSSAPI_DESCRIPTION_REALM;
- StringConfigAttribute realmStub =
- new StringConfigAttribute(ATTR_GSSAPI_REALM, getMessage(msgID), false,
- false, false);
- try
- {
- StringConfigAttribute realmAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(realmStub);
- if (realmAttr != null)
- {
- newRealm = realmAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLGSSAPI_CANNOT_GET_REALM;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
-
- // If everything has been successful, then apply any changes that were made.
- if (resultCode == ResultCode.SUCCESS)
- {
- if (! identityMapperDN.equals(newIdentityMapperDN))
- {
- identityMapperDN = newIdentityMapperDN;
- identityMapper = newIdentityMapper;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(identityMapperDN)));
- }
- }
-
- if (serverFQDN == null)
- {
- if (newServerFQDN != null)
- {
- serverFQDN = newServerFQDN;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_NEW_SERVER_FQDN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(serverFQDN)));
- }
- }
- }
- else if (newServerFQDN == null)
- {
- serverFQDN = null;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_NO_SERVER_FQDN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- }
- else
- {
- if (! serverFQDN.equals(newServerFQDN))
- {
- serverFQDN = newServerFQDN;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_NEW_SERVER_FQDN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(serverFQDN)));
- }
- }
- }
-
- if (kdcAddress == null)
- {
- if (newKDC != null)
- {
- kdcAddress = newKDC;
- System.setProperty(KRBV_PROPERTY_KDC, kdcAddress);
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_KDC;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(kdcAddress)));
- }
- }
- }
- else
- {
- if (newKDC == null)
- {
- kdcAddress = null;
- System.clearProperty(KRBV_PROPERTY_KDC);
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UNSET_KDC;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- }
- else if (! kdcAddress.equals(newKDC))
- {
- kdcAddress = newKDC;
- System.setProperty(KRBV_PROPERTY_KDC, kdcAddress);
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_KDC;
- messages.add(getMessage(msgID, String.valueOf(kdcAddress)));
- }
- }
- }
-
- if (realm == null)
- {
- if (newRealm != null)
- {
- realm = newRealm;
- System.setProperty(KRBV_PROPERTY_REALM, realm);
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_REALM;
- messages.add(getMessage(msgID, String.valueOf(realm)));
- }
- }
- }
- else
- {
- if (newRealm == null)
- {
- realm = null;
- System.clearProperty(KRBV_PROPERTY_REALM);
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UNSET_REALM;
- messages.add(getMessage(msgID));
- }
- }
- else if (! realm.equals(newRealm))
- {
- realm = newRealm;
- System.setProperty(KRBV_PROPERTY_REALM, realm);
-
- if (detailedResults)
- {
- msgID = MSGID_SASLGSSAPI_UPDATED_REALM;
- messages.add(getMessage(msgID, String.valueOf(realm)));
- }
- }
- }
- }
-
-
- // Return the result to the caller.
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
* {@inheritDoc}
*/
@Override()
@@ -1029,5 +365,159 @@
// This may be considered a secure mechanism.
return true;
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ GSSAPISASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ boolean configAcceptable = true;
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ int msgID = MSGID_SASLGSSAPI_NO_SUCH_IDENTITY_MAPPER;
+ unacceptableReasons.add(getMessage(msgID,
+ String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ configAcceptable = false;
+ }
+
+
+ return configAcceptable;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ GSSAPISASLMechanismHandlerCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ }
+
+ int msgID = MSGID_SASLGSSAPI_NO_SUCH_IDENTITY_MAPPER;
+ messages.add(getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ }
+
+
+ // Determine the fully-qualified hostname for this system. It may be
+ // provided, but if not, then try to determine it programmatically.
+ String newFQDN = configuration.getServerFqdn();
+ if (newFQDN == null)
+ {
+ try
+ {
+ newFQDN = InetAddress.getLocalHost().getCanonicalHostName();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ int msgID = MSGID_SASLGSSAPI_CANNOT_GET_SERVER_FQDN;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+ stackTraceToSingleLineString(e)));
+ }
+ }
+
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ String configFileName;
+ try
+ {
+ File tempFile = File.createTempFile("login", "conf");
+ configFileName = tempFile.getAbsolutePath();
+ tempFile.deleteOnExit();
+ BufferedWriter w = new BufferedWriter(new FileWriter(tempFile, false));
+
+ w.write(getClass().getName() + " {");
+ w.newLine();
+
+ w.write(" com.sun.security.auth.module.Krb5LoginModule required " +
+ "storeKey=true useKeyTab=true ");
+
+ String keyTabFile = configuration.getKeytab();
+ if (keyTabFile != null)
+ {
+ w.write("keyTab=\"" + keyTabFile + "\" ");
+ }
+
+ // FIXME -- Should we add the ability to include "debug=true"?
+
+ // FIXME -- Can we get away from hard-coding a protocol here?
+ w.write("principal=\"ldap/" + serverFQDN);
+
+ String realm = configuration.getRealm();
+ if (realm != null)
+ {
+ w.write("@" + realm);
+ }
+ w.write("\";");
+
+ w.newLine();
+
+ w.write("};");
+ w.newLine();
+
+ w.flush();
+ w.close();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ resultCode = DirectoryServer.getServerErrorResultCode();
+
+ int msgID = MSGID_SASLGSSAPI_CANNOT_CREATE_JAAS_CONFIG;
+ messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ System.setProperty(JAAS_PROPERTY_CONFIG_FILE, configFileName);
+
+ identityMapper = newIdentityMapper;
+ serverFQDN = newFQDN;
+ currentConfig = configuration;
+ }
+
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
}
diff --git a/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java b/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java
index af35d3f..28ec02f 100644
--- a/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java
+++ b/opends/src/server/org/opends/server/extensions/LengthBasedPasswordValidator.java
@@ -28,33 +28,22 @@
-import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import org.opends.server.api.ConfigurableComponent;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.LengthBasedPasswordValidatorCfg;
import org.opends.server.api.PasswordValidator;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.IntegerConfigAttribute;
-import org.opends.server.core.DirectoryServer;
import org.opends.server.core.Operation;
import org.opends.server.types.ByteString;
import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
import static org.opends.server.messages.ExtensionsMessages.*;
import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.util.StaticUtils.*;
@@ -62,21 +51,12 @@
* This class provides a password validator that can ensure that the provided
* password meets minimum and/or maximum length requirements.
*/
-public class LengthBasedPasswordValidator
- extends PasswordValidator
- implements ConfigurableComponent
+public class LengthBasedPasswordValidator extends
+ PasswordValidator<LengthBasedPasswordValidatorCfg> implements
+ ConfigurationChangeListener<LengthBasedPasswordValidatorCfg>
{
-
-
-
- // The DN of the configuration entry for this password validator.
- private DN configEntryDN;
-
- // The maximum number of characters allowed for a password.
- private int maxLength;
-
- // The minimum number of characters allowed for a password.
- private int minLength;
+ // The current configuration for this password validator.
+ private LengthBasedPasswordValidatorCfg currentConfig;
@@ -87,7 +67,6 @@
{
super();
-
// All initialization must be done in the initializePasswordValidator
// method.
}
@@ -98,82 +77,24 @@
* {@inheritDoc}
*/
@Override()
- public void initializePasswordValidator(ConfigEntry configEntry)
+ public void initializePasswordValidator(
+ LengthBasedPasswordValidatorCfg configuration)
throws ConfigException, InitializationException
{
- configEntryDN = configEntry.getDN();
+ configuration.addLengthBasedChangeListener(this);
+ currentConfig = configuration;
- // Get the configured minimum length.
- minLength = 0;
- int msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MIN_LENGTH;
- IntegerConfigAttribute minLengthStub =
- new IntegerConfigAttribute(ATTR_PASSWORD_MIN_LENGTH, getMessage(msgID),
- false, false, false, true, 0, false, 0);
- try
+ // Make sure that if both the maximum and minimum lengths are set, the
+ // maximum length is greater than or equal to the minimum length.
+ int maxLength = configuration.getMaximumPasswordLength();
+ int minLength = configuration.getMinimumPasswordLength();
+ if ((maxLength > 0) && (minLength > 0) && (minLength > maxLength))
{
- IntegerConfigAttribute minLengthAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(minLengthStub);
- if (minLengthAttr != null)
- {
- minLength = minLengthAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PWLENGTHVALIDATOR_CANNOT_DETERMINE_MIN_LENGTH;
- String message = getMessage(msgID, stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Get the configured maximum length.
- maxLength = 0;
- msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MAX_LENGTH;
- IntegerConfigAttribute maxLengthStub =
- new IntegerConfigAttribute(ATTR_PASSWORD_MAX_LENGTH, getMessage(msgID),
- false, false, false, true, 0, false, 0);
- try
- {
- IntegerConfigAttribute maxLengthAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(maxLengthStub);
- if (maxLengthAttr != null)
- {
- maxLength = maxLengthAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PWLENGTHVALIDATOR_CANNOT_DETERMINE_MAX_LENGTH;
- String message = getMessage(msgID, stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // If both a minimum and a maximum were provided, then make sure the
- // minimum is less than or equal to the maximum.
- if ((minLength > 0) && (maxLength > 0) && (minLength > maxLength))
- {
- msgID = MSGID_PWLENGTHVALIDATOR_MIN_GREATER_THAN_MAX;
+ int msgID = MSGID_PWLENGTHVALIDATOR_MIN_GREATER_THAN_MAX;
String message = getMessage(msgID, minLength, maxLength);
throw new ConfigException(msgID, message);
}
-
-
- // Register with the Directory Server as a configurable component.
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -184,7 +105,7 @@
@Override()
public void finalizePasswordValidator()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeLengthBasedChangeListener(this);
}
@@ -198,8 +119,11 @@
Operation operation, Entry userEntry,
StringBuilder invalidReason)
{
+ LengthBasedPasswordValidatorCfg config = currentConfig;
+
int numChars = newPassword.stringValue().length();
+ int minLength = config.getMinimumPasswordLength();
if ((minLength > 0) && (numChars < minLength))
{
invalidReason.append(getMessage(MSGID_PWLENGTHVALIDATOR_TOO_SHORT,
@@ -207,6 +131,7 @@
return false;
}
+ int maxLength = config.getMaximumPasswordLength();
if ((maxLength > 0) && (numChars > maxLength))
{
invalidReason.append(getMessage(MSGID_PWLENGTHVALIDATOR_TOO_LONG,
@@ -222,112 +147,22 @@
/**
* {@inheritDoc}
*/
- public DN getConfigurableComponentEntryDN()
+ public boolean isConfigurationChangeAcceptable(
+ LengthBasedPasswordValidatorCfg configuration,
+ List<String> unacceptableReasons)
{
- return configEntryDN;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrs = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MIN_LENGTH;
- attrs.add(new IntegerConfigAttribute(ATTR_PASSWORD_MIN_LENGTH,
- getMessage(msgID), false, false, false,
- true, 0, false, 0, minLength));
-
- msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MAX_LENGTH;
- attrs.add(new IntegerConfigAttribute(ATTR_PASSWORD_MAX_LENGTH,
- getMessage(msgID), false, false, false,
- true, 0, false, 0, maxLength));
-
- return attrs;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- // Get the configured minimum length.
- int newMinLength = 0;
- int msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MIN_LENGTH;
- IntegerConfigAttribute minLengthStub =
- new IntegerConfigAttribute(ATTR_PASSWORD_MIN_LENGTH, getMessage(msgID),
- false, false, false, true, 0, false, 0);
- try
+ // Make sure that if both the maximum and minimum lengths are set, the
+ // maximum length is greater than or equal to the minimum length.
+ int maxLength = configuration.getMaximumPasswordLength();
+ int minLength = configuration.getMinimumPasswordLength();
+ if ((maxLength > 0) && (minLength > 0) && (minLength > maxLength))
{
- IntegerConfigAttribute minLengthAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(minLengthStub);
- if (minLengthAttr != null)
- {
- newMinLength = minLengthAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PWLENGTHVALIDATOR_CANNOT_DETERMINE_MIN_LENGTH;
- unacceptableReasons.add(getMessage(msgID,
- stackTraceToSingleLineString(e)));
- }
-
-
- // Get the configured maximum length.
- int newMaxLength = 0;
- msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MAX_LENGTH;
- IntegerConfigAttribute maxLengthStub =
- new IntegerConfigAttribute(ATTR_PASSWORD_MAX_LENGTH, getMessage(msgID),
- false, false, false, true, 0, false, 0);
- try
- {
- IntegerConfigAttribute maxLengthAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(maxLengthStub);
- if (maxLengthAttr != null)
- {
- newMaxLength = maxLengthAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PWLENGTHVALIDATOR_CANNOT_DETERMINE_MAX_LENGTH;
- unacceptableReasons.add(getMessage(msgID,
- stackTraceToSingleLineString(e)));
+ int msgID = MSGID_PWLENGTHVALIDATOR_MIN_GREATER_THAN_MAX;
+ String message = getMessage(msgID, minLength, maxLength);
+ unacceptableReasons.add(message);
return false;
}
-
- // If both a minimum and a maximum were provided, then make sure the
- // minimum is less than or equal to the maximum.
- if ((newMinLength > 0) && (newMaxLength > 0) &&
- (newMinLength > newMaxLength))
- {
- msgID = MSGID_PWLENGTHVALIDATOR_MIN_GREATER_THAN_MAX;
- unacceptableReasons.add(getMessage(msgID, newMinLength, newMaxLength));
- return false;
- }
-
-
- // If we've gotten here, then everything looks OK.
return true;
}
@@ -336,124 +171,13 @@
/**
* {@inheritDoc}
*/
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
+ public ConfigChangeResult applyConfigurationChange(
+ LengthBasedPasswordValidatorCfg configuration)
{
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Get the configured minimum length.
- int newMinLength = 0;
- int msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MIN_LENGTH;
- IntegerConfigAttribute minLengthStub =
- new IntegerConfigAttribute(ATTR_PASSWORD_MIN_LENGTH, getMessage(msgID),
- false, false, false, true, 0, false, 0);
- try
- {
- IntegerConfigAttribute minLengthAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(minLengthStub);
- if (minLengthAttr != null)
- {
- newMinLength = minLengthAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- }
-
- msgID = MSGID_PWLENGTHVALIDATOR_CANNOT_DETERMINE_MIN_LENGTH;
- messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
- }
-
-
- // Get the configured maximum length.
- int newMaxLength = 0;
- msgID = MSGID_PWLENGTHVALIDATOR_DESCRIPTION_MAX_LENGTH;
- IntegerConfigAttribute maxLengthStub =
- new IntegerConfigAttribute(ATTR_PASSWORD_MAX_LENGTH, getMessage(msgID),
- false, false, false, true, 0, false, 0);
- try
- {
- IntegerConfigAttribute maxLengthAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(maxLengthStub);
- if (maxLengthAttr != null)
- {
- newMaxLength = maxLengthAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- }
-
- msgID = MSGID_PWLENGTHVALIDATOR_CANNOT_DETERMINE_MAX_LENGTH;
- messages.add(getMessage(msgID, stackTraceToSingleLineString(e)));
- }
-
-
- // If both a minimum and a maximum were provided, then make sure the
- // minimum is less than or equal to the maximum.
- if ((newMinLength > 0) && (newMaxLength > 0) &&
- (newMinLength > newMaxLength))
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
-
- msgID = MSGID_PWLENGTHVALIDATOR_MIN_GREATER_THAN_MAX;
- messages.add(getMessage(msgID, newMinLength, newMaxLength));
- }
-
-
- // If everything looks good, then apply the changes.
- if (resultCode == ResultCode.SUCCESS)
- {
- if (newMinLength != minLength)
- {
- minLength = newMinLength;
-
- if (detailedResults)
- {
- msgID = MSGID_PWLENGTHVALIDATOR_UPDATED_MIN_LENGTH;
- messages.add(getMessage(msgID, minLength));
- }
- }
-
-
- if (newMaxLength != maxLength)
- {
- maxLength = newMaxLength;
-
- if (detailedResults)
- {
- msgID = MSGID_PWLENGTHVALIDATOR_UPDATED_MAX_LENGTH;
- messages.add(getMessage(msgID, maxLength));
- }
- }
- }
-
-
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ // We will always accept the proposed configuration if it's gotten to this
+ // point.
+ currentConfig = configuration;
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
}
diff --git a/opends/src/server/org/opends/server/extensions/NullKeyManagerProvider.java b/opends/src/server/org/opends/server/extensions/NullKeyManagerProvider.java
index f84d034..50bbab0 100644
--- a/opends/src/server/org/opends/server/extensions/NullKeyManagerProvider.java
+++ b/opends/src/server/org/opends/server/extensions/NullKeyManagerProvider.java
@@ -30,6 +30,7 @@
import javax.net.ssl.KeyManager;
+import org.opends.server.admin.std.server.KeyManagerCfg;
import org.opends.server.api.KeyManagerProvider;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
@@ -86,6 +87,18 @@
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initializeKeyManagerProvider(
+ KeyManagerCfg configuration) throws ConfigException,
+ InitializationException {
+ // No implementation is required.
+ }
+
+
+
+ /**
* Performs any finalization that may be necessary for this key manager
* provider.
*/
diff --git a/opends/src/server/org/opends/server/extensions/PKCS11KeyManagerProvider.java b/opends/src/server/org/opends/server/extensions/PKCS11KeyManagerProvider.java
index 863ce5e..4b9fc96 100644
--- a/opends/src/server/org/opends/server/extensions/PKCS11KeyManagerProvider.java
+++ b/opends/src/server/org/opends/server/extensions/PKCS11KeyManagerProvider.java
@@ -40,6 +40,7 @@
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
+import org.opends.server.admin.std.server.PKCS11KeyManagerCfg;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.KeyManagerProvider;
import org.opends.server.config.ConfigAttribute;
@@ -68,9 +69,9 @@
* PKCS#11 device. It will use the Java PKCS#11 interface, which may need to be
* configured on the underlying system.
*/
-public class PKCS11KeyManagerProvider
- extends KeyManagerProvider
- implements ConfigurableComponent
+public class PKCS11KeyManagerProvider extends
+ KeyManagerProvider<PKCS11KeyManagerCfg> implements
+ ConfigurableComponent
{
@@ -367,9 +368,116 @@
+
/**
- * Performs any finalization that may be necessary for this key manager
- * provider.
+ * {@inheritDoc}
+ */
+ @Override
+ public void initializeKeyManagerProvider(
+ PKCS11KeyManagerCfg configuration)
+ throws ConfigException, InitializationException {
+ // Store the DN of the configuration entry.
+ configEntryDN = configuration.dn();
+
+ // Get the PIN needed to access the contents of the PKCS#11
+ // keystore. We will offer several places to look for the PIN, and
+ // we will do so in the following order:
+ //
+ // - In a specified Java property
+ // - In a specified environment variable
+ // - In a specified file on the server filesystem.
+ // - As the value of a configuration attribute.
+ //
+ // In any case, the PIN must be in the clear.
+ keyStorePIN = null;
+ keyStorePINEnVar = null;
+ keyStorePINFile = null;
+ keyStorePINProperty = null;
+
+ if (configuration.getKeyStorePinProperty() != null) {
+ String propertyName = configuration.getKeyStorePinProperty();
+ String pinStr = System.getProperty(propertyName);
+
+ if (pinStr == null) {
+ int msgID = MSGID_PKCS11_KEYMANAGER_PIN_PROPERTY_NOT_SET;
+ String message = getMessage(msgID, String
+ .valueOf(propertyName), String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ keyStorePIN = pinStr.toCharArray();
+ keyStorePINProperty = propertyName;
+ } else if (configuration.getKeyStorePinEnvironmentVariable() != null) {
+ String enVarName = configuration
+ .getKeyStorePinEnvironmentVariable();
+ String pinStr = System.getenv(enVarName);
+
+ if (pinStr == null) {
+ int msgID = MSGID_PKCS11_KEYMANAGER_PIN_ENVAR_NOT_SET;
+ String message = getMessage(msgID, String.valueOf(enVarName),
+ String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ keyStorePIN = pinStr.toCharArray();
+ keyStorePINEnVar = enVarName;
+ } else if (configuration.getKeyStorePinFile() != null) {
+ String fileName = configuration.getKeyStorePinFile();
+ File pinFile = getFileForPath(fileName);
+
+ if (!pinFile.exists()) {
+ int msgID = MSGID_PKCS11_KEYMANAGER_PIN_NO_SUCH_FILE;
+ String message = getMessage(msgID, String.valueOf(fileName),
+ String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ String pinStr;
+ try {
+ BufferedReader br = new BufferedReader(
+ new FileReader(pinFile));
+ pinStr = br.readLine();
+ br.close();
+ } catch (IOException ioe) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, ioe);
+ }
+
+ int msgID = MSGID_PKCS11_KEYMANAGER_PIN_FILE_CANNOT_READ;
+ String message = getMessage(msgID, String.valueOf(fileName),
+ String.valueOf(configEntryDN),
+ stackTraceToSingleLineString(ioe));
+ throw new InitializationException(msgID, message, ioe);
+ }
+
+ if (pinStr == null) {
+ int msgID = MSGID_PKCS11_KEYMANAGER_PIN_FILE_EMPTY;
+ String message = getMessage(msgID, String.valueOf(fileName),
+ String.valueOf(configEntryDN));
+ throw new InitializationException(msgID, message);
+ }
+
+ keyStorePIN = pinStr.toCharArray();
+ keyStorePINFile = fileName;
+ } else if (configuration.getKeyStorePin() != null) {
+ keyStorePIN = configuration.getKeyStorePin().toCharArray();
+ } else {
+ // Pin wasn't defined anywhere.
+ int msgID = MSGID_PKCS11_KEYMANAGER_NO_PIN;
+ String message = getMessage(msgID, String
+ .valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
+ }
+
+ DirectoryServer.registerConfigurableComponent(this);
+ }
+
+
+
+ /**
+ * Performs any finalization that may be necessary for this key
+ * manager provider.
*/
public void finalizeKeyManagerProvider()
{
diff --git a/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
index 9722118..51e2f27 100644
--- a/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
@@ -29,17 +29,14 @@
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
-import org.opends.server.api.ConfigurableComponent;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.PlainSASLMechanismHandlerCfg;
import org.opends.server.api.IdentityMapper;
import org.opends.server.api.SASLMechanismHandler;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PasswordPolicyState;
@@ -56,7 +53,6 @@
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -79,21 +75,19 @@
* connection security provider to prevent exposing the password.
*/
public class PlainSASLMechanismHandler
- extends SASLMechanismHandler
- implements ConfigurableComponent
+ extends SASLMechanismHandler<PlainSASLMechanismHandlerCfg>
+ implements ConfigurationChangeListener<
+ PlainSASLMechanismHandlerCfg>
{
-
-
-
// The DN of the configuration entry for this SASL mechanism handler.
private DN configEntryDN;
- // The DN of the identity mapper configuration entry.
- private DN identityMapperDN;
-
// The identity mapper that will be used to map ID strings to user entries.
private IdentityMapper identityMapper;
+ // The current configuration for this SASL mechanism handler.
+ private PlainSASLMechanismHandlerCfg currentConfig;
+
/**
@@ -104,7 +98,6 @@
public PlainSASLMechanismHandler()
{
super();
-
}
@@ -113,60 +106,29 @@
* {@inheritDoc}
*/
@Override()
- public void initializeSASLMechanismHandler(ConfigEntry configEntry)
+ public void initializeSASLMechanismHandler(
+ PlainSASLMechanismHandlerCfg configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration.addPlainChangeListener(this);
+
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
// Get the identity mapper that should be used to find users.
- int msgID = MSGID_SASLPLAIN_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (identityMapper == null)
{
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLPLAIN_NO_IDENTITY_MAPPER_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- else
- {
- identityMapperDN = mapperAttr.activeValue();
- identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
- if (identityMapper == null)
- {
- msgID = MSGID_SASLPLAIN_NO_SUCH_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(identityMapperDN),
- String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLPLAIN_CANNOT_GET_IDENTITY_MAPPER;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ int msgID = MSGID_SASLPLAIN_NO_SUCH_IDENTITY_MAPPER;
+ String message = getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
}
DirectoryServer.registerSASLMechanismHandler(SASL_MECHANISM_PLAIN, this);
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -177,7 +139,7 @@
@Override()
public void finalizeSASLMechanismHandler()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removePlainChangeListener(this);
DirectoryServer.deregisterSASLMechanismHandler(SASL_MECHANISM_PLAIN);
}
@@ -190,6 +152,8 @@
@Override()
public void processSASLBind(BindOperation bindOperation)
{
+ IdentityMapper identityMapper = this.identityMapper;
+
// Get the SASL credentials provided by the user and decode them.
String authzID = null;
String authcID = null;
@@ -601,206 +565,6 @@
/**
- * Retrieves the DN of the configuration entry with which this component is
- * associated.
- *
- * @return The DN of the configuration entry with which this component is
- * associated.
- */
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated with this
- * configurable component.
- *
- * @return The set of configuration attributes that are associated with this
- * configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_SASLPLAIN_DESCRIPTION_IDENTITY_MAPPER_DN;
- attrList.add(new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID),
- true, false, false, identityMapperDN));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided list.
- *
- * @param configEntry The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons A list that can be used to hold messages about
- * why the provided entry does not have an
- * acceptable configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- // Look at the identity mapper configuration.
- int msgID = MSGID_SASLPLAIN_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLPLAIN_NO_IDENTITY_MAPPER_ATTR;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- return false;
- }
-
- DN mapperDN = mapperAttr.pendingValue();
- if (! mapperDN.equals(identityMapperDN))
- {
- IdentityMapper mapper = DirectoryServer.getIdentityMapper(mapperDN);
- if (mapper == null)
- {
- msgID = MSGID_SASLPLAIN_NO_SUCH_IDENTITY_MAPPER;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(mapperDN),
- String.valueOf(configEntryDN)));
- return false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLPLAIN_CANNOT_GET_IDENTITY_MAPPER;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // If we've gotten to this point, then everything must be OK.
- return true;
- }
-
-
-
- /**
- * Makes a best-effort attempt to apply the configuration contained in the
- * provided entry. Information about the result of this processing should be
- * added to the provided message list. Information should always be added to
- * this list if a configuration change could not be applied. If detailed
- * results are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not changed) should
- * also be included.
- *
- * @param configEntry The entry containing the new configuration to
- * apply for this component.
- * @param detailedResults Indicates whether detailed information about the
- * processing should be added to the list.
- *
- * @return Information about the result of the configuration update.
- */
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
- {
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // Look at the identity mapper configuration.
- DN newIdentityMapperDN = null;
- IdentityMapper newIdentityMapper = null;
- int msgID = MSGID_SASLPLAIN_DESCRIPTION_IDENTITY_MAPPER_DN;
- DNConfigAttribute mapperStub =
- new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
- false);
- try
- {
- DNConfigAttribute mapperAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
- if (mapperAttr == null)
- {
- msgID = MSGID_SASLPLAIN_NO_IDENTITY_MAPPER_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
-
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- else
- {
- newIdentityMapperDN = mapperAttr.pendingValue();
- if (! newIdentityMapperDN.equals(identityMapperDN))
- {
- newIdentityMapper =
- DirectoryServer.getIdentityMapper(newIdentityMapperDN);
- if (newIdentityMapper == null)
- {
- msgID = MSGID_SASLPLAIN_NO_SUCH_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(newIdentityMapperDN),
- String.valueOf(configEntryDN)));
-
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SASLPLAIN_CANNOT_GET_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
-
- // If everything has been successful, then apply any changes that were made.
- if (resultCode == ResultCode.SUCCESS)
- {
- if ((newIdentityMapperDN != null) && (identityMapper != null))
- {
- identityMapperDN = newIdentityMapperDN;
- identityMapper = newIdentityMapper;
-
- if (detailedResults)
- {
- msgID = MSGID_SASLPLAIN_UPDATED_IDENTITY_MAPPER;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(identityMapperDN)));
- }
- }
- }
-
-
- // Return the result to the caller.
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
-
- /**
* {@inheritDoc}
*/
@Override()
@@ -821,5 +585,73 @@
// This is not a secure mechanism.
return false;
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ PlainSASLMechanismHandlerCfg configuration,
+ List<String> unacceptableReasons)
+ {
+ boolean configAcceptable = true;
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ int msgID = MSGID_SASLPLAIN_NO_SUCH_IDENTITY_MAPPER;
+ unacceptableReasons.add(getMessage(msgID,
+ String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ configAcceptable = false;
+ }
+
+
+ return configAcceptable;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ PlainSASLMechanismHandlerCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Get the identity mapper that should be used to find users.
+ DN identityMapperDN = configuration.getIdentityMapperDN();
+ IdentityMapper newIdentityMapper =
+ DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (newIdentityMapper == null)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ }
+
+ int msgID = MSGID_SASLPLAIN_NO_SUCH_IDENTITY_MAPPER;
+ messages.add(getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN)));
+ }
+
+
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ identityMapper = newIdentityMapper;
+ currentConfig = configuration;
+ }
+
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
}
diff --git a/opends/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java b/opends/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
index d878c1b..815f484 100644
--- a/opends/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
+++ b/opends/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapper.java
@@ -32,17 +32,16 @@
import java.security.cert.X509Certificate;
import javax.security.auth.x500.X500Principal;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.
+ SubjectAttributeToUserAttributeCertificateMapperCfg;
import org.opends.server.api.CertificateMapper;
-import org.opends.server.api.ConfigurableComponent;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -58,7 +57,6 @@
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -77,21 +75,21 @@
* to search for matching user entries.
*/
public class SubjectAttributeToUserAttributeCertificateMapper
- extends CertificateMapper
- implements ConfigurableComponent
+ extends CertificateMapper<
+ SubjectAttributeToUserAttributeCertificateMapperCfg>
+ implements ConfigurationChangeListener<
+ SubjectAttributeToUserAttributeCertificateMapperCfg>
{
-
-
-
// The DN of the configuration entry for this certificate mapper.
private DN configEntryDN;
- // The set of base DNs below which the search will be performed.
- private DN[] baseDNs;
-
// The mappings between certificate attribute names and user attribute types.
private LinkedHashMap<String,AttributeType> attributeMap;
+ // The current configuration for this certificate mapper.
+ private SubjectAttributeToUserAttributeCertificateMapperCfg
+ currentConfig;
+
/**
@@ -102,7 +100,6 @@
public SubjectAttributeToUserAttributeCertificateMapper()
{
super();
-
}
@@ -110,136 +107,74 @@
/**
* {@inheritDoc}
*/
- public void initializeCertificateMapper(ConfigEntry configEntry)
+ public void initializeCertificateMapper(
+ SubjectAttributeToUserAttributeCertificateMapperCfg
+ configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration
+ .addSubjectAttributeToUserAttributeChangeListener(this);
- // Get the attribute that will be used to map subject attributes to user
- // attributes.
- attributeMap = new LinkedHashMap<String,AttributeType>();
- int msgID = MSGID_SATUACM_DESCRIPTION_ATTR_MAP;
- StringConfigAttribute mapStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR_MAP,
- getMessage(msgID), true, true, false);
- try
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
+
+ // Get and validate the subject attribute to user attribute mappings.
+ LinkedHashMap<String,AttributeType> attributeMap =
+ new LinkedHashMap<String,AttributeType>();
+ for (String mapStr : configuration.getSubjectAttributeMapping())
{
- StringConfigAttribute mapAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(mapStub);
- if (mapAttr == null)
+ String lowerMap = toLowerCase(mapStr);
+ int colonPos = lowerMap.indexOf(':');
+ if (colonPos <= 0)
{
- msgID = MSGID_SATUACM_NO_MAP_ATTR;
+ int msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_SUBJECT_ATTR_MAP);
+ mapStr);
throw new ConfigException(msgID, message);
}
- else
+
+ String certAttrName = lowerMap.substring(0, colonPos).trim();
+ String userAttrName = lowerMap.substring(colonPos+1).trim();
+ if ((certAttrName.length() == 0) || (userAttrName.length() == 0))
{
- for (String mapStr : mapAttr.pendingValues())
+ int msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
+ String message = getMessage(msgID, String.valueOf(configEntryDN),
+ mapStr);
+ throw new ConfigException(msgID, message);
+ }
+
+ if (attributeMap.containsKey(certAttrName))
+ {
+ int msgID = MSGID_SATUACM_DUPLICATE_CERT_ATTR;
+ String message = getMessage(msgID, String.valueOf(configEntryDN),
+ certAttrName);
+ throw new ConfigException(msgID, message);
+ }
+
+ AttributeType userAttrType =
+ DirectoryServer.getAttributeType(userAttrName, false);
+ if (userAttrType == null)
+ {
+ int msgID = MSGID_SATUACM_NO_SUCH_ATTR;
+ String message = getMessage(msgID, mapStr,
+ String.valueOf(configEntryDN),
+ userAttrName);
+ throw new ConfigException(msgID, message);
+ }
+
+ for (AttributeType attrType : attributeMap.values())
+ {
+ if (attrType.equals(userAttrType))
{
- String lowerMap = toLowerCase(mapStr);
- int colonPos = lowerMap.indexOf(':');
- if (colonPos <= 0)
- {
- msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- mapStr);
- throw new ConfigException(msgID, message);
- }
-
- String certAttrName = lowerMap.substring(0, colonPos).trim();
- String userAttrName = lowerMap.substring(colonPos+1).trim();
- if ((certAttrName.length() == 0) || (userAttrName.length() == 0))
- {
- msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- mapStr);
- throw new ConfigException(msgID, message);
- }
-
- if (attributeMap.containsKey(certAttrName))
- {
- msgID = MSGID_SATUACM_DUPLICATE_CERT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- certAttrName);
- throw new ConfigException(msgID, message);
- }
-
- AttributeType userAttrType =
- DirectoryServer.getAttributeType(userAttrName, false);
- if (userAttrType == null)
- {
- msgID = MSGID_SATUACM_NO_SUCH_ATTR;
- String message = getMessage(msgID, mapStr,
- String.valueOf(configEntryDN),
- userAttrName);
- throw new ConfigException(msgID, message);
- }
-
- for (AttributeType attrType : attributeMap.values())
- {
- if (attrType.equals(userAttrType))
- {
- msgID = MSGID_SATUACM_DUPLICATE_USER_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- attrType.getNameOrOID());
- throw new ConfigException(msgID, message);
- }
- }
-
- attributeMap.put(certAttrName, userAttrType);
+ int msgID = MSGID_SATUACM_DUPLICATE_USER_ATTR;
+ String message = getMessage(msgID, String.valueOf(configEntryDN),
+ attrType.getNameOrOID());
+ throw new ConfigException(msgID, message);
}
}
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- msgID = MSGID_SATUACM_CANNOT_GET_ATTR_MAP;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ attributeMap.put(certAttrName, userAttrType);
}
-
-
- // Get the set of base DNs below which to perform the searches.
- baseDNs = null;
- msgID = MSGID_SATUACM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- baseDNs = new DN[dnList.size()];
- dnList.toArray(baseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SATUACM_CANNOT_GET_BASE_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -249,7 +184,8 @@
*/
public void finalizeCertificateMapper()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig
+ .removeSubjectAttributeToUserAttributeChangeListener(this);
}
@@ -260,6 +196,11 @@
public Entry mapCertificateToUser(Certificate[] certificateChain)
throws DirectoryException
{
+ SubjectAttributeToUserAttributeCertificateMapperCfg config =
+ currentConfig;
+ LinkedHashMap<String,AttributeType> attributeMap = this.attributeMap;
+
+
// Make sure that a peer certificate was provided.
if ((certificateChain == null) || (certificateChain.length == 0))
{
@@ -337,11 +278,10 @@
// If we have an explicit set of base DNs, then use it. Otherwise, use the
// set of public naming contexts in the server.
- DN[] bases = baseDNs;
- if (bases == null)
+ Collection<DN> baseDNs = config.getUserBaseDN();
+ if ((baseDNs == null) || baseDNs.isEmpty())
{
- bases = new DN[0];
- bases = DirectoryServer.getPublicNamingContexts().keySet().toArray(bases);
+ baseDNs = DirectoryServer.getPublicNamingContexts().keySet();
}
@@ -350,7 +290,7 @@
Entry userEntry = null;
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- for (DN baseDN : bases)
+ for (DN baseDN : baseDNs)
{
InternalSearchOperation searchOperation =
conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE, filter);
@@ -381,218 +321,78 @@
/**
- * Retrieves the DN of the configuration entry with which this
- * component is associated.
- *
- * @return The DN of the configuration entry with which this
- * component is associated.
+ * {@inheritDoc}
*/
- public DN getConfigurableComponentEntryDN()
+ public boolean isConfigurationChangeAcceptable(
+ SubjectAttributeToUserAttributeCertificateMapperCfg
+ configuration,
+ List<String> unacceptableReasons)
{
- return configEntryDN;
- }
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated
- * with this configurable component.
- *
- * @return The set of configuration attributes that are associated
- * with this configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- LinkedList<String> mapValues = new LinkedList<String>();
- for (String certAttrName : attributeMap.keySet())
- {
- AttributeType certAttrType = attributeMap.get(certAttrName);
- mapValues.add(certAttrName + ":" + certAttrType.getNameOrOID());
- }
-
- int msgID = MSGID_SATUACM_DESCRIPTION_ATTR_MAP;
- attrList.add(new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR_MAP,
- getMessage(msgID), true, false,
- false, mapValues));
-
- LinkedList<DN> dnList = new LinkedList<DN>();
- if (baseDNs != null)
- {
- for (DN baseDN : baseDNs)
- {
- dnList.add(baseDN);
- }
- }
-
- msgID = MSGID_SATUACM_DESCRIPTION_BASE_DN;
- attrList.add(new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false,
- dnList));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an
- * acceptable configuration for this component. If it does not,
- * then detailed information about the problem(s) should be added to
- * the provided list.
- *
- * @param configEntry The configuration entry for which to
- * make the determination.
- * @param unacceptableReasons A list that can be used to hold
- * messages about why the provided
- * entry does not have an acceptable
- * configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an
- * acceptable configuration for this component, or
- * <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- DN configEntryDN = configEntry.getDN();
boolean configAcceptable = true;
-
- // Get the attribute that will be used to map subject attributes to user
- // attributes.
+ // Get and validate the subject attribute to user attribute mappings.
LinkedHashMap<String,AttributeType> newAttributeMap =
new LinkedHashMap<String,AttributeType>();
- int msgID = MSGID_SATUACM_DESCRIPTION_ATTR_MAP;
- StringConfigAttribute mapStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR_MAP,
- getMessage(msgID), true, true, false);
- try
- {
- StringConfigAttribute mapAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(mapStub);
- if (mapAttr == null)
- {
- msgID = MSGID_SATUACM_NO_MAP_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_SUBJECT_ATTR_MAP);
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
- else
- {
mapLoop:
- for (String mapStr : mapAttr.pendingValues())
+ for (String mapStr : configuration.getSubjectAttributeMapping())
+ {
+ String lowerMap = toLowerCase(mapStr);
+ int colonPos = lowerMap.indexOf(':');
+ if (colonPos <= 0)
+ {
+ int msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
+ unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
+ mapStr));
+ configAcceptable = false;
+ break;
+ }
+
+ String certAttrName = lowerMap.substring(0, colonPos).trim();
+ String userAttrName = lowerMap.substring(colonPos+1).trim();
+ if ((certAttrName.length() == 0) || (userAttrName.length() == 0))
+ {
+ int msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
+ unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
+ mapStr));
+ configAcceptable = false;
+ break;
+ }
+
+ if (newAttributeMap.containsKey(certAttrName))
+ {
+ int msgID = MSGID_SATUACM_DUPLICATE_CERT_ATTR;
+ unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
+ certAttrName));
+ configAcceptable = false;
+ break;
+ }
+
+ AttributeType userAttrType =
+ DirectoryServer.getAttributeType(userAttrName, false);
+ if (userAttrType == null)
+ {
+ int msgID = MSGID_SATUACM_NO_SUCH_ATTR;
+ unacceptableReasons.add(getMessage(msgID, mapStr,
+ String.valueOf(configEntryDN),
+ userAttrName));
+ configAcceptable = false;
+ break;
+ }
+
+ for (AttributeType attrType : newAttributeMap.values())
+ {
+ if (attrType.equals(userAttrType))
{
- String lowerMap = toLowerCase(mapStr);
- int colonPos = lowerMap.indexOf(':');
- if (colonPos <= 0)
- {
- msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- mapStr);
- unacceptableReasons.add(message);
- configAcceptable = false;
- continue;
- }
-
- String certAttrName = lowerMap.substring(0, colonPos).trim();
- String userAttrName = lowerMap.substring(colonPos+1).trim();
- if ((certAttrName.length() == 0) || (userAttrName.length() == 0))
- {
- msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- mapStr);
- unacceptableReasons.add(message);
- configAcceptable = false;
- continue;
- }
-
- if (newAttributeMap.containsKey(certAttrName))
- {
- msgID = MSGID_SATUACM_DUPLICATE_CERT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- certAttrName);
- unacceptableReasons.add(message);
- configAcceptable = false;
- continue;
- }
-
- AttributeType userAttrType =
- DirectoryServer.getAttributeType(userAttrName, false);
- if (userAttrType == null)
- {
- msgID = MSGID_SATUACM_NO_SUCH_ATTR;
- String message = getMessage(msgID, mapStr,
- String.valueOf(configEntryDN),
- userAttrName);
- unacceptableReasons.add(message);
- configAcceptable = false;
- continue;
- }
-
- for (AttributeType attrType : newAttributeMap.values())
- {
- if (attrType.equals(userAttrType))
- {
- msgID = MSGID_SATUACM_DUPLICATE_USER_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- attrType.getNameOrOID());
- unacceptableReasons.add(message);
- configAcceptable = false;
- continue mapLoop;
- }
- }
-
- newAttributeMap.put(certAttrName, userAttrType);
+ int msgID = MSGID_SATUACM_DUPLICATE_USER_ATTR;
+ unacceptableReasons.add(getMessage(msgID,
+ String.valueOf(configEntryDN),
+ attrType.getNameOrOID()));
+ configAcceptable = false;
+ break mapLoop;
}
}
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- msgID = MSGID_SATUACM_CANNOT_GET_ATTR_MAP;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
-
-
- // Get the set of base DNs below which to perform the searches.
- DN[] newBaseDNs = null;
- msgID = MSGID_SATUACM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- newBaseDNs = new DN[dnList.size()];
- dnList.toArray(newBaseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SATUACM_CANNOT_GET_BASE_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- configAcceptable = false;
+ newAttributeMap.put(certAttrName, userAttrType);
}
@@ -602,201 +402,107 @@
/**
- * Makes a best-effort attempt to apply the configuration contained
- * in the provided entry. Information about the result of this
- * processing should be added to the provided message list.
- * Information should always be added to this list if a
- * configuration change could not be applied. If detailed results
- * are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not
- * changed) should also be included.
- *
- * @param configEntry The entry containing the new
- * configuration to apply for this
- * component.
- * @param detailedResults Indicates whether detailed information
- * about the processing should be added to
- * the list.
- *
- * @return Information about the result of the configuration
- * update.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
+ public ConfigChangeResult applyConfigurationChange(
+ SubjectAttributeToUserAttributeCertificateMapperCfg
+ configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
- ArrayList<String> messages = new ArrayList<String>();
boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
- // Get the attribute that will be used to map subject attributes to user
- // attributes.
+ // Get and validate the subject attribute to user attribute mappings.
LinkedHashMap<String,AttributeType> newAttributeMap =
new LinkedHashMap<String,AttributeType>();
- int msgID = MSGID_SATUACM_DESCRIPTION_ATTR_MAP;
- StringConfigAttribute mapStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR_MAP,
- getMessage(msgID), true, true, false);
- try
+mapLoop:
+ for (String mapStr : configuration.getSubjectAttributeMapping())
{
- StringConfigAttribute mapAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(mapStub);
- if (mapAttr == null)
+ String lowerMap = toLowerCase(mapStr);
+ int colonPos = lowerMap.indexOf(':');
+ if (colonPos <= 0)
{
if (resultCode == ResultCode.SUCCESS)
{
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
}
- msgID = MSGID_SATUACM_NO_MAP_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_SUBJECT_ATTR_MAP));
+ int msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN), mapStr));
+ break;
}
- else
+
+ String certAttrName = lowerMap.substring(0, colonPos).trim();
+ String userAttrName = lowerMap.substring(colonPos+1).trim();
+ if ((certAttrName.length() == 0) || (userAttrName.length() == 0))
{
-mapLoop:
- for (String mapStr : mapAttr.pendingValues())
+ if (resultCode == ResultCode.SUCCESS)
{
- String lowerMap = toLowerCase(mapStr);
- int colonPos = lowerMap.indexOf(':');
- if (colonPos <= 0)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- }
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ }
- msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- mapStr));
- break;
+ int msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN), mapStr));
+ break;
+ }
+
+ if (newAttributeMap.containsKey(certAttrName))
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ }
+
+ int msgID = MSGID_SATUACM_DUPLICATE_CERT_ATTR;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+ certAttrName));
+ break;
+ }
+
+ AttributeType userAttrType =
+ DirectoryServer.getAttributeType(userAttrName, false);
+ if (userAttrType == null)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+ }
+
+ int msgID = MSGID_SATUACM_NO_SUCH_ATTR;
+ messages.add(getMessage(msgID, mapStr, String.valueOf(configEntryDN),
+ userAttrName));
+ break;
+ }
+
+ for (AttributeType attrType : newAttributeMap.values())
+ {
+ if (attrType.equals(userAttrType))
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
}
- String certAttrName = lowerMap.substring(0, colonPos).trim();
- String userAttrName = lowerMap.substring(colonPos+1).trim();
- if ((certAttrName.length() == 0) || (userAttrName.length() == 0))
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- }
-
- msgID = MSGID_SATUACM_INVALID_MAP_FORMAT;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- mapStr));
- break;
- }
-
- if (newAttributeMap.containsKey(certAttrName))
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
-
- msgID = MSGID_SATUACM_DUPLICATE_CERT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- certAttrName));
- break;
- }
-
- AttributeType userAttrType =
- DirectoryServer.getAttributeType(userAttrName, false);
- if (userAttrType == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
- }
-
- msgID = MSGID_SATUACM_NO_SUCH_ATTR;
- messages.add(getMessage(msgID, mapStr,
- String.valueOf(configEntryDN),
- userAttrName));
- break;
- }
-
- for (AttributeType attrType : newAttributeMap.values())
- {
- if (attrType.equals(userAttrType))
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
-
- msgID = MSGID_SATUACM_DUPLICATE_USER_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- attrType.getNameOrOID()));
- break mapLoop;
- }
- }
-
- newAttributeMap.put(certAttrName, userAttrType);
+ int msgID = MSGID_SATUACM_DUPLICATE_USER_ATTR;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+ attrType.getNameOrOID()));
+ break mapLoop;
}
}
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- msgID = MSGID_SATUACM_CANNOT_GET_ATTR_MAP;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
-
- // Get the set of base DNs below which to perform the searches.
- DN[] newBaseDNs = null;
- msgID = MSGID_SATUACM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- newBaseDNs = new DN[dnList.size()];
- dnList.toArray(newBaseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- msgID = MSGID_SATUACM_CANNOT_GET_BASE_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
+ newAttributeMap.put(certAttrName, userAttrType);
}
if (resultCode == ResultCode.SUCCESS)
{
- attributeMap = newAttributeMap;
- baseDNs = newBaseDNs;
+ attributeMap = newAttributeMap;
+ currentConfig = configuration;
}
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
}
diff --git a/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java b/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
index 55c5a1a..2a01254 100644
--- a/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
+++ b/opends/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapper.java
@@ -32,16 +32,14 @@
import java.security.cert.X509Certificate;
import javax.security.auth.x500.X500Principal;
import java.util.ArrayList;
-import java.util.LinkedList;
+import java.util.Collection;
import java.util.List;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.
+ SubjectDNToUserAttributeCertificateMapperCfg;
import org.opends.server.api.CertificateMapper;
-import org.opends.server.api.ConfigurableComponent;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -57,7 +55,6 @@
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
@@ -74,20 +71,19 @@
* one matching user entry for the mapping to be successful.
*/
public class SubjectDNToUserAttributeCertificateMapper
- extends CertificateMapper
- implements ConfigurableComponent
+ extends CertificateMapper<
+ SubjectDNToUserAttributeCertificateMapperCfg>
+ implements ConfigurationChangeListener<
+ SubjectDNToUserAttributeCertificateMapperCfg>
{
-
-
-
// The attribute type that will be used to map the certificate's subject.
private AttributeType subjectAttributeType;
// The DN of the configuration entry for this certificate mapper.
private DN configEntryDN;
- // The set of base DNs below which the search will be performed.
- private DN[] baseDNs;
+ // The current configuration for this certificate mapper.
+ private SubjectDNToUserAttributeCertificateMapperCfg currentConfig;
@@ -99,7 +95,6 @@
public SubjectDNToUserAttributeCertificateMapper()
{
super();
-
}
@@ -107,91 +102,28 @@
/**
* {@inheritDoc}
*/
- public void initializeCertificateMapper(ConfigEntry configEntry)
+ public void initializeCertificateMapper(
+ SubjectDNToUserAttributeCertificateMapperCfg
+ configuration)
throws ConfigException, InitializationException
{
- this.configEntryDN = configEntry.getDN();
+ configuration.addSubjectDNToUserAttributeChangeListener(this);
- // Get the attribute type that will be used to hold the certificate subject.
- int msgID = MSGID_SDTUACM_DESCRIPTION_SUBJECT_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR,
- getMessage(msgID), true, false, false);
- try
- {
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
- {
- msgID = MSGID_SDTUACM_NO_SUBJECT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_SUBJECT_ATTR);
- throw new ConfigException(msgID, message);
- }
- else
- {
- String attrName = attrAttr.pendingValue();
- String lowerName = toLowerCase(attrName);
- subjectAttributeType =
- DirectoryServer.getAttributeType(lowerName, false);
- if (subjectAttributeType == null)
- {
- msgID = MSGID_SDTUACM_NO_SUCH_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- attrName);
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
- msgID = MSGID_SDTUACM_CANNOT_GET_SUBJECT_ATTR;
+
+ // Get the attribute type that will be used to hold the fingerprint.
+ String attrName = configuration.getSubjectAttribute();
+ subjectAttributeType =
+ DirectoryServer.getAttributeType(toLowerCase(attrName), false);
+ if (subjectAttributeType == null)
+ {
+ int msgID = MSGID_SDTUACM_NO_SUCH_ATTR;
String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
+ attrName);
+ throw new ConfigException(msgID, message);
}
-
-
- // Get the set of base DNs below which to perform the searches.
- baseDNs = null;
- msgID = MSGID_SDTUACM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- baseDNs = new DN[dnList.size()];
- dnList.toArray(baseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SDTUACM_CANNOT_GET_BASE_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
- DirectoryServer.registerConfigurableComponent(this);
}
@@ -201,7 +133,7 @@
*/
public void finalizeCertificateMapper()
{
- DirectoryServer.deregisterConfigurableComponent(this);
+ currentConfig.removeSubjectDNToUserAttributeChangeListener(this);
}
@@ -212,6 +144,11 @@
public Entry mapCertificateToUser(Certificate[] certificateChain)
throws DirectoryException
{
+ SubjectDNToUserAttributeCertificateMapperCfg config =
+ currentConfig;
+ AttributeType subjectAttributeType = this.subjectAttributeType;
+
+
// Make sure that a peer certificate was provided.
if ((certificateChain == null) || (certificateChain.length == 0))
{
@@ -254,11 +191,10 @@
// If we have an explicit set of base DNs, then use it. Otherwise, use the
// set of public naming contexts in the server.
- DN[] bases = baseDNs;
- if (bases == null)
+ Collection<DN> baseDNs = config.getUserBaseDN();
+ if ((baseDNs == null) || baseDNs.isEmpty())
{
- bases = new DN[0];
- bases = DirectoryServer.getPublicNamingContexts().keySet().toArray(bases);
+ baseDNs = DirectoryServer.getPublicNamingContexts().keySet();
}
@@ -267,7 +203,7 @@
Entry userEntry = null;
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- for (DN baseDN : bases)
+ for (DN baseDN : baseDNs)
{
InternalSearchOperation searchOperation =
conn.processSearch(baseDN, SearchScope.WHOLE_SUBTREE, filter);
@@ -298,147 +234,25 @@
/**
- * Retrieves the DN of the configuration entry with which this
- * component is associated.
- *
- * @return The DN of the configuration entry with which this
- * component is associated.
+ * {@inheritDoc}
*/
- public DN getConfigurableComponentEntryDN()
+ public boolean isConfigurationChangeAcceptable(
+ SubjectDNToUserAttributeCertificateMapperCfg
+ configuration,
+ List<String> unacceptableReasons)
{
- return configEntryDN;
- }
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated
- * with this configurable component.
- *
- * @return The set of configuration attributes that are associated
- * with this configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_SDTUACM_DESCRIPTION_SUBJECT_ATTR;
- attrList.add(new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR,
- getMessage(msgID), true, false, false,
- subjectAttributeType.getNameOrOID()));
-
- LinkedList<DN> dnList = new LinkedList<DN>();
- if (baseDNs != null)
- {
- for (DN baseDN : baseDNs)
- {
- dnList.add(baseDN);
- }
- }
-
- msgID = MSGID_SDTUACM_DESCRIPTION_BASE_DN;
- attrList.add(new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false,
- dnList));
-
- return attrList;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an
- * acceptable configuration for this component. If it does not,
- * then detailed information about the problem(s) should be added to
- * the provided list.
- *
- * @param configEntry The configuration entry for which to
- * make the determination.
- * @param unacceptableReasons A list that can be used to hold
- * messages about why the provided
- * entry does not have an acceptable
- * configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an
- * acceptable configuration for this component, or
- * <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- DN configEntryDN = configEntry.getDN();
boolean configAcceptable = true;
-
- // Get the attribute type that will be used to hold the certificate subject.
- int msgID = MSGID_SDTUACM_DESCRIPTION_SUBJECT_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR,
- getMessage(msgID), true, false, false);
- try
+ // Make sure that the subject attribute is defined in the server schema.
+ String attrName = configuration.getSubjectAttribute();
+ AttributeType newSubjectType =
+ DirectoryServer.getAttributeType(toLowerCase(attrName),
+ false);
+ if (newSubjectType == null)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
- {
- msgID = MSGID_SDTUACM_NO_SUBJECT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_SUBJECT_ATTR);
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
- else
- {
- String attrName = attrAttr.pendingValue();
- String lowerName = toLowerCase(attrName);
- AttributeType attrType =
- DirectoryServer.getAttributeType(lowerName, false);
- if (attrType == null)
- {
- msgID = MSGID_SDTUACM_NO_SUCH_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- attrName);
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SDTUACM_CANNOT_GET_SUBJECT_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- configAcceptable = false;
- }
-
-
- // Get the set of base DNs below which to perform the searches.
- msgID = MSGID_SDTUACM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_SDTUACM_CANNOT_GET_BASE_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
+ unacceptableReasons.add(getMessage(MSGID_SDTUACM_NO_SUCH_ATTR,
+ String.valueOf(configEntryDN),
+ attrName));
configAcceptable = false;
}
@@ -449,133 +263,42 @@
/**
- * Makes a best-effort attempt to apply the configuration contained
- * in the provided entry. Information about the result of this
- * processing should be added to the provided message list.
- * Information should always be added to this list if a
- * configuration change could not be applied. If detailed results
- * are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not
- * changed) should also be included.
- *
- * @param configEntry The entry containing the new
- * configuration to apply for this
- * component.
- * @param detailedResults Indicates whether detailed information
- * about the processing should be added to
- * the list.
- *
- * @return Information about the result of the configuration
- * update.
+ * {@inheritDoc}
*/
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
+ public ConfigChangeResult applyConfigurationChange(
+ SubjectDNToUserAttributeCertificateMapperCfg
+ configuration)
{
- DN configEntryDN = configEntry.getDN();
ResultCode resultCode = ResultCode.SUCCESS;
- ArrayList<String> messages = new ArrayList<String>();
boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
- // Get the attribute type that will be used to hold the certificate subject.
- AttributeType newAttributeType = null;
- int msgID = MSGID_SDTUACM_DESCRIPTION_SUBJECT_ATTR;
- StringConfigAttribute attrStub =
- new StringConfigAttribute(ATTR_CERTIFICATE_SUBJECT_ATTR,
- getMessage(msgID), true, false, false);
- try
+ // Make sure that the fingerprint attribute is defined in the server schema.
+ String attrName = configuration.getSubjectAttribute();
+ AttributeType newSubjectType =
+ DirectoryServer.getAttributeType(toLowerCase(attrName),
+ false);
+ if (newSubjectType == null)
{
- StringConfigAttribute attrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(attrStub);
- if (attrAttr == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
-
- msgID = MSGID_SDTUACM_NO_SUBJECT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- ATTR_CERTIFICATE_SUBJECT_ATTR));
- }
- else
- {
- String attrName = attrAttr.pendingValue();
- String lowerName = toLowerCase(attrName);
- newAttributeType = DirectoryServer.getAttributeType(lowerName, false);
- if (subjectAttributeType == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
- }
-
- msgID = MSGID_SDTUACM_NO_SUCH_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- attrName));
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
if (resultCode == ResultCode.SUCCESS)
{
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
+ resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
}
- msgID = MSGID_SDTUACM_CANNOT_GET_SUBJECT_ATTR;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
-
- // Get the set of base DNs below which to perform the searches.
- DN[] newBaseDNs = null;
- msgID = MSGID_SDTUACM_DESCRIPTION_BASE_DN;
- DNConfigAttribute baseStub =
- new DNConfigAttribute(ATTR_CERTIFICATE_SUBJECT_BASEDN,
- getMessage(msgID), false, true, false);
- try
- {
- DNConfigAttribute baseAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(baseStub);
- if (baseAttr != null)
- {
- List<DN> dnList = baseAttr.activeValues();
- newBaseDNs = new DN[dnList.size()];
- dnList.toArray(newBaseDNs);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.OBJECTCLASS_VIOLATION;
- }
-
- msgID = MSGID_SDTUACM_CANNOT_GET_BASE_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
+ messages.add(getMessage(MSGID_SDTUACM_NO_SUCH_ATTR,
+ String.valueOf(configEntryDN), attrName));
}
if (resultCode == ResultCode.SUCCESS)
{
- subjectAttributeType = newAttributeType;
- baseDNs = newBaseDNs;
+ subjectAttributeType = newSubjectType;
+ currentConfig = configuration;
}
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
}
diff --git a/opends/src/server/org/opends/server/extensions/SubjectEqualsDNCertificateMapper.java b/opends/src/server/org/opends/server/extensions/SubjectEqualsDNCertificateMapper.java
index 7894c61..9bbe1be 100644
--- a/opends/src/server/org/opends/server/extensions/SubjectEqualsDNCertificateMapper.java
+++ b/opends/src/server/org/opends/server/extensions/SubjectEqualsDNCertificateMapper.java
@@ -33,8 +33,8 @@
import javax.security.auth.x500.X500Principal;
import java.util.concurrent.locks.Lock;
+import org.opends.server.admin.std.server.CertificateMapperCfg;
import org.opends.server.api.CertificateMapper;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DirectoryException;
@@ -59,11 +59,8 @@
* exactly matches the DN of a user in the Directory Server.
*/
public class SubjectEqualsDNCertificateMapper
- extends CertificateMapper
+ extends CertificateMapper<CertificateMapperCfg>
{
-
-
-
/**
* Creates a new instance of this certificate mapper. Note that all actual
* initialization should be done in the
@@ -78,20 +75,10 @@
/**
- * Initializes this certificate mapper based on the information in the
- * provided configuration entry.
- *
- * @param configEntry The configuration entry that contains the information
- * to use to initialize this certificate mapper.
- *
- * @throws ConfigException If the provided entry does not contain a valid
- * certificate mapper configuration.
- *
- * @throws InitializationException If a problem occurs during initialization
- * that is not related to the server
- * configuration.
+ * {@inheritDoc}
*/
- public void initializeCertificateMapper(ConfigEntry configEntry)
+ public void initializeCertificateMapper(CertificateMapperCfg
+ configuration)
throws ConfigException, InitializationException
{
// No initialization is required.
diff --git a/opends/src/server/org/opends/server/messages/AdminMessages.java b/opends/src/server/org/opends/server/messages/AdminMessages.java
new file mode 100644
index 0000000..8f01119
--- /dev/null
+++ b/opends/src/server/org/opends/server/messages/AdminMessages.java
@@ -0,0 +1,292 @@
+/*
+ * 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.messages;
+
+
+
+import static org.opends.server.messages.MessageHandler.*;
+
+
+
+/**
+ * This class defines the set of message IDs and default format strings for
+ * messages associated with the server-side administration framework.
+ * <p>
+ * FIXME: At the moment these error messages are just temporary and will be
+ * replaced in time with more specific detailed messages.
+ */
+public final class AdminMessages {
+
+ /**
+ * The message ID for the message that will be used if a problem occurs while
+ * trying to get the base entry for a configuration listener. This takes two
+ * arguments: the DN of the base entry, and a string representation of the
+ * exception that was caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_GET_LISTENER_BASE =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 1;
+
+ /**
+ * The message ID for the message that will be used if the base entry for a
+ * configuration listener does not exist in the server. This takes a single
+ * argument, which is the DN of the configuration entry.
+ */
+ public static final int MSGID_ADMIN_LISTENER_BASE_DOES_NOT_EXIST =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 2;
+
+ /**
+ * The message ID for the message that will be used if a problem occurs while
+ * trying to get the configuration entry associated with a managed object.
+ * This takes two arguments: the DN of the configuration entry, and a string
+ * representation of the exception that was caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_GET_MANAGED_OBJECT =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 3;
+
+ /**
+ * The message ID for the message that will be used if the configuration entry
+ * associated with a managed object does not exist in the server. This takes a
+ * single argument, which is the DN of the configuration entry.
+ */
+ public static final int MSGID_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 4;
+
+ /**
+ * The message ID for the message that will be used if a managed cannot be
+ * successfully decoded from its associated configuration entry. This takes
+ * two arguments: the DN of the configuration entry, and a string
+ * representation of the exception that was caught.
+ */
+ public static final int MSGID_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 5;
+
+ /**
+ * The message ID for the message that will be used if an error occurs while
+ * attempting to load and instantiate a configuration object. This takes three
+ * arguments, which are the name of the class, the DN of the configuration
+ * entry, and a string representation of the exception that was caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_INSTANTIATE_CLASS =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 6;
+
+ /**
+ * The message ID for the message that will be used if an error occurs while
+ * attempting to initialize a configuration object. This takes three
+ * arguments, which are the name of the class, the DN of the configuration
+ * entry, and a string representation of the exception that was caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_INITIALIZE_COMPONENT =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 7;
+
+ /**
+ * The message ID for the message that will be used if a component
+ * has been explicitly disabled. This takes a single argument,
+ * which is the DN of the configuration entry.
+ */
+ public static final int MSGID_ADMIN_COMPONENT_DISABLED =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_MILD_WARNING | 8;
+
+ /**
+ * The message ID for the message that will be used if an error
+ * occurs while trying to open a file for reading. This takes three
+ * arguments, which are the name of the jar file, the path to the
+ * jar directory, and a string representation of the exception that
+ * was caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_OPEN_JAR_FILE =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 9;
+
+ /**
+ * The message ID for the message that will be used if an error
+ * occurs while trying to load a core administration configuration
+ * definition class. This takes two arguments, which are the name of
+ * the manifest file, and a string representation of the exception
+ * that was caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_CORE_MANIFEST =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_FATAL_ERROR | 10;
+
+ /**
+ * The message ID for the message that will be used if an error
+ * occurs while trying to load a administration configuration
+ * definition class from an extension. This takes three arguments,
+ * which are the name of the manifest file, the name of the
+ * extension jar file, and a string representation of the exception
+ * that was caught.
+ */
+ public static final int
+ MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_EXTENSION_MANIFEST =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 11;
+
+ /**
+ * The message ID for the message that will be used if the
+ * extensions directory does not exist. This takes a single
+ * argument, which is the path to the extensions directory.
+ */
+ public static final int MSGID_ADMIN_NO_EXTENSIONS_DIR =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_MILD_ERROR | 12;
+
+ /**
+ * The message ID for the message that will be used if the
+ * extensions directory is not a directory. This takes a single
+ * argument, which is the path to the extensions directory.
+ */
+ public static final int MSGID_ADMIN_EXTENSIONS_DIR_NOT_DIRECTORY =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 13;
+
+ /**
+ * The message ID for the message that will be used if an error
+ * occurs while trying to list the files in the extensions
+ * directory. This takes two arguments, which are the path to the
+ * extensions directory and a string representation of the exception
+ * that was caught.
+ */
+ public static final int MSGID_ADMIN_EXTENSIONS_CANNOT_LIST_FILES =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 14;
+
+ /**
+ * The message ID for the message that will be used if the core
+ * administration configuration definition manifest file cannot be
+ * located. This takes a single argument, which is the name of the
+ * manifest file.
+ */
+ public static final int MSGID_ADMIN_CANNOT_FIND_CORE_MANIFEST =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_FATAL_ERROR | 15;
+
+ /**
+ * The message ID for the message that will be used if the core
+ * administration configuration definition manifest file cannot be
+ * read. This takes two arguments, which are the name of the
+ * manifest file and a string representation of the exception that
+ * was caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_READ_CORE_MANIFEST =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_FATAL_ERROR | 16;
+
+ /**
+ * The message ID for the message that will be used if the
+ * administration configuration definition manifest file contained
+ * in a extension cannot be read. This takes three arguments, which
+ * are the name of the manifest file, the name of the extension jar
+ * file, and a string representation of the exception that was
+ * caught.
+ */
+ public static final int MSGID_ADMIN_CANNOT_READ_EXTENSION_MANIFEST =
+ CATEGORY_MASK_ADMIN | SEVERITY_MASK_SEVERE_ERROR | 17;
+
+ // Prevent instantiation.
+ private AdminMessages() {
+ // Do nothing.
+ }
+
+
+
+ /**
+ * Associates a set of generic messages with the message IDs defined in this
+ * class.
+ */
+ public static void registerMessages() {
+ registerMessage(MSGID_ADMIN_CANNOT_GET_LISTENER_BASE,
+ "An error occurred while trying to "
+ + "retrieve relation configuration entry %s: %s.");
+
+ registerMessage(MSGID_ADMIN_LISTENER_BASE_DOES_NOT_EXIST,
+ "The relation entry %s does not appear to exist in the "
+ + "Directory Server configuration. This is a required entry.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_GET_MANAGED_OBJECT,
+ "An error occurred while trying to "
+ + "retrieve the managed object configuration entry %s: %s.");
+
+ registerMessage(MSGID_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST,
+ "The the managed object configuration entry %s does not "
+ + "appear to exist in the Directory Server "
+ + "configuration. This is a required entry.");
+
+ registerMessage(MSGID_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM,
+ "An error occurred while trying to "
+ + "decode the managed object configuration entry %s: %s.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_INSTANTIATE_CLASS,
+ "The Directory Server was unable to load class %s and "
+ + "use it to create a component instance as "
+ + "defined in configuration entry %s. The error that "
+ + "occurred was: %s. This component will be " + "disabled.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_INITIALIZE_COMPONENT,
+ "An error occurred while trying to initialize a " +
+ "component instance loaded from class %s with the " +
+ "information in configuration entry %s: %s. This " +
+ "component will be disabled.");
+
+ registerMessage(MSGID_ADMIN_COMPONENT_DISABLED,
+ "The Directory Server component configured in " +
+ "entry %s has been disabled.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_OPEN_JAR_FILE,
+ "The Directory Server jar file %s in directory %s cannot be " +
+ "loaded because an unexpected error occurred while " +
+ "trying to open the file for reading: %s.");
+
+ registerMessage(MSGID_ADMIN_NO_EXTENSIONS_DIR,
+ "The extensions directory %s does not exist, therefore no " +
+ "extensions will be loaded.");
+
+ registerMessage(MSGID_ADMIN_EXTENSIONS_DIR_NOT_DIRECTORY,
+ "Unable to read the Directory Server extensions " +
+ "because the extensions directory %s exists but is not a " +
+ "directory.");
+
+ registerMessage(MSGID_ADMIN_EXTENSIONS_CANNOT_LIST_FILES,
+ "Unable to read the Directory Server extensions " +
+ "from directory %s because an unexpected error occurred " +
+ "while trying to list the files in that directory: %s.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_CORE_MANIFEST,
+ "A core configuration definition class could not be loaded " +
+ "from the core manifest file %s because an unexpected error " +
+ "occurred while trying to initialize it: %s.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_LOAD_CLASS_FROM_EXTENSION_MANIFEST,
+ "A configuration definition class could not be loaded " +
+ "from the extension manifest file %s in extensions %s because an " +
+ "unexpected error occurred while trying to initialize it: %s.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_FIND_CORE_MANIFEST,
+ "The core administration manifest file %s cannot be located.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_READ_CORE_MANIFEST,
+ "The core administration manifest file %s cannot be " +
+ "loaded because an unexpected error occurred while " +
+ "trying to read it: %s.");
+
+ registerMessage(MSGID_ADMIN_CANNOT_READ_EXTENSION_MANIFEST,
+ "The administration manifest file %s associated with the " +
+ "extension %s cannot be loaded because an unexpected error " +
+ "occurred while trying to read it: %s.");
+ }
+}
diff --git a/opends/src/server/org/opends/server/messages/MessageHandler.java b/opends/src/server/org/opends/server/messages/MessageHandler.java
index e21085e..b83ecd9 100644
--- a/opends/src/server/org/opends/server/messages/MessageHandler.java
+++ b/opends/src/server/org/opends/server/messages/MessageHandler.java
@@ -63,6 +63,7 @@
* <LI>00A -- Directory Server tools</LI>
* <LI>00B -- Task processing</LI>
<LI>00C -- Access Control</LI>
+ <LI>00D -- Administration framework</LI>
* <LI>800 through FFE -- Reserved for third-party modules</LI>
* <LI>FFF -- User-defined processing</LI>
* </UL>
@@ -186,6 +187,14 @@
/**
+ * The category bitmask used for messages associated with the
+ * administration framework.
+ */
+ public static final int CATEGORY_MASK_ADMIN = 0x00D00000;
+
+
+
+ /**
* The category bitmask that will be used for messages associated with
* third-party (including user-defined) modules.
*/
@@ -281,6 +290,7 @@
BackendMessages.registerMessages();
ToolMessages.registerMessages();
TaskMessages.registerMessages();
+ AdminMessages.registerMessages();
AciMessages.registerMessages();
}
diff --git a/opends/src/server/org/opends/server/messages/ProtocolMessages.java b/opends/src/server/org/opends/server/messages/ProtocolMessages.java
index 09c2150..cb18329 100644
--- a/opends/src/server/org/opends/server/messages/ProtocolMessages.java
+++ b/opends/src/server/org/opends/server/messages/ProtocolMessages.java
@@ -4331,7 +4331,7 @@
* arguments, which are the DN of the configuration entry and the provided key
* manager provider DN.
*/
- public static final int MSGID_JMX_CONNHANDLER_INVALID_KEY_MANAGER_DN =
+ public static final int MSGID_JMX_CONNHANDLER_INVALID_KEYMANAGER_DN =
CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_SEVERE_ERROR | 399;
@@ -6132,7 +6132,7 @@
"connections or performing StartTLS negotiation. " +
"Changes to this configuration attribute will take effect " +
"immediately.");
- registerMessage(MSGID_JMX_CONNHANDLER_INVALID_KEY_MANAGER_DN,
+ registerMessage(MSGID_JMX_CONNHANDLER_INVALID_KEYMANAGER_DN,
"An error occurred while processing the " + ATTR_KEYMANAGER_DN +
" attribute in configuration entry %s, because the provided " +
"key manager DN %s does not refer to an enabled key manager " +
diff --git a/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java b/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
index 5a8bc35..5b51bf0 100644
--- a/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
+++ b/opends/src/server/org/opends/server/monitors/ConnectionHandlerMonitor.java
@@ -73,7 +73,7 @@
private AttributeType protocolType;
// The connection handler with which this monitor is associated.
- private ConnectionHandler connectionHandler;
+ private ConnectionHandler<?> connectionHandler;
// The name for this monitor.
private String monitorName;
diff --git a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java b/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
index 095a0ad..861e7cf 100644
--- a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
@@ -36,11 +36,11 @@
import java.util.Set;
import java.util.UUID;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.LDIFPluginResult;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreOperationPluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -68,11 +68,8 @@
* will have identical entryUUID values.
*/
public final class EntryUUIDPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
-
-
-
/**
* The name of the entryUUID attribute type.
*/
@@ -96,7 +93,6 @@
super();
-
// Get the entryUUID attribute type. This needs to be done in the
// constructor in order to make the associated variables "final".
AttributeType at = DirectoryConfig.getAttributeType(ENTRYUUID,
@@ -126,7 +122,7 @@
*/
@Override()
public final void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// Make sure that the plugin has been enabled for the appropriate types.
diff --git a/opends/src/server/org/opends/server/plugins/LDAPADListPlugin.java b/opends/src/server/org/opends/server/plugins/LDAPADListPlugin.java
index fb6f307..15626f9 100644
--- a/opends/src/server/org/opends/server/plugins/LDAPADListPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/LDAPADListPlugin.java
@@ -30,10 +30,10 @@
import java.util.LinkedHashSet;
import java.util.Set;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreParsePluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DirectoryConfig;
@@ -57,11 +57,8 @@
* object class identifier from an attribute descriptions.
*/
public final class LDAPADListPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
-
-
-
/**
* Creates a new instance of this Directory Server plugin. Every plugin must
* implement a default constructor (it is the only one that will be used to
@@ -81,14 +78,14 @@
*/
@Override()
public final void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// The set of plugin types must contain only the pre-parse search element.
if (pluginTypes.isEmpty())
{
int msgID = MSGID_PLUGIN_ADLIST_NO_PLUGIN_TYPES;
- String message = getMessage(msgID, String.valueOf(configEntry.getDN()));
+ String message = getMessage(msgID, String.valueOf(configuration.dn()));
throw new ConfigException(msgID, message);
}
else
@@ -99,7 +96,7 @@
{
int msgID = MSGID_PLUGIN_ADLIST_INVALID_PLUGIN_TYPE;
String message = getMessage(msgID,
- String.valueOf(configEntry.getDN()),
+ String.valueOf(configuration.dn()),
String.valueOf(t));
throw new ConfigException(msgID, message);
}
diff --git a/opends/src/server/org/opends/server/plugins/LastModPlugin.java b/opends/src/server/org/opends/server/plugins/LastModPlugin.java
index aa1cec6..15dff1d 100644
--- a/opends/src/server/org/opends/server/plugins/LastModPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/LastModPlugin.java
@@ -32,10 +32,10 @@
import java.util.LinkedHashSet;
import java.util.Set;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreOperationPluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -67,11 +67,8 @@
* whenever the entry is modified or renamed.
*/
public final class LastModPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
-
-
-
// The attribute type for the "createTimestamp" attribute.
private final AttributeType createTimestampType;
@@ -118,7 +115,7 @@
*/
@Override()
public final void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// Make sure that the plugin has been enabled for the appropriate types.
diff --git a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java b/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
index e835696..c208f5f 100644
--- a/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/PasswordPolicyImportPlugin.java
@@ -36,11 +36,11 @@
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.PasswordStorageScheme;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.LDIFPluginResult;
import org.opends.server.api.plugin.PluginType;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PasswordPolicy;
@@ -71,11 +71,8 @@
* that all of the password values are properly encoded before they are stored.
*/
public final class PasswordPolicyImportPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
-
-
-
// The sets of password storage schemes for the auth password attributes.
private final HashMap<AttributeType,PasswordStorageScheme[]>
authPasswordSchemes;
@@ -97,7 +94,6 @@
super();
-
// Get the password policies from the Directory Server configuration. This
// is done in the constructor to allow the instance variables to be declared
// "final".
@@ -176,7 +172,7 @@
*/
@Override()
public final void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// Make sure that the plugin has been enabled for the appropriate types.
diff --git a/opends/src/server/org/opends/server/plugins/profiler/ProfilerPlugin.java b/opends/src/server/org/opends/server/plugins/profiler/ProfilerPlugin.java
index d39c478..1a248e4 100644
--- a/opends/src/server/org/opends/server/plugins/profiler/ProfilerPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/profiler/ProfilerPlugin.java
@@ -30,24 +30,15 @@
import java.io.File;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import org.opends.server.api.ConfigurableComponent;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.ProfilerPluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.StartupPluginResult;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.IntegerWithUnitConfigAttribute;
-import org.opends.server.config.MultiChoiceConfigAttribute;
-import org.opends.server.config.ReadOnlyConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DirectoryConfig;
import org.opends.server.types.DN;
@@ -56,14 +47,12 @@
import org.opends.server.types.ResultCode;
import org.opends.server.util.TimeThread;
-import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import org.opends.server.types.DebugLogLevel;
import static org.opends.server.loggers.Error.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.PluginMessages.*;
-import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -78,12 +67,9 @@
* time.
*/
public final class ProfilerPlugin
- extends DirectoryServerPlugin
- implements ConfigurableComponent
+ extends DirectoryServerPlugin<ProfilerPluginCfg>
+ implements ConfigurationChangeListener<ProfilerPluginCfg>
{
-
-
-
/**
* The value to use for the profiler action when no action is necessary.
*/
@@ -115,45 +101,15 @@
- /**
- * The set of time units that will be used for expressing the task retention
- * time.
- */
- private static final LinkedHashMap<String,Double> timeUnits =
- new LinkedHashMap<String,Double>();
-
-
-
- // Indicates whether the profiler should be started automatically when the
- // Directory Server is started.
- private boolean autoStart;
-
// The DN of the configuration entry for this plugin.
private DN configEntryDN;
- // The set of profiler actions that a client may request.
- private LinkedHashSet<String> profilerActions;
-
- // The sample interval to use when capturing stack traces.
- private long sampleInterval;
+ // The current configuration for this plugin.
+ private ProfilerPluginCfg currentConfig;
// The thread that is actually capturing the profile information.
private ProfilerThread profilerThread;
- // The path to the directory into which the captured information should be
- // written.
- private String profileDirectory;
-
-
-
- static
- {
- timeUnits.put(TIME_UNIT_MILLISECONDS_ABBR, 1D);
- timeUnits.put(TIME_UNIT_MILLISECONDS_FULL, 1D);
- timeUnits.put(TIME_UNIT_SECONDS_ABBR, 1000D);
- timeUnits.put(TIME_UNIT_SECONDS_FULL, 1000D);
- }
-
/**
@@ -175,19 +131,13 @@
*/
@Override()
public final void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ ProfilerPluginCfg configuration)
throws ConfigException
{
- // Initialize the set of profiler actions.
- profilerActions = new LinkedHashSet<String>(4);
- profilerActions.add(PROFILE_ACTION_NONE);
- profilerActions.add(PROFILE_ACTION_START);
- profilerActions.add(PROFILE_ACTION_STOP);
- profilerActions.add(PROFILE_ACTION_CANCEL);
+ configuration.addProfilerChangeListener(this);
-
- // Get and store the DN of the associated configuration entry.
- configEntryDN = configEntry.getDN();
+ currentConfig = configuration;
+ configEntryDN = configuration.dn();
// Make sure that this plugin is only registered as a startup plugin.
@@ -212,114 +162,15 @@
}
- // Get the name of the profile directory from the config entry. We may
- // override this value when reading the stop request, but if that attribute
- // is missing or we get a request to finalize while the profiler is still
- // active, then we will want to know it ahead of time. If there is no
- // value, then just use the current working directory.
- profileDirectory = System.getProperty("user.dir");
-
- int msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_PROFILE_DIR;
- StringConfigAttribute profileDirStub =
- new StringConfigAttribute(ATTR_PROFILE_DIR, getMessage(msgID), true,
- false, false);
- try
+ // Make sure that the profile directory exists.
+ File profileDirectory = getFileForPath(configuration.getProfileDirectory());
+ if (! (profileDirectory.exists() && profileDirectory.isDirectory()))
{
- StringConfigAttribute profileDirAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(profileDirStub);
- if (profileDirAttr != null)
- {
- profileDirectory =
- getFileForPath(profileDirAttr.activeValue()).getAbsolutePath();
- }
+ int msgID = MSGID_PLUGIN_PROFILER_INVALID_PROFILE_DIR;
+ String message = getMessage(msgID, profileDirectory.getAbsolutePath(),
+ String.valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
}
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_PROFILE_DIR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e),
- profileDirectory);
- logError(ErrorLogCategory.PLUGIN, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- }
-
-
- // Determine whether the plugin should start capturing data automatically
- // when the server is starting.
- autoStart = false;
-
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_AUTOSTART;
- BooleanConfigAttribute autoStartStub =
- new BooleanConfigAttribute(ATTR_PROFILE_AUTOSTART, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute autoStartAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(autoStartStub);
- if (autoStartAttr != null)
- {
- autoStart = autoStartAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_AUTOSTART;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- logError(ErrorLogCategory.PLUGIN, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- }
-
-
- // Determine the sample interval that should be used when capturing stack
- // traces.
- sampleInterval = DEFAULT_PROFILE_INTERVAL;
-
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_INTERVAL;
- IntegerWithUnitConfigAttribute intervalStub =
- new IntegerWithUnitConfigAttribute(ATTR_PROFILE_INTERVAL,
- getMessage(msgID), false, timeUnits,
- true, 1, false, 0);
- try
- {
- IntegerWithUnitConfigAttribute intervalAttr =
- (IntegerWithUnitConfigAttribute)
- configEntry.getConfigAttribute(intervalStub);
- if (intervalAttr != null)
- {
- sampleInterval = intervalAttr.activeCalculatedValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_INTERVAL;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e),
- sampleInterval);
- logError(ErrorLogCategory.PLUGIN, ErrorLogSeverity.SEVERE_WARNING,
- message, msgID);
- }
-
-
- // Register with the Directory Server as a configurable component.
- DirectoryConfig.registerConfigurableComponent(this);
}
@@ -330,6 +181,8 @@
@Override()
public final void finalizePlugin()
{
+ currentConfig.removeProfilerChangeListener(this);
+
// If the profiler thread is still active, then cause it to dump the
// information it has captured and exit.
synchronized (this)
@@ -338,8 +191,8 @@
{
profilerThread.stopProfiling();
- String filename = profileDirectory + File.separator + "profile." +
- TimeThread.getGMTTime();
+ String filename = currentConfig.getProfileDirectory() + File.separator +
+ "profile." + TimeThread.getGMTTime();
try
{
profilerThread.writeCaptureData(filename);
@@ -360,9 +213,6 @@
}
}
}
-
-
- DirectoryConfig.deregisterConfigurableComponent(this);
}
@@ -373,10 +223,12 @@
@Override()
public final StartupPluginResult doStartup()
{
+ ProfilerPluginCfg config = currentConfig;
+
// If the profiler should be started automatically, then do so now.
- if (autoStart)
+ if (config.isEnableProfilingOnStartup())
{
- profilerThread = new ProfilerThread(sampleInterval);
+ profilerThread = new ProfilerThread(config.getProfileSampleInterval());
profilerThread.start();
}
@@ -388,465 +240,143 @@
/**
* {@inheritDoc}
*/
- public final DN getConfigurableComponentEntryDN()
+ public boolean isConfigurationChangeAcceptable(
+ ProfilerPluginCfg configuration,
+ List<String> unacceptableReasons)
{
- return configEntryDN;
+ boolean configAcceptable = true;
+
+ // Make sure that the profile directory exists.
+ File profileDirectory = getFileForPath(configuration.getProfileDirectory());
+ if (! (profileDirectory.exists() && profileDirectory.isDirectory()))
+ {
+ int msgID = MSGID_PLUGIN_PROFILER_INVALID_PROFILE_DIR;
+ unacceptableReasons.add(getMessage(msgID,
+ profileDirectory.getAbsolutePath(),
+ String.valueOf(configEntryDN)));
+ configAcceptable = false;
+ }
+
+ return configAcceptable;
}
/**
- * {@inheritDoc}
+ * Applies the configuration changes to this change listener.
+ *
+ * @param configuration
+ * The new configuration containing the changes.
+ * @return Returns information about the result of changing the
+ * configuration.
*/
- public final List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
-
-
- int msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_INTERVAL;
- IntegerWithUnitConfigAttribute intervalAttr =
- new IntegerWithUnitConfigAttribute(ATTR_PROFILE_INTERVAL,
- getMessage(msgID), false, timeUnits,
- true, 1, false, 0, sampleInterval,
- TIME_UNIT_MILLISECONDS_FULL);
- attrList.add(intervalAttr);
-
-
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_PROFILE_DIR;
- StringConfigAttribute profileDirAttr =
- new StringConfigAttribute(ATTR_PROFILE_DIR, getMessage(msgID), true,
- false, false, profileDirectory);
- attrList.add(profileDirAttr);
-
-
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_AUTOSTART;
- BooleanConfigAttribute autoStartAttr =
- new BooleanConfigAttribute(ATTR_PROFILE_AUTOSTART, getMessage(msgID),
- false, autoStart);
- attrList.add(autoStartAttr);
-
-
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_STATE;
- String stateStr = (profilerThread == null) ? "disabled" : "enabled";
- ReadOnlyConfigAttribute stateAttr =
- new ReadOnlyConfigAttribute(ATTR_PROFILE_STATE, getMessage(msgID),
- stateStr);
- attrList.add(stateAttr);
-
-
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_ACTION;
- MultiChoiceConfigAttribute actionAttr =
- new MultiChoiceConfigAttribute(ATTR_PROFILE_ACTION, getMessage(msgID),
- true, false, false, profilerActions,
- PROFILE_ACTION_NONE);
- attrList.add(actionAttr);
-
-
- return attrList;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public final boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- // See if there is an acceptable value for the sample interval.
- int msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_INTERVAL;
- IntegerWithUnitConfigAttribute intervalStub =
- new IntegerWithUnitConfigAttribute(ATTR_PROFILE_INTERVAL,
- getMessage(msgID), false, timeUnits,
- true, 1, false, 0);
- try
- {
- IntegerWithUnitConfigAttribute intervalAttr =
- (IntegerWithUnitConfigAttribute)
- configEntry.getConfigAttribute(intervalStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_INTERVAL;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e),
- sampleInterval));
- return false;
- }
-
-
- // See if there is an acceptable value for the profiler directory.
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_PROFILE_DIR;
- StringConfigAttribute profileDirStub =
- new StringConfigAttribute(ATTR_PROFILE_DIR, getMessage(msgID), true,
- false, false);
- try
- {
- StringConfigAttribute profileDirAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(profileDirStub);
- if (profileDirAttr != null)
- {
- File dirFile = getFileForPath(profileDirAttr.activeValue());
- if (! (dirFile.exists() && dirFile.isDirectory()))
- {
- msgID = MSGID_PLUGIN_PROFILER_INVALID_PROFILE_DIR;
- unacceptableReasons.add(getMessage(msgID,
- profileDirAttr.activeValue(),
- String.valueOf(configEntryDN)));
- return false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_PROFILE_DIR;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e),
- sampleInterval));
- return false;
- }
-
-
- // See if there is an acceptable value for the autostart flag.
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_AUTOSTART;
- BooleanConfigAttribute autoStartStub =
- new BooleanConfigAttribute(ATTR_PROFILE_AUTOSTART, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute autoStartAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(autoStartStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_AUTOSTART;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // See if there is an acceptable value for the profiler action.
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_ACTION;
- MultiChoiceConfigAttribute actionStub =
- new MultiChoiceConfigAttribute(ATTR_PROFILE_ACTION, getMessage(msgID),
- false, false, false, profilerActions);
- try
- {
- MultiChoiceConfigAttribute actionAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(actionStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_DETERMINE_ACTION;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- return false;
- }
-
-
- // If we've gotten here, then everything looks OK.
- return true;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public final ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
+ public ConfigChangeResult applyConfigurationChange(
+ ProfilerPluginCfg configuration)
{
ResultCode resultCode = ResultCode.SUCCESS;
boolean adminActionRequired = false;
ArrayList<String> messages = new ArrayList<String>();
+ currentConfig = configuration;
- // Check to see if the sample interval needs to change and apply it as
- // necessary.
- int msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_INTERVAL;
- IntegerWithUnitConfigAttribute intervalStub =
- new IntegerWithUnitConfigAttribute(ATTR_PROFILE_INTERVAL,
- getMessage(msgID), false, timeUnits,
- true, 1, false, 0);
- try
+ // See if we need to perform any action.
+ switch (configuration.getProfileAction())
{
- IntegerWithUnitConfigAttribute intervalAttr =
- (IntegerWithUnitConfigAttribute)
- configEntry.getConfigAttribute(intervalStub);
- if (intervalAttr != null)
- {
- long newInterval = intervalAttr.pendingCalculatedValue();
- if (newInterval != sampleInterval)
+ case START:
+ // See if the profiler thread is running. If so, then don't do
+ // anything. Otherwise, start it.
+ synchronized (this)
{
- sampleInterval = newInterval;
-
- if (detailedResults)
+ if (profilerThread == null)
{
- msgID = MSGID_PLUGIN_PROFILER_UPDATED_INTERVAL;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- sampleInterval));
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
+ profilerThread =
+ new ProfilerThread(configuration.getProfileSampleInterval());
+ profilerThread.start();
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_UPDATE_INTERVAL;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryConfig.getServerErrorResultCode();
- }
-
-
-
- // Check to see if the profile directory needs to change.
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_PROFILE_DIR;
- StringConfigAttribute profileDirStub =
- new StringConfigAttribute(ATTR_PROFILE_DIR, getMessage(msgID), true,
- false, false);
- try
- {
- StringConfigAttribute profileDirAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(profileDirStub);
- if (profileDirAttr != null)
- {
- String dirString = profileDirAttr.pendingValue();
- if (! dirString.equals(profileDirectory))
- {
- File dirFile = getFileForPath(dirString);
- if (! (dirFile.exists() && dirFile.isDirectory()))
- {
- msgID = MSGID_PLUGIN_PROFILER_INVALID_PROFILE_DIR;
- messages.add(getMessage(msgID, dirString,
- String.valueOf(configEntryDN)));
-
- resultCode = DirectoryConfig.getServerErrorResultCode();
+ int msgID = MSGID_PLUGIN_PROFILER_STARTED_PROFILING;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
}
else
{
- profileDirectory = dirFile.getAbsolutePath();
+ int msgID = MSGID_PLUGIN_PROFILER_ALREADY_PROFILING;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+ }
+ }
+ break;
- if (detailedResults)
+ case STOP:
+ // See if the profiler thread is running. If so, then stop it and write
+ // the information captured to disk. Otherwise, don't do anything.
+ synchronized (this)
+ {
+ if (profilerThread == null)
+ {
+ int msgID = MSGID_PLUGIN_PROFILER_NOT_RUNNING;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+ }
+ else
+ {
+ profilerThread.stopProfiling();
+
+ int msgID = MSGID_PLUGIN_PROFILER_STOPPED_PROFILING;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+
+ String filename =
+ getFileForPath(
+ configuration.getProfileDirectory()).getAbsolutePath() +
+ File.separator + "profile." + TimeThread.getGMTTime();
+
+ try
{
- msgID = MSGID_PLUGIN_PROFILER_UPDATED_DIRECTORY;
+ profilerThread.writeCaptureData(filename);
+
+ msgID = MSGID_PLUGIN_PROFILER_WROTE_PROFILE_DATA;
messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- profileDirectory));
+ filename));
}
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ msgID = MSGID_PLUGIN_PROFILER_CANNOT_WRITE_PROFILE_DATA;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN),
+ filename,
+ stackTraceToSingleLineString(e)));
+
+ resultCode = DirectoryConfig.getServerErrorResultCode();
+ }
+
+ profilerThread = null;
}
}
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
+ break;
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_UPDATE_DIRECTORY;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- resultCode = DirectoryConfig.getServerErrorResultCode();
- }
-
-
- // Check to see if we need to invoke some profiler action. We will only
- // try to take action if we haven't seen any problems with other parameters.
- msgID = MSGID_PLUGIN_PROFILER_DESCRIPTION_ACTION;
- MultiChoiceConfigAttribute actionStub =
- new MultiChoiceConfigAttribute(ATTR_PROFILE_ACTION, getMessage(msgID),
- false, false, false, profilerActions);
- try
- {
- MultiChoiceConfigAttribute actionAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(actionStub);
-
- if (actionAttr != null)
- {
- if (resultCode == ResultCode.SUCCESS)
+ case CANCEL:
+ // See if the profiler thread is running. If so, then stop it but don't
+ // write anything to disk. Otherwise, don't do anything.
+ synchronized (this)
{
- String action = actionAttr.pendingValue().toLowerCase();
- if (action.equals(PROFILE_ACTION_NONE))
+ if (profilerThread == null)
{
- // We don't need to do anything at all.
- }
- else if (action.equals(PROFILE_ACTION_START))
- {
- // See if the profiler thread is running. If so, then don't do
- // anything. Otherwise, start it.
- synchronized (this)
- {
- if (profilerThread == null)
- {
- profilerThread = new ProfilerThread(sampleInterval);
- profilerThread.start();
-
- if (detailedResults)
- {
- msgID = MSGID_PLUGIN_PROFILER_STARTED_PROFILING;
- messages.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
- }
- else
- {
- msgID = MSGID_PLUGIN_PROFILER_ALREADY_PROFILING;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- }
- }
- else if (action.equals(PROFILE_ACTION_STOP))
- {
- // See if the profiler thread is running. If so, then stop it and
- // write the information captured to disk. Otherwise, don't do
- // anything.
- synchronized (this)
- {
- if (profilerThread == null)
- {
- msgID = MSGID_PLUGIN_PROFILER_NOT_RUNNING;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- else
- {
- profilerThread.stopProfiling();
-
- if (detailedResults)
- {
- msgID = MSGID_PLUGIN_PROFILER_STOPPED_PROFILING;
- messages.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
-
- String filename = profileDirectory + File.separator +
- "profile." + TimeThread.getGMTTime();
-
- try
- {
- profilerThread.writeCaptureData(filename);
-
- if (detailedResults)
- {
- msgID = MSGID_PLUGIN_PROFILER_WROTE_PROFILE_DATA;
- messages.add(getMessage(msgID,
- String.valueOf(configEntryDN),
- filename));
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_WRITE_PROFILE_DATA;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- filename,
- stackTraceToSingleLineString(e)));
-
- resultCode = DirectoryConfig.getServerErrorResultCode();
- }
-
- profilerThread = null;
- }
- }
- }
- else if (action.equals(PROFILE_ACTION_CANCEL))
- {
- // See if the profiler thread is running. If so, then stop it but
- // don't write anything to disk. Otherwise, don't do anything.
- synchronized (this)
- {
- if (profilerThread == null)
- {
- msgID = MSGID_PLUGIN_PROFILER_NOT_RUNNING;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
- }
- else
- {
- profilerThread.stopProfiling();
-
- if (detailedResults)
- {
- msgID = MSGID_PLUGIN_PROFILER_STOPPED_PROFILING;
- messages.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- }
-
- profilerThread = null;
- }
- }
+ int msgID = MSGID_PLUGIN_PROFILER_NOT_RUNNING;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
}
else
{
- // This was an unrecognized action. We won't do anything.
- msgID = MSGID_PLUGIN_PROFILER_UNKNOWN_ACTION;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- action));
+ profilerThread.stopProfiling();
- resultCode = DirectoryConfig.getServerErrorResultCode();
+ int msgID = MSGID_PLUGIN_PROFILER_STOPPED_PROFILING;
+ messages.add(getMessage(msgID, String.valueOf(configEntryDN)));
+
+ profilerThread = null;
}
}
- else
- {
- msgID = MSGID_PLUGIN_PROFILER_SKIPPING_ACTION;
- messages.add(getMessage(msgID, actionAttr.pendingValue(),
- String.valueOf(configEntryDN)));
- }
-
- configEntry.removeConfigAttribute(ATTR_PROFILE_ACTION.toLowerCase());
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_PLUGIN_PROFILER_CANNOT_PERFORM_ACTION;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
-
- resultCode = DirectoryConfig.getServerErrorResultCode();
+ break;
}
-
- // Return the result of the processing.
return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
}
-
diff --git a/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java b/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java
index 03b89a1..7ad0b55 100644
--- a/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/internal/InternalConnectionHandler.java
@@ -31,6 +31,7 @@
import java.util.Collection;
import java.util.LinkedList;
+import org.opends.server.admin.std.server.*;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.config.ConfigEntry;
@@ -227,5 +228,17 @@
{
buffer.append("Internal Connection Handler");
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initializeConnectionHandler(
+ ConnectionHandlerCfg configuration)
+ throws ConfigException, InitializationException {
+ // No implementation required.
+ }
}
diff --git a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java b/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
index 1784efb..03b4522 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -121,7 +121,7 @@
nextOperationID = new AtomicLong(0);
this.jmxConnectionHandler = jmxConnectionHandler;
- jmxConnectionHandler.connectionList.add(this) ;
+ jmxConnectionHandler.registerClientConnection(this);
setAuthenticationInfo(authInfo);
@@ -152,7 +152,7 @@
//
// Register the Jmx Notification listener (this)
- jmxConnectionHandler.rmiConnector.jmxRmiConnectorNoClientCertificate
+ jmxConnectionHandler.getRMIConnector().jmxRmiConnectorNoClientCertificate
.addNotificationListener(this, null, null);
}
diff --git a/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java b/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
index 48f42b3..1e55145 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/jmx/JmxConnectionHandler.java
@@ -26,15 +26,11 @@
*/
package org.opends.server.protocols.jmx;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
+
+
import static org.opends.server.loggers.Error.logError;
-import static org.opends.server.messages.ConfigMessages.*;
-import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.messages.ProtocolMessages.*;
-import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import java.util.ArrayList;
import java.util.Collection;
@@ -42,18 +38,14 @@
import java.util.LinkedList;
import java.util.List;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.JMXConnectionHandlerCfg;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.api.KeyManagerProvider;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
+import org.opends.server.api.ServerShutdownListener;
import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.IntegerConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
@@ -63,291 +55,169 @@
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
+
+
/**
* This class defines a connection handler that will be used for
* communicating with administrative clients over JMX. The connection
- * handler is responsible for accepting new connections, reading requests
- * from the clients and parsing them as operations. A single request
- * handler should be used.
+ * handler is responsible for accepting new connections, reading
+ * requests from the clients and parsing them as operations. A single
+ * request handler should be used.
*/
-public class JmxConnectionHandler
- extends ConnectionHandler implements ConfigurableComponent, AlertGenerator
-{
- /**
- * The fully-qualified name of this class.
- */
- private static final String CLASS_NAME =
- "org.opends.server.protocols.jmx.JMXConnectionHandler";
-
- /**
- * The DN of the configuration entry for this connection handler.
- */
- private DN configEntryDN;
-
- /**
- * Indicates whether this connection handler is enabled.
- */
- protected boolean enabled;
-
- /**
- * The attribute which whether this connection handler is enabled.
- */
- BooleanConfigAttribute enabledAtt;
-
- /**
- * Indicates whether to use SSL to communicate with the clients.
- */
- protected boolean useSSL;
-
- /**
- * The attribute which indicates whether to use SSL to communicate with
- * the clients.
- */
- BooleanConfigAttribute useSslAtt;
-
- /**
- * The nickname of the SSL certificate that should be used if SSL is
- * enabled.
- */
- protected String sslServerCertNickname;
-
- /**
- * The attribute which represents the nickname of the SSL certificate
- * that should be used if SSL is enabled.
- */
- StringConfigAttribute sslServerCertNickNameAtt;
-
- /**
- * The unique name assigned to this connection handler.
- */
- private String handlerName;
-
- /**
- * The JMX RMI Connector associated with the Connection handler.
- */
- protected RmiConnector rmiConnector;
-
- /**
- * The port on which this connection handler should listen for
- * requests.
- */
- protected int listenPort;
-
- /**
- * The attibute which represents the port on which this connection
- * handler should listen for requests.
- */
- private IntegerConfigAttribute listenPortAtt;
-
- /**
- * The DN of the key manager provider to use with this connection handler.
- */
- protected DN keyManagerProviderDN;
-
- /**
- * The key manager provider for this connection handler.
- */
- protected KeyManagerProvider keyManagerProvider;
-
- /**
- * The attribute which represents the DN of the key manager provider for this
- * connection handler.
- */
- private DNConfigAttribute keyManagerDNAtt;
+public final class JmxConnectionHandler extends
+ ConnectionHandler<JMXConnectionHandlerCfg> implements
+ ServerShutdownListener, AlertGenerator,
+ ConfigurationChangeListener<JMXConnectionHandlerCfg> {
/**
* Key that may be placed into a JMX connection environment map to
- * provide a custom <code>javax.net.ssl.TrustManager</code> array for
- * a connection.
+ * provide a custom <code>javax.net.ssl.TrustManager</code> array
+ * for a connection.
*/
public static final String TRUST_MANAGER_ARRAY_KEY =
"org.opends.server.protocol.jmx.ssl.trust.manager.array";
- /**
- * Configuration attributes that are associated
- * with this configurable component.
- *
- */
- private LinkedList<ConfigAttribute> configAttrs =
- new LinkedList<ConfigAttribute>();
+ // The fully-qualified name of this class.
+ private static final String CLASS_NAME =
+ "org.opends.server.protocols.jmx.JMXConnectionHandler";
- /**
- * The unique name for this connection handler.
- */
- protected String connectionHandlerName;
+ // The list of active client connection.
+ private LinkedList<ClientConnection> connectionList;
- /**
- * The protocol used to communicate with clients.
- */
- protected String protocol;
+ // The current configuration state.
+ private JMXConnectionHandlerCfg currentConfig;
- /**
- * The set of listeners for this connection handler.
- */
- protected LinkedList<HostPort> listeners = new LinkedList<HostPort>();
+ // The JMX RMI Connector associated with the Connection handler.
+ private RmiConnector rmiConnector;
- /**
- * The list of active client connection.
- */
- protected LinkedList<ClientConnection> connectionList =
- new LinkedList<ClientConnection>();
+ // The unique name for this connection handler.
+ private String connectionHandlerName;
+
+ // The protocol used to communicate with clients.
+ private String protocol;
+
+ // The set of listeners for this connection handler.
+ private LinkedList<HostPort> listeners = new LinkedList<HostPort>();
/**
* Creates a new instance of this JMX connection handler. It must be
* initialized before it may be used.
*/
- public JmxConnectionHandler()
- {
+ public JmxConnectionHandler() {
super("JMX Connection Handler Thread");
-
- // No real implementation is required. Do all the work in the
- // initializeConnectionHandler method.
+ this.connectionList = new LinkedList<ClientConnection>();
}
+
+
/**
- * Initializes this connection handler based on the information in the
- * provided configuration entry.
- *
- * @param configEntry
- * The configuration entry that contains the information to
- * use to initialize this connection handler.
- * @throws ConfigException
- * If there is a problem with the configuration for this
- * connection handler.
- * @throws InitializationException
- * If a problem occurs while attempting to initialize this
- * connection handler.
+ * {@inheritDoc}
*/
- public void initializeConnectionHandler(ConfigEntry configEntry)
- throws ConfigException, InitializationException
- {
- //
- // If the initializeConnectionHandler method is called,
- // it means that the "enabled" attribure was true.
- enabledAtt = getEnabledAtt(configEntry);
- configAttrs.add(enabledAtt);
- enabled = enabledAtt.activeValue();
+ public ConfigChangeResult applyConfigurationChange(
+ JMXConnectionHandlerCfg config) {
+ // Create variables to include in the response.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ ArrayList<String> messages = new ArrayList<String>();
- //
- // Set the entry DN
- configEntryDN = configEntry.getDN();
+ // Determine whether or not the RMI connection needs restarting.
+ boolean rmiConnectorRestart = false;
+ boolean portChanged = false;
- //
- // Determine the port on which to listen. There should be a single
- // port specified.
- listenPortAtt = getListenPort(configEntry);
- configAttrs.add(listenPortAtt);
- listenPort = listenPortAtt.activeIntValue();
-
- //
- // Determine whether to use SSL.
- useSslAtt = getUseSSL(configEntry);
- configAttrs.add(useSslAtt);
- useSSL = useSslAtt.activeValue();
-
- //
- // Determine which SSL certificate to use.
- sslServerCertNickNameAtt = getServerCertNickname(configEntry);
- configAttrs.add(sslServerCertNickNameAtt);
- sslServerCertNickname = sslServerCertNickNameAtt.activeValue();
-
- //
- // Determine which key manager provider to use.
- keyManagerDNAtt = getKeyManagerDN(configEntry);
- configAttrs.add(keyManagerDNAtt);
- if (keyManagerDNAtt == null)
- {
- keyManagerProviderDN = null;
- }
- else
- {
- keyManagerProviderDN = keyManagerDNAtt.activeValue();
- keyManagerProvider =
- DirectoryServer.getKeyManagerProvider(keyManagerProviderDN);
+ if (currentConfig.getListenPort() != config.getListenPort()) {
+ rmiConnectorRestart = true;
+ portChanged = true;
}
- // Create the associated RMI Connector
- rmiConnector = new RmiConnector(DirectoryServer.getJMXMBeanServer(), this);
-
- //
- // Register this JMX ConnectionHandler as an MBean
- DirectoryServer.registerConfigurableComponent(this);
-
- //
- // Check if we have a correct SSL configuration
- if ((useSSL && keyManagerProvider == null))
- {
-
- //
- // TODO : give a more useful feedback message
- logError(
- ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_WARNING,
- MSGID_CONFIG_KEYMANAGER_NO_ENABLED_ATTR);
- int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
- String message = getMessage(msgID, String.valueOf(configEntryDN), "");
- throw new InitializationException(msgID, message);
+ if (currentConfig.isUseSSL() != config.isUseSSL()) {
+ rmiConnectorRestart = true;
}
- if (useSSL)
- {
- protocol = "JMX+SSL";
- }
- else
- {
- protocol = "JMX";
+ if (!currentConfig.getSSLCertNickname().equals(
+ config.getSSLCertNickname())) {
+ rmiConnectorRestart = true;
}
- listeners.clear();
- listeners.add(new HostPort("0.0.0.0", listenPort));
- connectionHandlerName = "JMX Connection Handler "+ listenPort;
+ // Save the configuration.
+ currentConfig = config;
+
+ // Restart the connector if required.
+ if (rmiConnectorRestart) {
+ if (config.isUseSSL()) {
+ protocol = "JMX+SSL";
+ } else {
+ protocol = "JMX";
+ }
+
+ listeners.clear();
+ listeners.add(new HostPort(config.getListenPort()));
+
+ rmiConnector.finalizeConnectionHandler(true, portChanged);
+ rmiConnector.initialize();
+ }
+
+ // Return configuration result.
+ return new ConfigChangeResult(resultCode, false, messages);
}
+
+
/**
- * Closes this connection handler so that it will no longer accept new
- * client connections. It may or may not disconnect existing client
- * connections based on the provided flag.
+ * Closes this connection handler so that it will no longer accept
+ * new client connections. It may or may not disconnect existing
+ * client connections based on the provided flag.
*
* @param finalizeReason
- * The reason that this connection handler should be
- * finalized.
+ * The reason that this connection handler should be
+ * finalized.
* @param closeConnections
- * Indicates whether any established client connections
- * associated with the connection handler should also be
- * closed.
+ * Indicates whether any established client connections
+ * associated with the connection handler should also be
+ * closed.
*/
- public void finalizeConnectionHandler(
- String finalizeReason, boolean closeConnections)
- {
+ public void finalizeConnectionHandler(String finalizeReason,
+ boolean closeConnections) {
+ // Make sure that we don't get notified of any more changes.
+ currentConfig.removeJMXChangeListener(this);
+
// We should also close the RMI registry.
rmiConnector.finalizeConnectionHandler(closeConnections, true);
}
- /**
- * {@inheritDoc}
- */
- public String getConnectionHandlerName()
- {
- return connectionHandlerName;
- }
+
/**
- * {@inheritDoc}
+ * Retrieves information about the set of alerts that this generator
+ * may produce. The map returned should be between the notification
+ * type for a particular notification and the human-readable
+ * description for that notification. This alert generator must not
+ * generate any alerts with types that are not contained in this
+ * list.
+ *
+ * @return Information about the set of alerts that this generator
+ * may produce.
*/
- public String getProtocol()
- {
- return protocol;
+ public LinkedHashMap<String, String> getAlerts() {
+ LinkedHashMap<String, String> alerts = new LinkedHashMap<String, String>();
+
+ return alerts;
}
+
+
/**
- * {@inheritDoc}
+ * Retrieves the fully-qualified name of the Java class for this
+ * alert generator implementation.
+ *
+ * @return The fully-qualified name of the Java class for this alert
+ * generator implementation.
*/
- public Collection<HostPort> getListeners()
- {
- return listeners;
+ public String getClassName() {
+ return CLASS_NAME;
}
+
+
/**
* Retrieves the set of active client connections that have been
* established through this connection handler.
@@ -355,465 +225,11 @@
* @return The set of active client connections that have been
* established through this connection handler.
*/
- public Collection<ClientConnection> getClientConnections()
- {
+ public Collection<ClientConnection> getClientConnections() {
return connectionList;
}
- /**
- * Start the JMX RMI Connector.
- */
- public void run()
- {
- rmiConnector.initialize();
- }
- /**
- * Retrieves the human-readable name for this shutdown listener.
- *
- * @return The human-readable name for this shutdown listener.
- */
- public String getShutdownListenerName()
- {
- return handlerName;
- }
-
- /**
- * Indicates that the Directory Server has received a request to stop
- * running and that this shutdown listener should take any action
- * necessary to prepare for it.
- *
- * @param reason
- * The human-readable reason for the shutdown.
- */
- public void processServerShutdown(String reason)
- {
- // We should also close the RMI registry.
- rmiConnector.finalizeConnectionHandler(true, true);
-
- }
-
- /**
- * Retrieves the DN of the configuration entry with which this
- * component is associated.
- *
- * @return The DN of the configuration entry with which this component
- * is associated.
- */
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
- /**
- * Retrieves the set of configuration attributes that are associated
- * with this configurable component.
- *
- * @return The set of configuration attributes that are associated with
- * this configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- return configAttrs;
-
- }
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided
- * list.
- *
- * @param configEntry
- * The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons
- * A list that can be used to hold messages about why the
- * provided entry does not have an acceptable configuration.
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if
- * not.
- */
- public boolean hasAcceptableConfiguration(
- ConfigEntry configEntry, List<String> unacceptableReasons)
- {
- boolean configValid = true;
-
- //
- // Determine the port on which to listen.
- try
- {
- getListenPort(configEntry);
- }
- catch (Exception e)
- {
- int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
- unacceptableReasons.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
- //
- // Determine the DN of the key manager provider.
- DN newKeyManagerProviderDN = null;
- KeyManagerProvider newKeyManagerProvider = null;
- try
- {
- DNConfigAttribute attr = getKeyManagerDN(configEntry);
- if (attr == null)
- {
- newKeyManagerProviderDN = null;
- }
- else
- {
- newKeyManagerProviderDN = attr.pendingValue();
- newKeyManagerProvider =
- DirectoryServer.getKeyManagerProvider(newKeyManagerProviderDN);
- }
- }
- catch (Exception e)
- {
- int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN;
- unacceptableReasons.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
- //
- // Determine whether to use SSL.
- try
- {
- boolean newUseSSL = getUseSSL(configEntry).activeValue();
- if (newUseSSL && (newKeyManagerProvider == null))
- {
- //
- // TODO Set an appropriate message (instead of null)
- int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
- unacceptableReasons.add(getMessage(msgID, String
- .valueOf(configEntryDN), null));
- configValid = false;
- }
- }
- catch (Exception e)
- {
- int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
- unacceptableReasons.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
- //
- // Determine which SSL certificate to use.
- try
- {
- getServerCertNickname(configEntry);
- }
- catch (Exception e)
- {
- configValid = false;
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
- unacceptableReasons.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
- //
- // return part
- return configValid;
- }
-
- /**
- * Makes a best-effort attempt to apply the configuration contained in
- * the provided entry. Information about the result of this processing
- * should be added to the provided message list. Information should
- * always be added to this list if a configuration change could not be
- * applied. If detailed results are requested, then information about
- * the changes applied successfully (and optionally about parameters
- * that were not changed) should also be included.
- *
- * @param configEntry
- * The entry containing the new configuration to apply for
- * this component.
- * @param detailedResults
- * Indicates whether detailed information about the
- * processing should be added to the list.
- * @return Information about the result of the configuration update.
- */
- public ConfigChangeResult applyNewConfiguration(
- ConfigEntry configEntry, boolean detailedResults)
- {
- //
- // Create variables to include in the response.
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean rmiConnectorRestart = false;
- ArrayList<String> messages = new ArrayList<String>();
-
- //
- // Determine the port on which to listen.
- int newListenPort = listenPort;
- try
- {
- if ((newListenPort = getListenPort(configEntry).activeIntValue())
- != listenPort)
- {
- rmiConnectorRestart = true;
- }
- }
- catch (Exception e)
- {
- int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
- messages.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- //
- // Determine whether to use SSL.
- boolean newUseSSL = useSSL;
- try
- {
- if ((newUseSSL = getUseSSL(configEntry).activeValue()) != useSSL)
- {
- rmiConnectorRestart = true;
- }
- }
- catch (Exception e)
- {
- int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
- messages.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- //
- // Determine which SSL certificate to use.
- String newSslServerCertNickname = sslServerCertNickname;
- try
- {
- if ((newSslServerCertNickname = getServerCertNickname(configEntry)
- .activeValue()) != sslServerCertNickname)
- {
- rmiConnectorRestart = true;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
- messages.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- //
- // Determine which key manager provider to use.
- DN newKeyManagerProviderDN = keyManagerProviderDN;
- KeyManagerProvider newKeyManagerProvider = keyManagerProvider;
- try
- {
- DNConfigAttribute attr = getKeyManagerDN(configEntry);
- if (attr == null)
- {
- newKeyManagerProviderDN = null;
- newKeyManagerProvider = null;
- if (keyManagerProviderDN != null)
- {
- rmiConnectorRestart = true;
- }
- }
- else
- {
- newKeyManagerProviderDN = attr.pendingValue();
- newKeyManagerProvider =
- DirectoryServer.getKeyManagerProvider(newKeyManagerProviderDN);
- if (newUseSSL && (newKeyManagerProvider == null))
- {
- int msgID = MSGID_JMX_CONNHANDLER_INVALID_KEY_MANAGER_DN;
- messages.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- String.valueOf(newKeyManagerProviderDN)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- else
- {
- if (! newKeyManagerProviderDN.equals(keyManagerProviderDN))
- {
- rmiConnectorRestart = true;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN;
- messages.add(getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- //
- // Apply new config, best effort mode
- if (rmiConnectorRestart)
- {
- applyNewConfiguration(
- newListenPort,
- newUseSSL,
- newSslServerCertNickname,
- newKeyManagerProviderDN,
- newKeyManagerProvider);
- }
-
- //
- // return part
- return new ConfigChangeResult(resultCode, false, messages);
- }
-
- /**
- * Apply the configuration.
- *
- * @param newListenPort
- * the new listen port
- * @param newUseSSL
- * Indicates if we should use ssl
- * @param newSslServerCertNickname
- * Indicates the new server certificate nickname
- * @param newKeyManagerProviderDN
- * The new key manager provider DN.
- * @param newKeyManagerProvider
- * The new key manager provider instance.
- */
- private void applyNewConfiguration(
- int newListenPort, boolean newUseSSL, String newSslServerCertNickname,
- DN newKeyManagerProviderDN, KeyManagerProvider newKeyManagerProvider)
- {
- //
- // Stop the current connector
- // TODO Set Msg
- this.rmiConnector.finalizeConnectionHandler(true,
- (listenPort != newListenPort));
-
- //
- // set new params and update JMX attributes
- if (listenPort != newListenPort)
- {
- try
- {
- listenPortAtt.setValue(newListenPort);
- listenPort = newListenPort;
- }
- catch (Exception e)
- {
- // TODO
- // Print error message
- }
- }
- if (useSSL != newUseSSL)
- {
- useSSL = newUseSSL;
- useSslAtt.setValue(newUseSSL);
- }
- if (sslServerCertNickname != newSslServerCertNickname)
- {
- try
- {
- sslServerCertNickNameAtt.setValue(newSslServerCertNickname);
- sslServerCertNickname = newSslServerCertNickname;
- }
- catch (Exception e)
- {
- // TODO
- // Print error message
- }
- }
-
- if (keyManagerProviderDN == null)
- {
- if (newKeyManagerProviderDN != null)
- {
- try
- {
- keyManagerProviderDN = newKeyManagerProviderDN;
- keyManagerProvider = newKeyManagerProvider;
- keyManagerDNAtt.setValue(newKeyManagerProviderDN);
- }
- catch (Exception e)
- {
- // TODO
- // Print error message
- }
- }
- }
- else if ((newKeyManagerProviderDN == null) ||
- (! newKeyManagerProviderDN.equals(keyManagerProviderDN)))
- {
- try
- {
- keyManagerProviderDN = newKeyManagerProviderDN;
- keyManagerProvider = newKeyManagerProvider;
- keyManagerDNAtt.setValue(newKeyManagerProviderDN);
- }
- catch (Exception e)
- {
- // TODO
- // Print error message
- }
- }
-
- if (useSSL)
- {
- protocol = "JMX+SSL";
- }
- else
- {
- protocol = "JMX";
- }
-
- listeners.clear();
- listeners.add(new HostPort(listenPort));
-
- //
- // Start the new RMI Connector
- rmiConnector.initialize();
- }
-
- /**
- * Appends a string representation of this connection handler to the
- * provided buffer.
- *
- * @param buffer
- * The buffer to which the information should be appended.
- */
- public void toString(StringBuilder buffer)
- {
- buffer.append(handlerName);
- }
/**
* Retrieves the DN of the configuration entry with which this alert
@@ -822,291 +238,237 @@
* @return The DN of the configuration entry with which this alert
* generator is associated.
*/
- public DN getComponentEntryDN()
- {
- return configEntryDN;
+ public DN getComponentEntryDN() {
+ return currentConfig.dn();
}
- /**
- * Retrieves the fully-qualified name of the Java class for this alert
- * generator implementation.
- *
- * @return The fully-qualified name of the Java class for this alert
- * generator implementation.
- */
- public String getClassName()
- {
- return CLASS_NAME;
- }
+
/**
- * Retrieves information about the set of alerts that this generator
- * may produce. The map returned should be between the notification
- * type for a particular notification and the human-readable
- * description for that notification. This alert generator must not
- * generate any alerts with types that are not contained in this list.
+ * Retrieves the DN of the key manager provider that should be used
+ * for operations associated with this connection handler which need
+ * access to a key manager.
*
- * @return Information about the set of alerts that this generator may
- * produce.
- */
- public LinkedHashMap<String, String> getAlerts()
- {
- LinkedHashMap<String, String> alerts = new LinkedHashMap<String, String>();
-
- return alerts;
- }
-
- /**
- * Retrieves the enabled attribure from the configuration entry with
- * which this component is associated.
- *
- * @param configEntry
- * The configuration entry for which to make the determination.
- * @return The enabled attribute
- * @throws ConfigException
- * If there is a problem with the configuration for this
- * connection handler.
- * @throws InitializationException
- * If a problem occurs while attempting to initialize this
+ * @return The DN of the key manager provider that should be used
+ * for operations associated with this connection handler
+ * which need access to a key manager, or {@code null} if no
+ * key manager provider has been configured for this
* connection handler.
*/
- private BooleanConfigAttribute getEnabledAtt(ConfigEntry configEntry)
- throws InitializationException, ConfigException
- {
- int msgID = MSGID_CONFIG_CONNHANDLER_ATTR_DESCRIPTION_ENABLED;
- BooleanConfigAttribute enabledStub =
- new BooleanConfigAttribute(ATTR_CONNECTION_HANDLER_ENABLED,
- getMessage(msgID), false);
- BooleanConfigAttribute attr = null;
- try
- {
- attr = (BooleanConfigAttribute) configEntry
- .getConfigAttribute(enabledStub);
- if (attr == null)
- {
- msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
+ public DN getKeyManagerProviderDN() {
+ return currentConfig.getKeyManagerProviderDN();
+ }
+
+
+
+ /**
+ * Get the JMX connection handler's listen port.
+ *
+ * @return Returns the JMX connection handler's listen port.
+ */
+ public int getListenPort() {
+ return currentConfig.getListenPort();
+ }
+
+
+
+ /**
+ * Get the JMX connection handler's RMI connector.
+ *
+ * @return Returns the JMX connection handler's RMI connector.
+ */
+ public RmiConnector getRMIConnector() {
+ return rmiConnector;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getShutdownListenerName() {
+ return connectionHandlerName;
+ }
+
+
+
+ /**
+ * Retrieves the nickname of the server certificate that should be
+ * used in conjunction with this JMX connection handler.
+ *
+ * @return The nickname of the server certificate that should be
+ * used in conjunction with this JMX connection handler.
+ */
+ public String getSSLServerCertNickname() {
+ return currentConfig.getSSLCertNickname();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeConnectionHandler(
+ JMXConnectionHandlerCfg config)
+ throws ConfigException, InitializationException {
+ // Validate the key manager provider DN.
+ DN keyManagerProviderDN = config.getKeyManagerProviderDN();
+ if (keyManagerProviderDN != null) {
+ KeyManagerProvider provider = DirectoryServer
+ .getKeyManagerProvider(keyManagerProviderDN);
+ if (provider == null) {
+ int msgID = MSGID_JMX_CONNHANDLER_INVALID_KEYMANAGER_DN;
+ String message = getMessage(msgID, String
+ .valueOf(config.dn()), String
+ .valueOf(keyManagerProviderDN));
throw new ConfigException(msgID, message);
}
-
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_CONFIG_CONNHANDLER_NO_ENABLED_ATTR;
- String message = getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
}
- return attr;
+ // Issue warning if there is not key manager by SSL is enabled.
+ if (config.isUseSSL() && keyManagerProviderDN == null) {
+ // TODO: give a more useful feedback message.
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING,
+ MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL);
+ int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
+ String message = getMessage(msgID,
+ String.valueOf(currentConfig.dn()), "");
+ throw new ConfigException(msgID, message);
+ }
+
+ // Configuration is ok.
+ currentConfig = config;
+
+ if (config.isUseSSL()) {
+ protocol = "JMX+SSL";
+ } else {
+ protocol = "JMX";
+ }
+
+ listeners.clear();
+ listeners.add(new HostPort("0.0.0.0", config.getListenPort()));
+ connectionHandlerName = "JMX Connection Handler " + config.getListenPort();
+
+ // Create the associated RMI Connector.
+ rmiConnector = new RmiConnector(DirectoryServer.getJMXMBeanServer(), this);
+
+ // Register this as a change listener.
+ config.addJMXChangeListener(this);
}
+
+
/**
- * Retrieves the listen port of the configuration entry with which this
- * component is associated.
+ * {@inheritDoc}
+ */
+ public String getConnectionHandlerName() {
+ return connectionHandlerName;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getProtocol() {
+ return protocol;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<HostPort> getListeners() {
+ return listeners;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ JMXConnectionHandlerCfg config,
+ List<String> unacceptableReasons) {
+ boolean isAcceptable = true;
+
+ // Validate the key manager provider DN.
+ DN keyManagerProviderDN = config.getKeyManagerProviderDN();
+ if (keyManagerProviderDN != null) {
+ KeyManagerProvider provider = DirectoryServer
+ .getKeyManagerProvider(keyManagerProviderDN);
+ if (provider == null) {
+ int msgID = MSGID_JMX_CONNHANDLER_INVALID_KEYMANAGER_DN;
+ unacceptableReasons.add(getMessage(msgID, String
+ .valueOf(config.dn()), String
+ .valueOf(keyManagerProviderDN)));
+ isAcceptable = false;
+ }
+ }
+
+ if (config.isUseSSL() && keyManagerProviderDN == null) {
+ // TODO: give a more useful feedback message.
+ int msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
+ unacceptableReasons.add(getMessage(msgID, String.valueOf(config
+ .dn()), ""));
+ isAcceptable = false;
+ }
+
+ return isAcceptable;
+ }
+
+
+
+ /**
+ * Determines whether or not clients are allowed to connect over JMX
+ * using SSL.
*
- * @param configEntry
- * The configuration entry for which to make the
- * determination.
- * @return The listen port
+ * @return Returns <code>true</code> if clients are allowed to
+ * connect over JMX using SSL.
+ */
+ public boolean isUseSSL() {
+ return currentConfig.isUseSSL();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void processServerShutdown(String reason) {
+ // We should also close the RMI registry.
+ rmiConnector.finalizeConnectionHandler(true, true);
+ }
+
+
+
+ /**
+ * Registers a client connection with this JMX connection handler.
*
- * @throws ConfigException
- * If there is a problem with the configuration for this
- * connection handler.
- * @throws InitializationException
- * If a problem occurs while attempting to initialize this
- * connection handler.
+ * @param connection
+ * The client connection.
*/
- private IntegerConfigAttribute getListenPort(ConfigEntry configEntry)
- throws InitializationException, ConfigException
- {
- int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_LISTEN_PORT;
- IntegerConfigAttribute portStub = new IntegerConfigAttribute(
- ATTR_LISTEN_PORT, getMessage(msgID), true, false, false, true, 1,
- true, 65535);
- IntegerConfigAttribute portAttr = null;
- try
- {
- portAttr = (IntegerConfigAttribute) configEntry
- .getConfigAttribute(portStub);
- if (portAttr == null)
- {
- msgID = MSGID_JMX_CONNHANDLER_NO_LISTEN_PORT;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
-
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
- String message = getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
- return portAttr;
+ public void registerClientConnection(ClientConnection connection) {
+ connectionList.add(connection);
}
- /**
- * Determine if the specified Configuration entry defines the
- * use-ssl attribute.
- * @param configEntry The entry to check
- * @return true if we should use SSL, else false
- * @throws InitializationException
- * If a problem occurs while attempting to get the entry
- * useSSL attribute
- */
- private BooleanConfigAttribute getUseSSL(ConfigEntry configEntry)
- throws InitializationException
- {
- //
- // Determine whether to use SSL.
- int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_USE_SSL;
- BooleanConfigAttribute useSSLStub = new BooleanConfigAttribute(
- ATTR_USE_SSL, getMessage(msgID), false);
- BooleanConfigAttribute useSSLAttr = null;
- try
- {
- useSSLAttr = (BooleanConfigAttribute) configEntry
- .getConfigAttribute(useSSLStub);
- if (useSSLAttr == null)
- {
- //
- // This is fine -- we'll just use the default value.
- useSSLAttr = new BooleanConfigAttribute(ATTR_USE_SSL,
- getMessage(msgID), false, DEFAULT_USE_SSL, DEFAULT_USE_SSL);
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
- String message = getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
- return useSSLAttr;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ rmiConnector.initialize();
}
- /**
- * Determine if the specified Configuration entry defines the
- * server certificate nickname.
- * @param configEntry The entry to check
- * @return The server certificate nickname
- * @throws InitializationException
- * If a problem occurs while attempting to get the entry
- * certificate nickname
- */
- private StringConfigAttribute getServerCertNickname(ConfigEntry configEntry)
- throws InitializationException
- {
- int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME;
- StringConfigAttribute certNameStub = new StringConfigAttribute(
- ATTR_SSL_CERT_NICKNAME, getMessage(msgID), false, false, false);
- StringConfigAttribute certNameAttr = null;
- try
- {
- certNameAttr = (StringConfigAttribute) configEntry
- .getConfigAttribute(certNameStub);
- if (certNameAttr == null)
- {
- //
- // This is fine -- we'll just let the server pick one.
- certNameAttr = new StringConfigAttribute(ATTR_SSL_CERT_NICKNAME,
- getMessage(msgID), false, false, false, (String) null);
- }
- return certNameAttr;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
- String message = getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
- }
/**
- * Determine if the specified Configuration entry defines the
- * key manager provider DN.
- * @param configEntry The entry to check.
- * @return The key manager provider DN.
- * @throws InitializationException
- * If a problem occurs while attempting to get the key manager
- * provider DN.
+ * {@inheritDoc}
*/
- private DNConfigAttribute getKeyManagerDN(ConfigEntry configEntry)
- throws InitializationException
- {
- int msgID = MSGID_JMX_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN;
- DNConfigAttribute keyManagerStub = new DNConfigAttribute(
- ATTR_KEYMANAGER_DN, getMessage(msgID), false, false, false);
- DNConfigAttribute keyManagerAttr = null;
- try
- {
- keyManagerAttr = (DNConfigAttribute) configEntry
- .getConfigAttribute(keyManagerStub);
- return keyManagerAttr;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_JMX_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN;
- String message = getMessage(
- msgID,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
+ public void toString(StringBuilder buffer) {
+ buffer.append(connectionHandlerName);
}
}
diff --git a/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java b/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java
index a258e98..59fdc4b 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java
+++ b/opends/src/server/org/opends/server/protocols/jmx/RmiConnector.java
@@ -44,6 +44,7 @@
import org.opends.server.api.KeyManagerProvider;
import org.opends.server.config.JMXMBean;
+import org.opends.server.core.DirectoryServer;
import org.opends.server.extensions.NullKeyManagerProvider;
import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
@@ -207,7 +208,7 @@
*/
private void startCommonRegistry() throws Exception
{
- int registryPort = jmxConnectionHandler.listenPort;
+ int registryPort = jmxConnectionHandler.getListenPort();
//
// create our local RMI registry if it does not exist already
@@ -294,7 +295,7 @@
// ---------------------
DirectoryRMIClientSocketFactory rmiClientSockeyFactory = null;
DirectoryRMIServerSocketFactory rmiServerSockeyFactory = null;
- if (jmxConnectionHandler.useSSL)
+ if (jmxConnectionHandler.isUseSSL())
{
if (debugEnabled())
{
@@ -307,14 +308,15 @@
//
// Get a Server socket factory
KeyManager[] keyManagers;
- KeyManagerProvider provider = jmxConnectionHandler.keyManagerProvider;
- if (provider == null)
- {
+ KeyManagerProvider provider = DirectoryServer
+ .getKeyManagerProvider(jmxConnectionHandler
+ .getKeyManagerProviderDN());
+ if (provider == null) {
keyManagers = new NullKeyManagerProvider().getKeyManagers();
}
else
{
- String nickname = jmxConnectionHandler.sslServerCertNickname;
+ String nickname = jmxConnectionHandler.getSSLServerCertNickname();
if (nickname == null)
{
keyManagers = provider.getKeyManagers();
@@ -374,7 +376,7 @@
// Create the JMX Service URL
String uri = "org.opends.server.protocols.jmx.client-unknown";
String serviceUrl = "service:jmx:rmi:///jndi/rmi://"
- + registryClientAddress + ":" + jmxConnectionHandler.listenPort
+ + registryClientAddress + ":" + jmxConnectionHandler.getListenPort()
+ "/" + uri;
JMXServiceURL url = new JMXServiceURL(serviceUrl);
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index 554f2dd..1ea5d8e 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -28,48 +28,49 @@
+import static org.opends.server.loggers.Access.logConnect;
+import static org.opends.server.loggers.Error.logError;
+import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.messages.ProtocolMessages.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+
import java.net.InetAddress;
import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.ClientConnection;
-import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.api.ConnectionSecurityProvider;
import org.opends.server.api.KeyManagerProvider;
+import org.opends.server.api.ServerShutdownListener;
import org.opends.server.api.TrustManagerProvider;
import org.opends.server.api.plugin.PostConnectPluginResult;
+import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PluginConfigManager;
-import org.opends.server.config.BooleanConfigAttribute;
-import org.opends.server.config.ConfigAttribute;
-import org.opends.server.config.ConfigEntry;
-import org.opends.server.config.ConfigException;
-import org.opends.server.config.DNConfigAttribute;
-import org.opends.server.config.IntegerConfigAttribute;
-import org.opends.server.config.IntegerWithUnitConfigAttribute;
-import org.opends.server.config.MultiChoiceConfigAttribute;
-import org.opends.server.config.StringConfigAttribute;
import org.opends.server.extensions.NullConnectionSecurityProvider;
import org.opends.server.extensions.TLSConnectionSecurityProvider;
import org.opends.server.types.AddressMask;
import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DisconnectReason;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.HostPort;
@@ -77,176 +78,71 @@
import org.opends.server.types.ResultCode;
import org.opends.server.types.SSLClientAuthPolicy;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.loggers.Access.*;
-import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
-import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
-import org.opends.server.types.DebugLogLevel;
-import static org.opends.server.loggers.Error.*;
-import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.messages.ProtocolMessages.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
/**
- * This class defines a connection handler that will be used for communicating
- * with clients over LDAP. It is actually implemented in two parts: as a
- * connection handler and one or more request handlers. The connection handler
- * is responsible for accepting new connections and registering each of them
- * with a request handler. The request handlers then are responsible for
- * reading requests from the clients and parsing them as operations. A single
- * request handler may be used, but having multiple handlers might provide
+ * This class defines a connection handler that will be used for
+ * communicating with clients over LDAP. It is actually implemented in
+ * two parts: as a connection handler and one or more request
+ * handlers. The connection handler is responsible for accepting new
+ * connections and registering each of them with a request handler.
+ * The request handlers then are responsible for reading requests from
+ * the clients and parsing them as operations. A single request
+ * handler may be used, but having multiple handlers might provide
* better performance in a multi-CPU system.
*/
-public class LDAPConnectionHandler
- extends ConnectionHandler
- implements ConfigurableComponent, AlertGenerator
-{
+public final class LDAPConnectionHandler extends
+ ConnectionHandler<LDAPConnectionHandlerCfg> implements
+ ConfigurationChangeListener<LDAPConnectionHandlerCfg>,
+ ServerShutdownListener, AlertGenerator {
+
/**
* The fully-qualified name of this class.
*/
private static final String CLASS_NAME =
- "org.opends.server.protocols.ldap.LDAPConnectionHandler";
+ "org.opends.server.protocols.ldap.LDAPConnectionHandler";
+ // The current configuration state.
+ private LDAPConnectionHandlerCfg currentConfig;
-
- /**
- * The hash map that holds the units that may be provided in conjunction with
- * the maximum request size.
- */
- private static final HashMap<String,Double> SIZE_UNITS =
- new HashMap<String,Double>();
-
- static
- {
- SIZE_UNITS.put(SIZE_UNIT_BYTES_ABBR, 1D);
- SIZE_UNITS.put(SIZE_UNIT_BYTES_FULL, 1D);
- SIZE_UNITS.put(SIZE_UNIT_KILOBYTES_ABBR, 1000D);
- SIZE_UNITS.put(SIZE_UNIT_KILOBYTES_FULL, 1000D);
- SIZE_UNITS.put(SIZE_UNIT_MEGABYTES_ABBR, 1000000D);
- SIZE_UNITS.put(SIZE_UNIT_MEGABYTES_FULL, 1000000D);
- SIZE_UNITS.put(SIZE_UNIT_GIGABYTES_ABBR, 1000000000D);
- SIZE_UNITS.put(SIZE_UNIT_GIGABYTES_FULL, 1000000000D);
- SIZE_UNITS.put(SIZE_UNIT_KIBIBYTES_ABBR, 1024D);
- SIZE_UNITS.put(SIZE_UNIT_KIBIBYTES_FULL, 1024D);
- SIZE_UNITS.put(SIZE_UNIT_MEBIBYTES_ABBR, (double) (1024 * 1024));
- SIZE_UNITS.put(SIZE_UNIT_MEBIBYTES_FULL, (double) (1024 * 1024));
- SIZE_UNITS.put(SIZE_UNIT_GIBIBYTES_ABBR, (double) (1024 * 1024 * 1024));
- SIZE_UNITS.put(SIZE_UNIT_GIBIBYTES_FULL, (double) (1024 * 1024 * 1024));
- }
-
-
-
- /**
- * The maximum value that may be specified for the max request size
- * configuration attribute.
- */
- private static final int MAX_REQUEST_SIZE_LIMIT = 2147483647;
-
-
-
- // The set of clients that are explicitly allowed access to the server.
- private AddressMask[] allowedClients;
-
- // The set of clients that have been explicitly denied access to the server.
- private AddressMask[] deniedClients;
-
- // Indicates whether to allow LDAPv2 clients.
- private boolean allowLDAPv2;
-
- // Indicates whether to allow the reuse address socket option.
- private boolean allowReuseAddress;
-
- // Indicates whether to allow startTLS extended operations on this connection.
- private boolean allowStartTLS;
-
- // Indicates whether this connection handler is enabled.
- private boolean enabled;
-
- // Indicates whether usage statistics should be maintained.
- private boolean keepStats;
-
- // Indicates whether the server should send an LDAP notice of disconnection
- // message to a client if a connection is rejected.
- private boolean sendRejectionNotice;
-
- // Indicates whether the Directory Server is in the process of shutting down.
- private boolean shutdownRequested;
-
- // Indicates whether to use TCP keepalive messages for new connections.
- private boolean useKeepAlive;
-
- // Indicates whether to use SSL to communicate with the clients.
- private boolean useSSL;
-
- // Indicates whether to use TCP_NODELAY for new connections.
- private boolean useTCPNoDelay;
-
- // The connection security provider that will be used by default for new
- // client connections.
- private ConnectionSecurityProvider securityProvider;
-
- // The DN of the configuration entry for this connection handler.
- private DN configEntryDN;
-
- // The DN of the key manager provider for this connection handler.
- private DN keyManagerProviderDN;
-
- // The DN of the trust manager provider for this connection handler.
- private DN trustManagerProviderDN;
+ /* Properties that cannot be modified dynamically */
// The set of addresses on which to listen for new connections.
- private HashSet<InetAddress> listenAddresses;
+ private Set<InetAddress> listenAddresses;
- // The backlog that will be used for the accept queue.
- private int backlog;
-
- // The port on which this connection handler should listen for requests.
+ // The port on which this connection handler should listen for
+ // requests.
private int listenPort;
- // The maximum ASN.1 element value length that will be allowed when processing
- // requests for this connection handler.
- private int maxRequestSize;
-
- // The number of request handlers that should be used for this connection
- // handler.
- private int numRequestHandlers;
-
- // The index to the request handler that will be used for the next connection
- // accepted by the server.
- private int requestHandlerIndex;
-
- // The set of listeners for this connection handler.
- private LinkedList<HostPort> listeners;
-
- // The set of request handlers that are associated with this connection
- // handler.
- private LDAPRequestHandler[] requestHandlers;
-
- // The set of statistics collected for this connection handler.
- private LDAPStatistics statTracker;
-
- // The selector that will be used to multiplex connection acceptance across
- // multiple sockets by a single thread.
- private Selector selector;
-
// The SSL client auth policy used by this connection handler.
private SSLClientAuthPolicy sslClientAuthPolicy;
- // The unique name assigned to this connection handler.
- private String handlerName;
+ // The backlog that will be used for the accept queue.
+ private int backlog;
- // The protocol used by this connection handler.
- private String protocol;
+ // Indicates whether to allow the reuse address socket option.
+ private boolean allowReuseAddress;
- // The security mechanism used for connections accepted by this connection
- // handler.
- private String securityMechanism;
+ // The number of request handlers that should be used for this
+ // connection handler.
+ private int numRequestHandlers;
- // The nickname of the SSL certificate that should be used if SSL is enabled.
- private String sslServerCertNickname;
+ // Indicates whether the Directory Server is in the process of
+ // shutting down.
+ private boolean shutdownRequested;
+
+ /* Internal LDAP connection handler state */
+
+ // Indicates whether this connection handler is enabled.
+ private boolean enabled;
+
+ // The set of clients that are explicitly allowed access to the
+ // server.
+ private AddressMask[] allowedClients;
+
+ // The set of clients that have been explicitly denied access to the
+ // server.
+ private AddressMask[] deniedClients;
// The set of SSL cipher suites that should be allowed.
private String[] enabledSSLCipherSuites;
@@ -254,1013 +150,181 @@
// The set of SSL protocols that should be allowed.
private String[] enabledSSLProtocols;
- // The thread being used to run this connection handler.
- private Thread connHandlerThread;
+ // The index to the request handler that will be used for the next
+ // connection accepted by the server.
+ private int requestHandlerIndex;
+
+ // The set of listeners for this connection handler.
+ private LinkedList<HostPort> listeners;
+
+ // The set of request handlers that are associated with this
+ // connection handler.
+ private LDAPRequestHandler[] requestHandlers;
+
+ // The set of statistics collected for this connection handler.
+ private LDAPStatistics statTracker;
+
+ // The selector that will be used to multiplex connection acceptance
+ // across multiple sockets by a single thread.
+ private Selector selector;
+
+ // The unique name assigned to this connection handler.
+ private String handlerName;
+
+ // The protocol used by this connection handler.
+ private String protocol;
+
+ // The connection security provider that will be used by default for
+ // new client connections.
+ private ConnectionSecurityProvider securityProvider;
/**
- * Creates a new instance of this LDAP connection handler. It must be
- * initialized before it may be used.
+ * Creates a new instance of this LDAP connection handler. It must
+ * be initialized before it may be used.
*/
- public LDAPConnectionHandler()
- {
+ public LDAPConnectionHandler() {
super("LDAP Connection Handler Thread");
-
- // No real implementation is required. Do all the work in the
+ // No real implementation is required. Do all the work in the
// initializeConnectionHandler method.
}
/**
- * Initializes this connection handler based on the information in the
- * provided configuration entry.
+ * Indicates whether this connection handler should allow
+ * interaction with LDAPv2 clients.
*
- * @param configEntry The configuration entry that contains the information
- * to use to initialize this connection handler.
- *
- * @throws ConfigException If there is a problem with the configuration for
- * this connection handler.
- *
- * @throws InitializationException If a problem occurs while attempting to
- * initialize this connection handler.
+ * @return <CODE>true</CODE> if LDAPv2 is allowed, or <CODE>false</CODE>
+ * if not.
*/
- public void initializeConnectionHandler(ConfigEntry configEntry)
- throws ConfigException, InitializationException
- {
- enabled = true;
+ public boolean allowLDAPv2() {
+ return currentConfig.isAllowLDAPV2();
+ }
- configEntryDN = configEntry.getDN();
- // Determine the set of addresses on which to listen. There can be
- // multiple addresses specified.
- int msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_ADDRESS;
- listenAddresses = new HashSet<InetAddress>();
- StringConfigAttribute addrStub =
- new StringConfigAttribute(ATTR_LISTEN_ADDRESS, getMessage(msgID),
- true, true, true);
- try
- {
- StringConfigAttribute addrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(addrStub);
- if ((addrAttr == null) || addrAttr.activeValues().isEmpty())
- {
- // This is fine -- we'll just listen on all IPv4 addresses.
- listenAddresses.add(InetAddress.getByName("0.0.0.0"));
+
+ /**
+ * Indicates whether this connection handler should allow the use of
+ * the StartTLS extended operation.
+ *
+ * @return <CODE>true</CODE> if StartTLS is allowed, or <CODE>false</CODE>
+ * if not.
+ */
+ public boolean allowStartTLS() {
+ if (currentConfig.isAllowStartTLS()) {
+ if (currentConfig.isUseSSL()) {
+ return false;
+ } else {
+ return true;
}
- else
- {
- for (String s : addrAttr.activeValues())
- {
- try
- {
- listenAddresses.add(InetAddress.getByName(s));
- }
- catch (UnknownHostException uhe)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, uhe);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_UNKNOWN_LISTEN_ADDRESS;
- String message = getMessage(msgID, s,
- stackTraceToSingleLineString(uhe));
- throw new ConfigException(msgID, message, uhe);
- }
- }
- }
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_LISTEN_ADDRESS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the port on which to listen. There may only be a single port
- // specified.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT;
- IntegerConfigAttribute portStub =
- new IntegerConfigAttribute(ATTR_LISTEN_PORT, getMessage(msgID), true,
- false, true, true, 1, true, 65535);
- try
- {
- IntegerConfigAttribute portAttr =
- (IntegerConfigAttribute) configEntry.getConfigAttribute(portStub);
- if (portAttr == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_NO_LISTEN_PORT;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
-
- listenPort = portAttr.activeIntValue();
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the accept backlog.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_BACKLOG;
- IntegerConfigAttribute backlogStub =
- new IntegerConfigAttribute(ATTR_ACCEPT_BACKLOG, getMessage(msgID),
- true, false, true, true, 1, true,
- Integer.MAX_VALUE);
- try
- {
- IntegerConfigAttribute backlogAttr =
- (IntegerConfigAttribute) configEntry.getConfigAttribute(backlogStub);
- if (backlogAttr == null)
- {
- // This is fine -- just use the default value.
- backlog = DEFAULT_ACCEPT_BACKLOG;
- }
- else
- {
- backlog = backlogAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_BACKLOG;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the set of allowed clients.
- allowedClients = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOWED_CLIENTS;
- StringConfigAttribute allowedStub =
- new StringConfigAttribute(ATTR_ALLOWED_CLIENT, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute allowedAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(allowedStub);
- if (allowedAttr != null)
- {
- List<String> maskStrings = allowedAttr.activeValues();
- allowedClients = new AddressMask[maskStrings.size()];
- for (int i=0; i < allowedClients.length; i++)
- {
- try
- {
- allowedClients[i] = AddressMask.decode(maskStrings.get(i));
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_ADDRESS_MASK;
- String message = getMessage(msgID, maskStrings.get(i),
- ATTR_ALLOWED_CLIENT,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(ce));
- throw new ConfigException(msgID, message, ce);
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOWED_CLIENTS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the set of denied clients.
- deniedClients = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_DENIED_CLIENTS;
- StringConfigAttribute deniedStub =
- new StringConfigAttribute(ATTR_DENIED_CLIENT, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute deniedAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(deniedStub);
- if (deniedAttr != null)
- {
- List<String> maskStrings = deniedAttr.activeValues();
- deniedClients = new AddressMask[maskStrings.size()];
- for (int i=0; i < deniedClients.length; i++)
- {
- try
- {
- deniedClients[i] = AddressMask.decode(maskStrings.get(i));
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_ADDRESS_MASK;
- String message = getMessage(msgID, maskStrings.get(i),
- ATTR_ALLOWED_CLIENT,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(ce));
- throw new ConfigException(msgID, message, ce);
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_DENIED_CLIENTS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to allow LDAPv2 clients.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_LDAPV2;
- BooleanConfigAttribute allowLDAPv2Stub =
- new BooleanConfigAttribute(ATTR_ALLOW_LDAPV2, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute allowLDAPv2Attr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(allowLDAPv2Stub);
- if (allowLDAPv2Attr == null)
- {
- // This is fine -- we'll just use the default behavior, which is to
- // allow these clients.
- allowLDAPv2 = DEFAULT_ALLOW_LDAPV2;
- }
- else
- {
- allowLDAPv2 = allowLDAPv2Attr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_LDAPV2;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to keep LDAP statistics.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEEP_STATS;
- BooleanConfigAttribute keepStatsStub =
- new BooleanConfigAttribute(ATTR_KEEP_LDAP_STATS, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute keepStatsAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(keepStatsStub);
- if (keepStatsAttr == null)
- {
- // This is fine -- we'll just use the default behavior, which is to
- // allow these clients.
- keepStats = DEFAULT_KEEP_LDAP_STATS;
- }
- else
- {
- keepStats = keepStatsAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEEP_STATS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the number of request handlers to maintain.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_NUM_REQUEST_HANDLERS;
- IntegerConfigAttribute reqHandlerStub =
- new IntegerConfigAttribute(ATTR_NUM_REQUEST_HANDLERS,
- getMessage(msgID), true, false, true,
- true, 1, false, 0);
- try
- {
- IntegerConfigAttribute reqHandlerAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(reqHandlerStub);
- if (reqHandlerAttr == null)
- {
- // This is fine -- we'll just use the default value.
- numRequestHandlers = DEFAULT_NUM_REQUEST_HANDLERS;
- }
- else
- {
- numRequestHandlers = reqHandlerAttr.activeIntValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_NUM_REQUEST_HANDLERS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to send a notice to clients on rejection.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SEND_REJECTION_NOTICE;
- BooleanConfigAttribute notifyRejectsStub =
- new BooleanConfigAttribute(ATTR_SEND_REJECTION_NOTICE,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute notifyRejectsAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(notifyRejectsStub);
- if (notifyRejectsAttr == null)
- {
- // This is fine -- we'll just use the default value.
- sendRejectionNotice = DEFAULT_SEND_REJECTION_NOTICE;
- }
- else
- {
- sendRejectionNotice = notifyRejectsAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SEND_REJECTION_NOTICE;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to use TCP keepalive.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_KEEPALIVE;
- BooleanConfigAttribute keepAliveStub =
- new BooleanConfigAttribute(ATTR_USE_TCP_KEEPALIVE, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute keepAliveAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(keepAliveStub);
- if (keepAliveAttr == null)
- {
- // This is fine -- we'll just use the default.
- useKeepAlive = DEFAULT_USE_TCP_KEEPALIVE;
- }
- else
- {
- useKeepAlive = keepAliveAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_KEEPALIVE;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to use TCP nodelay.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_NODELAY;
- BooleanConfigAttribute noDelayStub =
- new BooleanConfigAttribute(ATTR_USE_TCP_NODELAY, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute noDelayAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(noDelayStub);
- if (noDelayAttr == null)
- {
- // This is fine -- we'll just use the default.
- useTCPNoDelay = DEFAULT_USE_TCP_NODELAY;
- }
- else
- {
- useTCPNoDelay = noDelayAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_NODELAY;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to allow reuse of address/port combinations.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_REUSE_ADDRESS;
- BooleanConfigAttribute reuseAddrStub =
- new BooleanConfigAttribute(ATTR_ALLOW_REUSE_ADDRESS,
- getMessage(msgID), true);
- try
- {
- BooleanConfigAttribute reuseAddrAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(reuseAddrStub);
- if (reuseAddrAttr == null)
- {
- // This is fine -- we'll just use the default.
- allowReuseAddress = DEFAULT_ALLOW_REUSE_ADDRESS;
- }
- else
- {
- allowReuseAddress = reuseAddrAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_REUSE_ADDRESS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the maximum allowed request size.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_MAX_REQUEST_SIZE;
- IntegerWithUnitConfigAttribute maxReqSizeStub =
- new IntegerWithUnitConfigAttribute(ATTR_MAX_REQUEST_SIZE,
- getMessage(msgID), false,
- SIZE_UNITS, true, 0, true,
- MAX_REQUEST_SIZE_LIMIT);
- try
- {
- IntegerWithUnitConfigAttribute maxReqSizeAttr =
- (IntegerWithUnitConfigAttribute)
- configEntry.getConfigAttribute(maxReqSizeStub);
- if (maxReqSizeAttr == null)
- {
- // This is fine -- we'll just use the default value.
- maxRequestSize = DEFAULT_MAX_REQUEST_SIZE;
- }
- else
- {
- maxRequestSize = (int) maxReqSizeAttr.activeCalculatedValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_MAX_REQUEST_SIZE;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to use SSL.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_SSL;
- BooleanConfigAttribute useSSLStub =
- new BooleanConfigAttribute(ATTR_USE_SSL, getMessage(msgID), true);
- try
- {
- BooleanConfigAttribute useSSLAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(useSSLStub);
- if (useSSLAttr == null)
- {
- // This is fine -- we'll just use the default value.
- useSSL = DEFAULT_USE_SSL;
- }
- else
- {
- useSSL = useSSLAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine whether to allow the StartTLS extended operation.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_STARTTLS;
- BooleanConfigAttribute startTLSStub =
- new BooleanConfigAttribute(ATTR_ALLOW_STARTTLS, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute startTLSAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(startTLSStub);
- if (startTLSAttr == null)
- {
- // This is fine -- we'll just use the default.
- allowStartTLS = DEFAULT_ALLOW_STARTTLS;
- }
- else
- {
- allowStartTLS = startTLSAttr.activeValue();
- }
-
-
- // See if both SSL and startTLS are configured. If so, we'll have to
- // disable startTLS because they can't both be used concurrently.
- if (useSSL && allowStartTLS)
- {
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_HAVE_SSL_AND_STARTTLS;
- String message = getMessage(msgID, String.valueOf(configEntryDN));
- logError(ErrorLogCategory.CONFIGURATION,
- ErrorLogSeverity.SEVERE_WARNING, message, msgID);
-
- allowStartTLS = false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_STARTTLS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine how to handle SSL client authentication.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_CLIENT_AUTH_POLICY;
- HashSet<String> allowedValues = new HashSet<String>(3);
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.DISABLED.toString()));
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.OPTIONAL.toString()));
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.REQUIRED.toString()));
- MultiChoiceConfigAttribute sslAuthPolicyStub =
- new MultiChoiceConfigAttribute(ATTR_SSL_CLIENT_AUTH_POLICY,
- getMessage(msgID), false, false, true,
- allowedValues);
- try
- {
- MultiChoiceConfigAttribute sslAuthPolicyAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(sslAuthPolicyStub);
- if (sslAuthPolicyAttr == null)
- {
- // This is fine -- We'll just use the default.
- sslClientAuthPolicy = DEFAULT_SSL_CLIENT_AUTH_POLICY;
- }
- else
- {
- sslClientAuthPolicy = SSLClientAuthPolicy.policyForName(
- sslAuthPolicyAttr.activeValue());
- if (sslClientAuthPolicy == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_SSL_CLIENT_AUTH_POLICY;
- String message = getMessage(msgID, sslAuthPolicyAttr.activeValue(),
- String.valueOf(configEntryDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CLIENT_AUTH_POLICY;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine which SSL certificate to use.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME;
- StringConfigAttribute certNameStub =
- new StringConfigAttribute(ATTR_SSL_CERT_NICKNAME, getMessage(msgID),
- false, false, true);
- try
- {
- StringConfigAttribute certNameAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(certNameStub);
- if (certNameAttr == null)
- {
- // This is fine -- We'll just let the server pick one.
- sslServerCertNickname = null;
- }
- else
- {
- sslServerCertNickname = certNameAttr.activeValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the set of SSL protocols to allow.
- enabledSSLProtocols = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_PROTOCOLS;
- StringConfigAttribute sslProtocolsStub =
- new StringConfigAttribute(ATTR_SSL_PROTOCOLS, getMessage(msgID), false,
- true, false);
- try
- {
- StringConfigAttribute sslProtocolsAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(sslProtocolsStub);
- if (sslProtocolsAttr != null)
- {
- enabledSSLProtocols = listToArray(sslProtocolsAttr.activeValues());
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_PROTOCOLS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the set of SSL cipher suites to allow.
- enabledSSLCipherSuites = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_CIPHERS;
- StringConfigAttribute sslCiphersStub =
- new StringConfigAttribute(ATTR_SSL_CIPHERS, getMessage(msgID), false,
- true, false);
- try
- {
- StringConfigAttribute sslCiphersAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(sslCiphersStub);
- if (sslCiphersAttr != null)
- {
- enabledSSLCipherSuites = listToArray(sslCiphersAttr.activeValues());
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CIPHERS;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the key manager provider to use.
- keyManagerProviderDN = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN;
- DNConfigAttribute keyManagerStub =
- new DNConfigAttribute(ATTR_KEYMANAGER_DN, getMessage(msgID), false,
- false, false);
- try
- {
- DNConfigAttribute keyManagerAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(keyManagerStub);
- if (keyManagerAttr != null)
- {
- keyManagerProviderDN = keyManagerAttr.activeValue();
- KeyManagerProvider provider =
- DirectoryServer.getKeyManagerProvider(keyManagerProviderDN);
- if (provider == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_KEYMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(keyManagerProviderDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Determine the trust manager provider to use.
- trustManagerProviderDN = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN;
- DNConfigAttribute trustManagerStub =
- new DNConfigAttribute(ATTR_TRUSTMANAGER_DN, getMessage(msgID), false,
- false, false);
- try
- {
- DNConfigAttribute trustManagerAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(trustManagerStub);
- if (trustManagerAttr != null)
- {
- trustManagerProviderDN = trustManagerAttr.activeValue();
- TrustManagerProvider provider =
- DirectoryServer.getTrustManagerProvider(trustManagerProviderDN);
- if (provider == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_TRUSTMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(trustManagerProviderDN));
- throw new ConfigException(msgID, message);
- }
- }
- }
- catch (ConfigException ce)
- {
- throw ce;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_TRUSTMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- if (useSSL)
- {
- TLSConnectionSecurityProvider tlsProvider =
- new TLSConnectionSecurityProvider();
- tlsProvider.initializeConnectionSecurityProvider(null);
- tlsProvider.setSSLClientAuthPolicy(sslClientAuthPolicy);
- tlsProvider.setEnabledProtocols(enabledSSLProtocols);
- tlsProvider.setEnabledCipherSuites(enabledSSLCipherSuites);
-
- // FIXME -- Need to do something with the requested cert nickname.
-
- securityProvider = tlsProvider;
- }
- else
- {
- securityProvider = new NullConnectionSecurityProvider();
- securityProvider.initializeConnectionSecurityProvider(null);
- }
-
-
- DirectoryServer.registerConfigurableComponent(this);
-
-
- try
- {
- selector = Selector.open();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_OPEN_SELECTOR_FAILED;
- String message = getMessage(msgID, configEntryDN,
- stackTraceToSingleLineString(e));
- throw new InitializationException(msgID, message, e);
- }
-
-
- // Construct a unique name for this connection handler, and put together the
- // set of listeners.
- listeners = new LinkedList<HostPort>();
- StringBuilder nameBuffer = new StringBuilder();
- nameBuffer.append("LDAP Connection Handler");
- for (InetAddress a : listenAddresses)
- {
- listeners.add(new HostPort(a.getHostAddress(), listenPort));
- nameBuffer.append(" ");
- nameBuffer.append(a.getHostAddress());
- }
- nameBuffer.append(" port ");
- nameBuffer.append(listenPort);
- handlerName = nameBuffer.toString();
-
-
- // Set the security mechanism for this connection handler.
- if (useSSL)
- {
- securityMechanism = SECURITY_MECHANISM_SSL;
- protocol = "LDAP+SSL";
- }
- else
- {
- securityMechanism = null;
- protocol = "LDAP";
- }
-
-
- // Perform any additional initialization that might be required.
- connHandlerThread = null;
- statTracker = new LDAPStatistics(handlerName + " Statistics");
-
-
- // Create and start the request handlers.
- requestHandlers = new LDAPRequestHandler[numRequestHandlers];
- for (int i=0; i < numRequestHandlers; i++)
- {
- requestHandlers[i] = new LDAPRequestHandler(this, i);
- }
- for (int i=0; i < numRequestHandlers; i++)
- {
- requestHandlers[i].start();
+ } else {
+ return false;
}
}
/**
- * Closes this connection handler so that it will no longer accept new client
- * connections. It may or may not disconnect existing client connections
- * based on the provided flag. Note, however, that some connection handler
- * implementations may not have any way to continue processing requests from
- * existing connections, in which case they should always be closed regardless
- * of the value of the <CODE>closeConnections</CODE> flag.
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ LDAPConnectionHandlerCfg config) {
+ // Create variables to include in the response.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ // Note that the following properties cannot be modified:
+ //
+ // * listen port and addresses
+ // * use ssl
+ // * ssl policy
+ // * ssl cert nickname
+ // * accept backlog
+ // * tcp reuse address
+ // * num request handler
+
+ // Start/clear the stat tracker if LDAPv2 is being enabled.
+ if (currentConfig.isAllowLDAPV2() != config.isAllowLDAPV2()) {
+ if (config.isAllowLDAPV2()) {
+ if (statTracker == null) {
+ statTracker = new LDAPStatistics(handlerName
+ + " Statistics");
+ } else {
+ statTracker.clearStatistics();
+ }
+ }
+ }
+
+ // Apply the changes.
+ currentConfig = config;
+ enabled = config.isEnabled();
+ allowedClients = config.getAllowedClients().toArray(
+ new AddressMask[0]);
+ deniedClients = config.getDeniedClients().toArray(
+ new AddressMask[0]);
+
+ // Get the supported SSL ciphers and protocols.
+ Set<String> ciphers = config.getSSLCipherSuites();
+ if (ciphers.isEmpty()) {
+ enabledSSLCipherSuites = null;
+ } else {
+ enabledSSLCipherSuites = ciphers.toArray(new String[0]);
+ }
+
+ Set<String> protocols = config.getSSLProtocols();
+ if (protocols.isEmpty()) {
+ enabledSSLProtocols = null;
+ } else {
+ enabledSSLProtocols = protocols.toArray(new String[0]);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired,
+ messages);
+ }
+
+
+
+ /**
+ * Closes this connection handler so that it will no longer accept
+ * new client connections. It may or may not disconnect existing
+ * client connections based on the provided flag. Note, however,
+ * that some connection handler implementations may not have any way
+ * to continue processing requests from existing connections, in
+ * which case they should always be closed regardless of the value
+ * of the <CODE>closeConnections</CODE> flag.
*
- * @param finalizeReason The reason that this connection handler should be
- * finalized.
- * @param closeConnections Indicates whether any established client
- * connections associated with the connection
- * handler should also be closed.
+ * @param finalizeReason
+ * The reason that this connection handler should be
+ * finalized.
+ * @param closeConnections
+ * Indicates whether any established client connections
+ * associated with the connection handler should also be
+ * closed.
*/
public void finalizeConnectionHandler(String finalizeReason,
- boolean closeConnections)
- {
+ boolean closeConnections) {
shutdownRequested = true;
+ currentConfig.removeLDAPChangeListener(this);
- DirectoryServer.deregisterConfigurableComponent(this);
-
- try
- {
+ try {
selector.wakeup();
- }
- catch (Exception e)
- {
+ } catch (Exception e) {
if (debugEnabled())
{
debugCaught(DebugLogLevel.ERROR, e);
}
}
-
- if (closeConnections)
- {
- for (LDAPRequestHandler requestHandler : requestHandlers)
- {
+ if (closeConnections) {
+ for (LDAPRequestHandler requestHandler : requestHandlers) {
requestHandler.processServerShutdown(finalizeReason);
}
- }
- else
- {
- for (LDAPRequestHandler requestHandler : requestHandlers)
- {
+ } else {
+ for (LDAPRequestHandler requestHandler : requestHandlers) {
requestHandler.registerShutdownListener();
}
}
@@ -1269,48 +333,54 @@
/**
- * {@inheritDoc}
- */
- public String getConnectionHandlerName()
- {
- return handlerName;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public String getProtocol()
- {
- return protocol;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- public Collection<HostPort> getListeners()
- {
- return listeners;
- }
-
-
-
- /**
- * Retrieves the set of active client connections that have been established
- * through this connection handler.
+ * Retrieves information about the set of alerts that this generator
+ * may produce. The map returned should be between the notification
+ * type for a particular notification and the human-readable
+ * description for that notification. This alert generator must not
+ * generate any alerts with types that are not contained in this
+ * list.
*
- * @return The set of active client connections that have been established
- * through this connection handler.
+ * @return Information about the set of alerts that this generator
+ * may produce.
*/
- public Collection<ClientConnection> getClientConnections()
- {
+ public LinkedHashMap<String, String> getAlerts() {
+ LinkedHashMap<String, String> alerts = new LinkedHashMap<String, String>();
+
+ alerts
+ .put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES,
+ ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES);
+ alerts.put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR,
+ ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR);
+
+ return alerts;
+ }
+
+
+
+ /**
+ * Retrieves the fully-qualified name of the Java class for this
+ * alert generator implementation.
+ *
+ * @return The fully-qualified name of the Java class for this alert
+ * generator implementation.
+ */
+ public String getClassName() {
+ return CLASS_NAME;
+ }
+
+
+
+ /**
+ * Retrieves the set of active client connections that have been
+ * established through this connection handler.
+ *
+ * @return The set of active client connections that have been
+ * established through this connection handler.
+ */
+ public Collection<ClientConnection> getClientConnections() {
LinkedList<ClientConnection> connectionList =
- new LinkedList<ClientConnection>();
- for (LDAPRequestHandler requestHandler : requestHandlers)
- {
+ new LinkedList<ClientConnection>();
+ for (LDAPRequestHandler requestHandler : requestHandlers) {
connectionList.addAll(requestHandler.getClientConnections());
}
@@ -1320,104 +390,492 @@
/**
+ * Retrieves the DN of the configuration entry with which this alert
+ * generator is associated.
+ *
+ * @return The DN of the configuration entry with which this alert
+ * generator is associated.
+ */
+ public DN getComponentEntryDN() {
+ return currentConfig.dn();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getConnectionHandlerName() {
+ return handlerName;
+ }
+
+
+
+ /**
+ * Retrieves the set of enabled SSL cipher suites configured for
+ * this connection handler.
+ *
+ * @return The set of enabled SSL cipher suites configured for this
+ * connection handler.
+ */
+ public String[] getEnabledSSLCipherSuites() {
+ return enabledSSLCipherSuites;
+ }
+
+
+
+ /**
+ * Retrieves the set of enabled SSL protocols configured for this
+ * connection handler.
+ *
+ * @return The set of enabled SSL protocols configured for this
+ * connection handler.
+ */
+ public String[] getEnabledSSLProtocols() {
+ return enabledSSLProtocols;
+ }
+
+
+
+ /**
+ * Retrieves the DN of the key manager provider that should be used
+ * for operations associated with this connection handler which need
+ * access to a key manager.
+ *
+ * @return The DN of the key manager provider that should be used
+ * for operations associated with this connection handler
+ * which need access to a key manager, or {@code null} if no
+ * key manager provider has been configured for this
+ * connection handler.
+ */
+ public DN getKeyManagerProviderDN() {
+ return currentConfig.getKeyManagerProviderDN();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<HostPort> getListeners() {
+ return listeners;
+ }
+
+
+
+ /**
* Retrieves the port on which this connection handler is listening
* for client connections.
*
- * @return The port on which this connection handler is listening
- * for client connections.
+ * @return The port on which this connection handler is listening
+ * for client connections.
*/
- public int getListenPort()
- {
+ public int getListenPort() {
return listenPort;
}
/**
- * Operates in a loop, accepting new connections and ensuring that requests on
- * those connections are handled properly.
+ * Retrieves the maximum ASN.1 element value length that will be
+ * allowed by this connection handler.
+ *
+ * @return The maximum ASN.1 element value length that will be
+ * allowed by this connection handler.
*/
- public void run()
- {
- connHandlerThread = Thread.currentThread();
- setName(handlerName);
+ public int getMaxRequestSize() {
+ return (int) ((long) currentConfig.getMaxRequestSize());
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getProtocol() {
+ return protocol;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getShutdownListenerName() {
+ return handlerName;
+ }
+
+
+
+ /**
+ * Retrieves the nickname of the server certificate that should be
+ * used in conjunction with this LDAP connection handler.
+ *
+ * @return The nickname of the server certificate that should be
+ * used in conjunction with this LDAP connection handler.
+ */
+ public String getSSLServerCertNickname() {
+ return currentConfig.getSSLCertNickname();
+ }
+
+
+
+ /**
+ * Retrieves the SSL client authentication policy for this
+ * connection handler.
+ *
+ * @return The SSL client authentication policy for this connection
+ * handler.
+ */
+ public SSLClientAuthPolicy getSSLClientAuthPolicy() {
+ return sslClientAuthPolicy;
+ }
+
+
+
+ /**
+ * Retrieves the set of statistics maintained by this connection
+ * handler.
+ *
+ * @return The set of statistics maintained by this connection
+ * handler.
+ */
+ public LDAPStatistics getStatTracker() {
+ return statTracker;
+ }
+
+
+
+ /**
+ * Retrieves the DN of the trust manager provider that should be
+ * used for operations associated with this connection handler which
+ * need access to a trust manager.
+ *
+ * @return The DN of the trust manager provider that should be used
+ * for operations associated with this connection handler
+ * which need access to a trust manager, or {@code null} if
+ * no trust manager provider has been configured for this
+ * connection handler.
+ */
+ public DN getTrustManagerProviderDN() {
+ return currentConfig.getTrustManagerProviderDN();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeConnectionHandler(
+ LDAPConnectionHandlerCfg config)
+ throws ConfigException, InitializationException {
+ // SSL and StartTLS are mutually exclusive.
+ if (config.isAllowStartTLS() && config.isUseSSL()) {
+ int msgID = MSGID_LDAP_CONNHANDLER_CANNOT_HAVE_SSL_AND_STARTTLS;
+ String message = getMessage(msgID, String.valueOf(config.dn()));
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING, message, msgID);
+ }
+
+ // Validate the key manager provider DN.
+ DN keyManagerProviderDN = config.getKeyManagerProviderDN();
+ if (keyManagerProviderDN != null) {
+ KeyManagerProvider provider = DirectoryServer
+ .getKeyManagerProvider(keyManagerProviderDN);
+ if (provider == null) {
+ int msgID = MSGID_LDAP_CONNHANDLER_INVALID_KEYMANAGER_DN;
+ String message = getMessage(msgID, String
+ .valueOf(config.dn()), String
+ .valueOf(keyManagerProviderDN));
+ throw new ConfigException(msgID, message);
+ }
+ }
+
+ // Validate the trust manager provider DN.
+ DN trustManagerProviderDN = config.getTrustManagerProviderDN();
+ if (trustManagerProviderDN != null) {
+ TrustManagerProvider provider = DirectoryServer
+ .getTrustManagerProvider(trustManagerProviderDN);
+ if (provider == null) {
+ int msgID = MSGID_LDAP_CONNHANDLER_INVALID_TRUSTMANAGER_DN;
+ String message = getMessage(msgID, String
+ .valueOf(config.dn()), String
+ .valueOf(trustManagerProviderDN));
+ throw new ConfigException(msgID, message);
+ }
+ }
+
+ // Open the selector.
+ try {
+ selector = Selector.open();
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ int msgID = MSGID_LDAP_CONNHANDLER_OPEN_SELECTOR_FAILED;
+ String message = getMessage(msgID, config.dn(),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
+
+ // Get the SSL auth policy.
+ switch (config.getSSLClientAuthPolicy()) {
+ case DISABLED:
+ sslClientAuthPolicy = SSLClientAuthPolicy.DISABLED;
+ break;
+ case REQUIRED:
+ sslClientAuthPolicy = SSLClientAuthPolicy.REQUIRED;
+ break;
+ default:
+ sslClientAuthPolicy = SSLClientAuthPolicy.OPTIONAL;
+ break;
+ }
+
+ // Get the supported SSL ciphers and protocols.
+ Set<String> ciphers = config.getSSLCipherSuites();
+ if (ciphers.isEmpty()) {
+ enabledSSLCipherSuites = null;
+ } else {
+ enabledSSLCipherSuites = ciphers.toArray(new String[0]);
+ }
+
+ Set<String> protocols = config.getSSLProtocols();
+ if (protocols.isEmpty()) {
+ enabledSSLProtocols = null;
+ } else {
+ enabledSSLProtocols = protocols.toArray(new String[0]);
+ }
+
+ // Initialize the security provider.
+ if (config.isUseSSL()) {
+ TLSConnectionSecurityProvider tlsProvider =
+ new TLSConnectionSecurityProvider();
+ tlsProvider.initializeConnectionSecurityProvider(null);
+ tlsProvider.setSSLClientAuthPolicy(sslClientAuthPolicy);
+ tlsProvider.setEnabledProtocols(enabledSSLProtocols);
+ tlsProvider.setEnabledCipherSuites(enabledSSLCipherSuites);
+
+ // FIXME -- Need to do something with the requested cert
+ // nickname.
+
+ securityProvider = tlsProvider;
+ } else {
+ securityProvider = new NullConnectionSecurityProvider();
+ securityProvider.initializeConnectionSecurityProvider(null);
+ }
+
+ // Save this configuration for future reference.
+ currentConfig = config;
+ enabled = config.isEnabled();
+ requestHandlerIndex = 0;
+ allowedClients = config.getAllowedClients().toArray(
+ new AddressMask[0]);
+ deniedClients = config.getDeniedClients().toArray(
+ new AddressMask[0]);
+
+ // Save properties that cannot be dynamically modified.
+ allowReuseAddress = config.isAllowTCPReuseAddress();
+ backlog = config.getAcceptBacklog();
+ listenAddresses = config.getListenAddresses();
+ listenPort = config.getListenPort();
+ numRequestHandlers = config.getNumRequestHandlers();
+
+ // Construct a unique name for this connection handler, and put
+ // together the
+ // set of listeners.
+ listeners = new LinkedList<HostPort>();
+ StringBuilder nameBuffer = new StringBuilder();
+ nameBuffer.append("LDAP Connection Handler");
+ for (InetAddress a : listenAddresses) {
+ listeners.add(new HostPort(a.getHostAddress(), listenPort));
+ nameBuffer.append(" ");
+ nameBuffer.append(a.getHostAddress());
+ }
+ nameBuffer.append(" port ");
+ nameBuffer.append(listenPort);
+ handlerName = nameBuffer.toString();
+
+ // Set the protocol for this connection handler.
+ if (config.isUseSSL()) {
+ protocol = "LDAP+SSL";
+ } else {
+ protocol = "LDAP";
+ }
+
+ // Perform any additional initialization that might be required.
+ statTracker = new LDAPStatistics(handlerName + " Statistics");
+
+ // Create and start the request handlers.
+ requestHandlers = new LDAPRequestHandler[numRequestHandlers];
+ for (int i = 0; i < numRequestHandlers; i++) {
+ requestHandlers[i] = new LDAPRequestHandler(this, i);
+ }
+
+ for (int i = 0; i < numRequestHandlers; i++) {
+ requestHandlers[i].start();
+ }
+
+ // Register this as a change listener.
+ config.addLDAPChangeListener(this);
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ LDAPConnectionHandlerCfg config,
+ List<String> unacceptableReasons) {
+ boolean isAcceptable = true;
+
+ // SSL and StartTLS are mutually exclusive.
+ if (config.isAllowStartTLS() && config.isUseSSL()) {
+ int msgID = MSGID_LDAP_CONNHANDLER_CANNOT_HAVE_SSL_AND_STARTTLS;
+ unacceptableReasons.add(getMessage(msgID, String.valueOf(config
+ .dn())));
+ isAcceptable = false;
+ }
+
+ // Validate the key manager provider DN.
+ DN keyManagerProviderDN = config.getKeyManagerProviderDN();
+ if (keyManagerProviderDN != null) {
+ KeyManagerProvider provider = DirectoryServer
+ .getKeyManagerProvider(keyManagerProviderDN);
+ if (provider == null) {
+ int msgID = MSGID_LDAP_CONNHANDLER_INVALID_KEYMANAGER_DN;
+ unacceptableReasons.add(getMessage(msgID, String
+ .valueOf(config.dn()), String
+ .valueOf(keyManagerProviderDN)));
+ isAcceptable = false;
+ }
+ }
+
+ // Validate the trust manager provider DN.
+ DN trustManagerProviderDN = config.getTrustManagerProviderDN();
+ if (trustManagerProviderDN != null) {
+ TrustManagerProvider provider = DirectoryServer
+ .getTrustManagerProvider(trustManagerProviderDN);
+ if (provider == null) {
+ int msgID = MSGID_LDAP_CONNHANDLER_INVALID_TRUSTMANAGER_DN;
+ unacceptableReasons.add(getMessage(msgID, String
+ .valueOf(config.dn()), String
+ .valueOf(trustManagerProviderDN)));
+ isAcceptable = false;
+ }
+ }
+
+ return isAcceptable;
+ }
+
+
+
+ /**
+ * Indicates whether this connection handler should maintain usage
+ * statistics.
+ *
+ * @return <CODE>true</CODE> if this connection handler should
+ * maintain usage statistics, or <CODE>false</CODE> if
+ * not.
+ */
+ public boolean keepStats() {
+ return currentConfig.isKeepStats();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void processServerShutdown(String reason) {
+ shutdownRequested = true;
+
+ try {
+ for (LDAPRequestHandler requestHandler : requestHandlers) {
+ try {
+ requestHandler.processServerShutdown(reason);
+ } catch (Exception e) {
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+
+
+
+ /**
+ * Operates in a loop, accepting new connections and ensuring that
+ * requests on those connections are handled properly.
+ */
+ public void run() {
+ setName(handlerName);
boolean listening = false;
- while (! shutdownRequested)
- {
- // If this connection handler is not enabled, then just sleep for a bit
- // and check again.
- if (! enabled)
- {
- if (listening)
- {
+ while (!shutdownRequested) {
+ // If this connection handler is not enabled, then just sleep
+ // for a bit and check again.
+ if (!enabled) {
+ if (listening) {
cleanUpSelector();
listening = false;
- enabled = false;
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.NOTICE,
- MSGID_LDAP_CONNHANDLER_STOPPED_LISTENING, handlerName);
+ ErrorLogSeverity.NOTICE,
+ MSGID_LDAP_CONNHANDLER_STOPPED_LISTENING, handlerName);
}
- try
- {
+ try {
Thread.sleep(1000);
- } catch (Exception e) {}
+ } catch (Exception e) {
+ }
continue;
}
-
- // If we have gotten here, then we are about to start listening for the
- // first time since startup or since we were previously disabled. Make
- // sure to start with a clean selector and then create all the listeners.
- try
- {
+ // If we have gotten here, then we are about to start listening
+ // for the first time since startup or since we were previously
+ // disabled. Make sure to start with a clean selector and then
+ // create all the listeners.
+ try {
cleanUpSelector();
int numRegistered = 0;
- for (InetAddress a : listenAddresses)
- {
- try
- {
+ for (InetAddress a : listenAddresses) {
+ try {
ServerSocketChannel channel = ServerSocketChannel.open();
channel.socket().setReuseAddress(allowReuseAddress);
- channel.socket().bind(new InetSocketAddress(a, listenPort),
- backlog);
+ channel.socket().bind(
+ new InetSocketAddress(a, listenPort), backlog);
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_ACCEPT);
numRegistered++;
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.NOTICE,
- MSGID_LDAP_CONNHANDLER_STARTED_LISTENING, handlerName);
- }
- catch (Exception e)
- {
+ ErrorLogSeverity.NOTICE,
+ MSGID_LDAP_CONNHANDLER_STARTED_LISTENING, handlerName);
+ } catch (Exception e) {
if (debugEnabled())
{
debugCaught(DebugLogLevel.ERROR, e);
}
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.SEVERE_ERROR,
- MSGID_LDAP_CONNHANDLER_CREATE_CHANNEL_FAILED,
- configEntryDN, a.getHostAddress(), listenPort,
- stackTraceToSingleLineString(e));
+ ErrorLogSeverity.SEVERE_ERROR,
+ MSGID_LDAP_CONNHANDLER_CREATE_CHANNEL_FAILED,
+ currentConfig.dn(), a.getHostAddress(), listenPort,
+ stackTraceToSingleLineString(e));
}
}
-
- // If none of the listeners were created successfully, then consider the
- // connection handler disabled and require administrative action before
- // trying again.
- if (numRegistered == 0)
- {
+ // If none of the listeners were created successfully, then
+ // consider the connection handler disabled and require
+ // administrative action before trying again.
+ if (numRegistered == 0) {
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.FATAL_ERROR,
- MSGID_LDAP_CONNHANDLER_NO_ACCEPTORS, configEntryDN);
+ ErrorLogSeverity.FATAL_ERROR,
+ MSGID_LDAP_CONNHANDLER_NO_ACCEPTORS, currentConfig.dn());
enabled = false;
continue;
@@ -1425,66 +883,64 @@
listening = true;
-
- // Enter a loop, waiting for new connections to arrive and then
- // accepting them as they come in.
+ // Enter a loop, waiting for new connections to arrive and
+ // then accepting them as they come in.
boolean lastIterationFailed = false;
- while (enabled && (! shutdownRequested))
- {
- try
- {
- if (selector.select() > 0)
- {
- Iterator<SelectionKey> iterator =
- selector.selectedKeys().iterator();
+ while (enabled && (!shutdownRequested)) {
+ try {
+ if (selector.select() > 0) {
+ Iterator<SelectionKey> iterator = selector
+ .selectedKeys().iterator();
- while (iterator.hasNext())
- {
+ while (iterator.hasNext()) {
SelectionKey key = iterator.next();
- if (key.isAcceptable())
- {
+ if (key.isAcceptable()) {
// Accept the new client connection.
- ServerSocketChannel serverChannel =
- (ServerSocketChannel) key.channel();
- SocketChannel clientChannel = serverChannel.accept();
+ ServerSocketChannel serverChannel = (ServerSocketChannel) key
+ .channel();
+ SocketChannel clientChannel = serverChannel
+ .accept();
LDAPClientConnection clientConnection =
- new LDAPClientConnection(this, clientChannel);
- InetAddress clientAddr=clientConnection.getRemoteAddress();
- // Check to see if the client is on the denied list. If so,
- // then reject it immediately.
- if((deniedClients != null) && (deniedClients.length > 0) &&
- AddressMask.maskListContains(clientAddr.getAddress(),
- clientAddr.getHostName(), deniedClients))
- {
- clientConnection.disconnect(
- DisconnectReason.CONNECTION_REJECTED,
- sendRejectionNotice,
- MSGID_LDAP_CONNHANDLER_DENIED_CLIENT,
- clientConnection.getClientHostPort(),
- clientConnection.getServerHostPort());
+ new LDAPClientConnection(this, clientChannel);
+ InetAddress clientAddr = clientConnection
+ .getRemoteAddress();
+ // Check to see if the client is on the denied list.
+ // If so, then reject it immediately.
+ if ((deniedClients.length > 0)
+ && AddressMask.maskListContains(clientAddr
+ .getAddress(), clientAddr.getHostName(),
+ deniedClients)) {
+ clientConnection.disconnect(
+ DisconnectReason.CONNECTION_REJECTED,
+ currentConfig.isSendRejectionNotice(),
+ MSGID_LDAP_CONNHANDLER_DENIED_CLIENT,
+ clientConnection.getClientHostPort(),
+ clientConnection.getServerHostPort());
- iterator.remove();
- continue;
+ iterator.remove();
+ continue;
}
- // Check to see if there is an allowed list and if there is
- // whether the client is on that list. If not, then reject
- // the connection.
- if((allowedClients != null) && (allowedClients.length > 0) &&
- (!AddressMask.maskListContains(clientAddr.getAddress(),
- clientAddr.getHostName(), allowedClients)))
- {
- clientConnection.disconnect(
- DisconnectReason.CONNECTION_REJECTED,
- sendRejectionNotice,
- MSGID_LDAP_CONNHANDLER_DISALLOWED_CLIENT,
- clientConnection.getClientHostPort(),
- clientConnection.getServerHostPort());
+ // Check to see if there is an allowed list and if
+ // there is whether the client is on that list. If
+ // not, then reject the connection.
+ if ((allowedClients.length > 0)
+ && (!AddressMask.maskListContains(clientAddr
+ .getAddress(), clientAddr.getHostName(),
+ allowedClients))) {
+ clientConnection.disconnect(
+ DisconnectReason.CONNECTION_REJECTED,
+ currentConfig.isSendRejectionNotice(),
+ MSGID_LDAP_CONNHANDLER_DISALLOWED_CLIENT,
+ clientConnection.getClientHostPort(),
+ clientConnection.getServerHostPort());
- iterator.remove();
- continue;
+ iterator.remove();
+ continue;
}
- clientChannel.socket().setKeepAlive(useKeepAlive);
- clientChannel.socket().setTcpNoDelay(useTCPNoDelay);
+ clientChannel.socket().setKeepAlive(
+ currentConfig.isUseTCPKeepAlive());
+ clientChannel.socket().setTcpNoDelay(
+ currentConfig.isUseTCPNoDelay());
try
{
@@ -1510,69 +966,61 @@
}
- // Check to see if the core server rejected the connection
- // (e.g., already too many connections established).
- if (clientConnection.getConnectionID() < 0)
- {
+ // Check to see if the core server rejected the
+ // connection (e.g., already too many connections
+ // established).
+ if (clientConnection.getConnectionID() < 0) {
// The connection will have already been closed.
iterator.remove();
continue;
}
- // If we've gotten here, then we'll take the connection so
- // invoke the post-connect plugins and register the client
- // connection with a request handler.
- try
- {
- PluginConfigManager pluginManager =
- DirectoryServer.getPluginConfigManager();
- PostConnectPluginResult pluginResult =
- pluginManager.invokePostConnectPlugins(
- clientConnection);
- if (pluginResult.connectionTerminated())
- {
+ // If we've gotten here, then we'll take the
+ // connection so invoke the post-connect plugins and
+ // register the client connection with a request
+ // handler.
+ try {
+ PluginConfigManager pluginManager = DirectoryServer
+ .getPluginConfigManager();
+ PostConnectPluginResult pluginResult = pluginManager
+ .invokePostConnectPlugins(clientConnection);
+ if (pluginResult.connectionTerminated()) {
iterator.remove();
continue;
}
LDAPRequestHandler requestHandler =
- requestHandlers[requestHandlerIndex++];
- if (requestHandlerIndex >= numRequestHandlers)
- {
+ requestHandlers[requestHandlerIndex++];
+ if (requestHandlerIndex >= numRequestHandlers) {
requestHandlerIndex = 0;
}
- if (requestHandler.registerClient(clientConnection))
- {
+ if (requestHandler
+ .registerClient(clientConnection)) {
logConnect(clientConnection);
- }
- else
- {
+ } else {
iterator.remove();
continue;
}
- }
- catch (Exception e)
- {
+ } catch (Exception e) {
if (debugEnabled())
{
debugCaught(DebugLogLevel.ERROR, e);
}
int msgID =
- MSGID_LDAP_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT;
- String message =
- getMessage(msgID,
- clientConnection.getClientHostPort(),
- clientConnection.getServerHostPort(),
- stackTraceToSingleLineString(e));
+ MSGID_LDAP_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT;
+ String message = getMessage(msgID,
+ clientConnection.getClientHostPort(),
+ clientConnection.getServerHostPort(),
+ stackTraceToSingleLineString(e));
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.SEVERE_ERROR, message, msgID);
+ ErrorLogSeverity.SEVERE_ERROR, message, msgID);
- clientConnection.disconnect(DisconnectReason.SERVER_ERROR,
- sendRejectionNotice, message,
- msgID);
+ clientConnection.disconnect(
+ DisconnectReason.SERVER_ERROR, currentConfig
+ .isSendRejectionNotice(), message, msgID);
iterator.remove();
continue;
@@ -1581,89 +1029,83 @@
iterator.remove();
}
- }
- else
- {
- if (shutdownRequested)
- {
+ } else {
+ if (shutdownRequested) {
cleanUpSelector();
listening = false;
- enabled = false;
+ enabled = false;
continue;
}
}
lastIterationFailed = false;
- }
- catch (Exception e)
- {
+ } catch (Exception e) {
if (debugEnabled())
{
debugCaught(DebugLogLevel.ERROR, e);
}
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.SEVERE_WARNING,
- MSGID_LDAP_CONNHANDLER_CANNOT_ACCEPT_CONNECTION,
- configEntryDN, stackTraceToSingleLineString(e));
+ ErrorLogSeverity.SEVERE_WARNING,
+ MSGID_LDAP_CONNHANDLER_CANNOT_ACCEPT_CONNECTION,
+ currentConfig.dn(), stackTraceToSingleLineString(e));
- if (lastIterationFailed)
- {
- // The last time through the accept loop we also encountered a
- // failure. Rather than enter a potential infinite loop of
- // failures, disable this acceptor and log an error.
+ if (lastIterationFailed) {
+ // The last time through the accept loop we also
+ // encountered a failure. Rather than enter a potential
+ // infinite loop of failures, disable this acceptor and
+ // log an error.
int msgID = MSGID_LDAP_CONNHANDLER_CONSECUTIVE_ACCEPT_FAILURES;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
+ String message = getMessage(msgID, String
+ .valueOf(currentConfig.dn()),
+ stackTraceToSingleLineString(e));
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.FATAL_ERROR, message, msgID);
+ ErrorLogSeverity.FATAL_ERROR, message, msgID);
- DirectoryServer.sendAlertNotification(this,
- ALERT_TYPE_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES,
- msgID, message);
+ DirectoryServer
+ .sendAlertNotification(
+ this,
+ ALERT_TYPE_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES,
+ msgID, message);
enabled = false;
- try
- {
+ try {
cleanUpSelector();
+ } catch (Exception e2) {
}
- catch (Exception e2)
- {
- }
- }
- else
- {
+ } else {
lastIterationFailed = true;
}
}
}
- }
- catch (Exception e)
- {
+ } catch (Exception e) {
if (debugEnabled())
{
debugCaught(DebugLogLevel.ERROR, e);
}
- // This is very bad because we failed outside the loop. The only
- // thing we can do here is log a message, send an alert, and disable the
- // selector until an administrator can figure out what's going on.
+ // This is very bad because we failed outside the loop. The
+ // only thing we can do here is log a message, send an alert,
+ // and disable the selector until an administrator can figure
+ // out what's going on.
int msgID = MSGID_LDAP_CONNHANDLER_UNCAUGHT_ERROR;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
+ String message = getMessage(msgID, String
+ .valueOf(currentConfig.dn()),
+ stackTraceToSingleLineString(e));
logError(ErrorLogCategory.CONNECTION_HANDLING,
- ErrorLogSeverity.SEVERE_ERROR, message, msgID);
+ ErrorLogSeverity.SEVERE_ERROR, message, msgID);
DirectoryServer.sendAlertNotification(this,
- ALERT_TYPE_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR, msgID, message);
+ ALERT_TYPE_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR, msgID,
+ message);
- try
- {
+ try {
cleanUpSelector();
- } catch (Exception e2) {}
+ } catch (Exception e2) {
+ }
enabled = false;
}
@@ -1673,2151 +1115,66 @@
/**
- * Cleans up the contents of the selector, closing any server socket channels
- * that might be associated with it. Any connections that might have been
- * established through those channels should not be impacted.
+ * Appends a string representation of this connection handler to the
+ * provided buffer.
+ *
+ * @param buffer
+ * The buffer to which the information should be appended.
*/
- private void cleanUpSelector()
- {
- try
- {
- Iterator<SelectionKey> iterator = selector.keys().iterator();
- while (iterator.hasNext())
- {
- SelectionKey key = iterator.next();
-
- try
- {
- key.cancel();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- }
-
- try
- {
- key.channel().close();
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
- }
- }
-
-
-
- /**
- * Indicates whether this connection handler should maintain usage statistics.
- *
- * @return <CODE>true</CODE> if this connection handler should maintain usage
- * statistics, or <CODE>false</CODE> if not.
- */
- public boolean keepStats()
- {
- return keepStats;
- }
-
-
-
- /**
- * Specifies whether this connection handler should maintain usage statistics.
- *
- * @param keepStats Specifies whether this connection handler should
- * maintain usage statistics.
- */
- public void setKeepStats(boolean keepStats)
- {
- this.keepStats = keepStats;
- }
-
-
-
- /**
- * Retrieves the set of statistics maintained by this connection handler.
- *
- * @return The set of statistics maintained by this connection handler.
- */
- public LDAPStatistics getStatTracker()
- {
- return statTracker;
- }
-
-
-
- /**
- * Indicates whether this connection handler should allow interaction with
- * LDAPv2 clients.
- *
- * @return <CODE>true</CODE> if LDAPv2 is allowed, or <CODE>false</CODE> if
- * not.
- */
- public boolean allowLDAPv2()
- {
- return allowLDAPv2;
- }
-
-
-
- /**
- * Indicates whether this connection handler should allow the use of the
- * StartTLS extended operation.
- *
- * @return <CODE>true</CODE> if StartTLS is allowed, or <CODE>false</CODE> if
- * not.
- */
- public boolean allowStartTLS()
- {
- return allowStartTLS;
- }
-
-
-
- /**
- * Indicates whether this connection handler should use SSL to communicate
- * with clients.
- *
- * @return {@code true} if this connection handler should use SSL to
- * communicate with clients, or {@code false} if not.
- */
- public boolean useSSL()
- {
- return useSSL;
- }
-
-
-
- /**
- * Retrieves the SSL client authentication policy for this connection handler.
- *
- * @return The SSL client authentication policy for this connection handler.
- */
- public SSLClientAuthPolicy getSSLClientAuthPolicy()
- {
- return sslClientAuthPolicy;
- }
-
-
-
- /**
- * Retrieves the set of enabled SSL protocols configured for this connection
- * handler.
- *
- * @return The set of enabled SSL protocols configured for this connection
- * handler.
- */
- public String[] getEnabledSSLProtocols()
- {
- return enabledSSLProtocols;
- }
-
-
-
- /**
- * Retrieves the set of enabled SSL cipher suites configured for this
- * connection handler.
- *
- * @return The set of enabled SSL cipher suites configured for this
- * connection handler.
- */
- public String[] getEnabledSSLCipherSuites()
- {
- return enabledSSLCipherSuites;
- }
-
-
-
- /**
- * Retrieves the DN of the key manager provider that should be used for
- * operations associated with this connection handler which need access to a
- * key manager.
- *
- * @return The DN of the key manager provider that should be used for
- * operations associated with this connection handler which need
- * access to a key manager, or {@code null} if no key manager
- * provider has been configured for this connection handler.
- */
- public DN getKeyManagerProviderDN()
- {
- return keyManagerProviderDN;
- }
-
-
-
- /**
- * Retrieves the DN of the trust manager provider that should be used for
- * operations associated with this connection handler which need access to a
- * trust manager.
- *
- * @return The DN of the trust manager provider that should be used for
- * operations associated with this connection handler which need
- * access to a trust manager, or {@code null} if no trust manager
- * provider has been configured for this connection handler.
- */
- public DN getTrustManagerProviderDN()
- {
- return trustManagerProviderDN;
- }
-
-
-
- /**
- * Retrieves the nickname of the server certificate that should be used in
- * conjunction with this LDAP connection handler.
- *
- * @return The nickname of the server certificate that should be used in
- * conjunction with this LDAP connection handler.
- */
- public String getSSLServerCertNickname()
- {
- return sslServerCertNickname;
- }
-
-
-
- /**
- * Retrieves the maximum ASN.1 element value length that will be allowed by
- * this connection handler.
- *
- * @return The maximum ASN.1 element value length that will be allowed by
- * this connection handler.
- */
- public int getMaxRequestSize()
- {
- return maxRequestSize;
- }
-
-
-
- /**
- * Retrieves the human-readable name for this shutdown listener.
- *
- * @return The human-readable name for this shutdown listener.
- */
- public String getShutdownListenerName()
- {
- return handlerName;
- }
-
-
-
- /**
- * Indicates that the Directory Server has received a request to stop running
- * and that this shutdown listener should take any action necessary to prepare
- * for it.
- *
- * @param reason The human-readable reason for the shutdown.
- */
- public void processServerShutdown(String reason)
- {
- shutdownRequested = true;
-
- try
- {
- for (LDAPRequestHandler requestHandler : requestHandlers)
- {
- try
- {
- requestHandler.processServerShutdown(reason);
- } catch (Exception e) {}
- }
- } catch (Exception e) {}
- }
-
-
-
- /**
- * Retrieves the DN of the configuration entry with which this component is
- * associated.
- *
- * @return The DN of the configuration entry with which this component is
- * associated.
- */
- public DN getConfigurableComponentEntryDN()
- {
- return configEntryDN;
- }
-
-
-
- /**
- * Retrieves the set of configuration attributes that are associated with this
- * configurable component.
- *
- * @return The set of configuration attributes that are associated with this
- * configurable component.
- */
- public List<ConfigAttribute> getConfigurationAttributes()
- {
- LinkedList<ConfigAttribute> configAttrs = new LinkedList<ConfigAttribute>();
-
- int msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_ADDRESS;
- ArrayList<String> listenAddressStrings =
- new ArrayList<String>(listenAddresses.size());
- for (InetAddress a : listenAddresses)
- {
- listenAddressStrings.add(a.getHostAddress());
- }
- configAttrs.add(new StringConfigAttribute(ATTR_LISTEN_ADDRESS,
- getMessage(msgID), true, true,
- true, listenAddressStrings));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT;
- configAttrs.add(new IntegerConfigAttribute(ATTR_LISTEN_PORT,
- getMessage(msgID), true, false,
- true, true, 1, true, 65535,
- listenPort));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_BACKLOG;
- configAttrs.add(new IntegerConfigAttribute(ATTR_ACCEPT_BACKLOG,
- getMessage(msgID), true, false,
- true, true, 1, true,
- Integer.MAX_VALUE, backlog));
-
-
- if (allowedClients == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOWED_CLIENTS;
- ArrayList<String> allowedMasks = new ArrayList<String>(0);
- configAttrs.add(new StringConfigAttribute(ATTR_ALLOWED_CLIENT,
- getMessage(msgID), false, true,
- false, allowedMasks));
- }
- else
- {
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOWED_CLIENTS;
- ArrayList<String> allowedMasks =
- new ArrayList<String>(allowedClients.length);
- for (AddressMask m : allowedClients)
- {
- allowedMasks.add(m.toString());
- }
- configAttrs.add(new StringConfigAttribute(ATTR_ALLOWED_CLIENT,
- getMessage(msgID), false, true,
- false, allowedMasks));
- }
-
-
- if (deniedClients == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_DENIED_CLIENTS;
- ArrayList<String> deniedMasks = new ArrayList<String>(0);
- configAttrs.add(new StringConfigAttribute(ATTR_DENIED_CLIENT,
- getMessage(msgID), false, true,
- false, deniedMasks));
- }
- else
- {
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_DENIED_CLIENTS;
- ArrayList<String> deniedMasks =
- new ArrayList<String>(deniedClients.length);
- for (AddressMask m : deniedClients)
- {
- deniedMasks.add(m.toString());
- }
- configAttrs.add(new StringConfigAttribute(ATTR_DENIED_CLIENT,
- getMessage(msgID), false, true,
- false, deniedMasks));
- }
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_LDAPV2;
- configAttrs.add(new BooleanConfigAttribute(ATTR_ALLOW_LDAPV2,
- getMessage(msgID), false,
- allowLDAPv2));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEEP_STATS;
- configAttrs.add(new BooleanConfigAttribute(ATTR_KEEP_LDAP_STATS,
- getMessage(msgID), false,
- keepStats));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_NUM_REQUEST_HANDLERS;
- configAttrs.add(new IntegerConfigAttribute(ATTR_NUM_REQUEST_HANDLERS,
- getMessage(msgID), true, false,
- true, true, 1, false, 0,
- numRequestHandlers));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SEND_REJECTION_NOTICE;
- configAttrs.add(new BooleanConfigAttribute(ATTR_SEND_REJECTION_NOTICE,
- getMessage(msgID), false,
- sendRejectionNotice));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_KEEPALIVE;
- configAttrs.add(new BooleanConfigAttribute(ATTR_USE_TCP_KEEPALIVE,
- getMessage(msgID), false,
- useKeepAlive));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_NODELAY;
- configAttrs.add(new BooleanConfigAttribute(ATTR_USE_TCP_NODELAY,
- getMessage(msgID), false,
- useTCPNoDelay));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_REUSE_ADDRESS;
- configAttrs.add(new BooleanConfigAttribute(ATTR_ALLOW_REUSE_ADDRESS,
- getMessage(msgID), true,
- allowReuseAddress));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_MAX_REQUEST_SIZE;
- configAttrs.add(new IntegerWithUnitConfigAttribute(ATTR_MAX_REQUEST_SIZE,
- getMessage(msgID), false,
- SIZE_UNITS, true, 0,
- true,
- MAX_REQUEST_SIZE_LIMIT,
- maxRequestSize,
- SIZE_UNIT_BYTES_FULL));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_SSL;
- configAttrs.add(new BooleanConfigAttribute(ATTR_USE_SSL, getMessage(msgID),
- true, useSSL));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_STARTTLS;
- configAttrs.add(new BooleanConfigAttribute(ATTR_ALLOW_STARTTLS,
- getMessage(msgID), false,
- allowStartTLS));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_CLIENT_AUTH_POLICY;
- HashSet<String> allowedValues = new HashSet<String>(3);
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.DISABLED.toString()));
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.OPTIONAL.toString()));
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.REQUIRED.toString()));
- configAttrs.add(new MultiChoiceConfigAttribute(ATTR_SSL_CLIENT_AUTH_POLICY,
- getMessage(msgID), false, false, true,
- allowedValues, sslClientAuthPolicy.toString()));
-
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME;
- configAttrs.add(new StringConfigAttribute(ATTR_SSL_CERT_NICKNAME,
- getMessage(msgID), false, false,
- true, sslServerCertNickname));
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_PROTOCOLS;
- configAttrs.add(new StringConfigAttribute(ATTR_SSL_PROTOCOLS,
- getMessage(msgID), false, true, false,
- arrayToList(enabledSSLProtocols)));
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_CIPHERS;
- configAttrs.add(new StringConfigAttribute(ATTR_SSL_CIPHERS,
- getMessage(msgID), false, true, false,
- arrayToList(enabledSSLCipherSuites)));
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN;
- configAttrs.add(new DNConfigAttribute(ATTR_KEYMANAGER_DN, getMessage(msgID),
- false, false, false,
- keyManagerProviderDN));
-
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN;
- configAttrs.add(new DNConfigAttribute(ATTR_TRUSTMANAGER_DN,
- getMessage(msgID), false, false,
- false, trustManagerProviderDN));
-
-
- return configAttrs;
- }
-
-
-
- /**
- * Indicates whether the provided configuration entry has an acceptable
- * configuration for this component. If it does not, then detailed
- * information about the problem(s) should be added to the provided list.
- *
- * @param configEntry The configuration entry for which to make the
- * determination.
- * @param unacceptableReasons A list that can be used to hold messages about
- * why the provided entry does not have an
- * acceptable configuration.
- *
- * @return <CODE>true</CODE> if the provided entry has an acceptable
- * configuration for this component, or <CODE>false</CODE> if not.
- */
- public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
- List<String> unacceptableReasons)
- {
- boolean configValid = true;
-
-
- // Determine the set of addresses on which to listen. There can be
- // multiple addresses specified.
- int msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_ADDRESS;
- StringConfigAttribute addrStub =
- new StringConfigAttribute(ATTR_LISTEN_ADDRESS, getMessage(msgID),
- true, true, false);
- try
- {
- StringConfigAttribute addrAttr =
- (StringConfigAttribute) configEntry.getConfigAttribute(addrStub);
- if ((addrAttr == null) || addrAttr.activeValues().isEmpty())
- {
- // This is fine -- we'll just listen on all IPv4 addresses.
- }
- else
- {
- for (String s : addrAttr.activeValues())
- {
- try
- {
- InetAddress.getByName(s);
- }
- catch (UnknownHostException uhe)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, uhe);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_UNKNOWN_LISTEN_ADDRESS;
- unacceptableReasons.add(getMessage(msgID, s,
- stackTraceToSingleLineString(uhe)));
- configValid = false;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_LISTEN_ADDRESS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the port on which to listen. There may only be a single port
- // specified.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT;
- IntegerConfigAttribute portStub =
- new IntegerConfigAttribute(ATTR_LISTEN_PORT, getMessage(msgID), true,
- false, false, true, 1, true, 65535);
- try
- {
- IntegerConfigAttribute portAttr =
- (IntegerConfigAttribute) configEntry.getConfigAttribute(portStub);
- if (portAttr == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_NO_LISTEN_PORT;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- configValid = false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the accept backlog to use.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_BACKLOG;
- IntegerConfigAttribute backlogStub =
- new IntegerConfigAttribute(ATTR_ACCEPT_BACKLOG, getMessage(msgID),
- true, false, true, true, 1, true,
- Integer.MAX_VALUE);
- try
- {
- IntegerConfigAttribute backlogAttr =
- (IntegerConfigAttribute) configEntry.getConfigAttribute(backlogStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_BACKLOG;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the set of allowed clients.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOWED_CLIENTS;
- StringConfigAttribute allowedStub =
- new StringConfigAttribute(ATTR_ALLOWED_CLIENT, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute allowedAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(allowedStub);
- if (allowedAttr != null)
- {
- for (String s : allowedAttr.activeValues())
- {
- try
- {
- AddressMask.decode(s);
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_ADDRESS_MASK;
- unacceptableReasons.add(getMessage(msgID, s, ATTR_ALLOWED_CLIENT,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(ce)));
- configValid = false;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOWED_CLIENTS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the set of denied clients.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_DENIED_CLIENTS;
- StringConfigAttribute deniedStub =
- new StringConfigAttribute(ATTR_DENIED_CLIENT, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute deniedAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(deniedStub);
- if (deniedAttr != null)
- {
- for (String s : deniedAttr.activeValues())
- {
- try
- {
- AddressMask.decode(s);
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_ADDRESS_MASK;
- unacceptableReasons.add(getMessage(msgID, s, ATTR_DENIED_CLIENT,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(ce)));
- configValid = false;
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_DENIED_CLIENTS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine whether to allow LDAPv2 clients.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_LDAPV2;
- BooleanConfigAttribute allowLDAPv2Stub =
- new BooleanConfigAttribute(ATTR_ALLOW_LDAPV2, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute allowLDAPv2Attr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(allowLDAPv2Stub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_LDAPV2;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine whether to keep LDAP statistics.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEEP_STATS;
- BooleanConfigAttribute keepStatsStub =
- new BooleanConfigAttribute(ATTR_KEEP_LDAP_STATS, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute keepStatsAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(keepStatsStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEEP_STATS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the number of request handlers to maintain.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_NUM_REQUEST_HANDLERS;
- IntegerConfigAttribute reqHandlerStub =
- new IntegerConfigAttribute(ATTR_NUM_REQUEST_HANDLERS,
- getMessage(msgID), true, false, true,
- true, 1, false, 0);
- try
- {
- IntegerConfigAttribute reqHandlerAttr =
- (IntegerConfigAttribute)
- configEntry.getConfigAttribute(reqHandlerStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_NUM_REQUEST_HANDLERS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine whether to send a notice to clients on rejection.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SEND_REJECTION_NOTICE;
- BooleanConfigAttribute notifyRejectsStub =
- new BooleanConfigAttribute(ATTR_SEND_REJECTION_NOTICE,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute notifyRejectsAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(notifyRejectsStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SEND_REJECTION_NOTICE;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine whether to use TCP keepalive.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_KEEPALIVE;
- BooleanConfigAttribute keepAliveStub =
- new BooleanConfigAttribute(ATTR_USE_TCP_KEEPALIVE, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute keepAliveAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(keepAliveStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_KEEPALIVE;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine whether to use TCP nodelay.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_NODELAY;
- BooleanConfigAttribute noDelayStub =
- new BooleanConfigAttribute(ATTR_USE_TCP_NODELAY, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute noDelayAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(noDelayStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_NODELAY;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine whether to allow reuse of address/port combinations.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_REUSE_ADDRESS;
- BooleanConfigAttribute reuseAddrStub =
- new BooleanConfigAttribute(ATTR_ALLOW_REUSE_ADDRESS,
- getMessage(msgID), true);
- try
- {
- BooleanConfigAttribute reuseAddrAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(reuseAddrStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_REUSE_ADDRESS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the maximum allowed request size.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_MAX_REQUEST_SIZE;
- IntegerWithUnitConfigAttribute maxReqSizeStub =
- new IntegerWithUnitConfigAttribute(ATTR_MAX_REQUEST_SIZE,
- getMessage(msgID), false,
- SIZE_UNITS, true, 0, true,
- MAX_REQUEST_SIZE_LIMIT);
- try
- {
- IntegerWithUnitConfigAttribute maxReqSizeAttr =
- (IntegerWithUnitConfigAttribute)
- configEntry.getConfigAttribute(maxReqSizeStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_MAX_REQUEST_SIZE;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine whether to use SSL.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_SSL;
- boolean tmpUseSSL;
- BooleanConfigAttribute useSSLStub =
- new BooleanConfigAttribute(ATTR_USE_SSL, getMessage(msgID), true);
- try
- {
- BooleanConfigAttribute useSSLAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(useSSLStub);
- if (useSSLAttr == null)
- {
- tmpUseSSL = DEFAULT_USE_SSL;
- }
- else
- {
- tmpUseSSL = useSSLAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_SSL;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- tmpUseSSL = DEFAULT_USE_SSL;
- }
-
-
- // Determine whether to allow the StartTLS extended operation.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_STARTTLS;
- BooleanConfigAttribute startTLSStub =
- new BooleanConfigAttribute(ATTR_ALLOW_STARTTLS, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute startTLSAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(startTLSStub);
- boolean tmpAllowStartTLS;
- if (startTLSAttr == null)
- {
- // This is fine -- we'll just use the default.
- tmpAllowStartTLS = DEFAULT_ALLOW_STARTTLS;
- }
- else
- {
- tmpAllowStartTLS = startTLSAttr.activeValue();
- }
-
-
- // See if both SSL and startTLS are configured. If so, we'll have to
- // disable startTLS because they can't both be used concurrently.
- if (tmpUseSSL && tmpAllowStartTLS)
- {
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_HAVE_SSL_AND_STARTTLS;
- unacceptableReasons.add(getMessage(msgID,
- String.valueOf(configEntryDN)));
- configValid = false;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_STARTTLS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine how to handle SSL client authentication.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_CLIENT_AUTH_POLICY;
- HashSet<String> allowedValues = new HashSet<String>(3);
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.DISABLED.toString()));
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.OPTIONAL.toString()));
- allowedValues.add(toLowerCase(SSLClientAuthPolicy.REQUIRED.toString()));
- MultiChoiceConfigAttribute sslAuthPolicyStub =
- new MultiChoiceConfigAttribute(ATTR_SSL_CLIENT_AUTH_POLICY,
- getMessage(msgID), false, false, true,
- allowedValues);
- try
- {
- MultiChoiceConfigAttribute sslAuthPolicyAttr =
- (MultiChoiceConfigAttribute)
- configEntry.getConfigAttribute(sslAuthPolicyStub);
- if (sslAuthPolicyAttr == null)
- {
- // This is fine -- We'll just use the default.
- }
- else
- {
- SSLClientAuthPolicy tmpPolicy = SSLClientAuthPolicy.policyForName(
- sslAuthPolicyAttr.activeValue());
- if (tmpPolicy == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_SSL_CLIENT_AUTH_POLICY;
- unacceptableReasons.add(getMessage(msgID,
- sslAuthPolicyAttr.activeValue(),
- String.valueOf(configEntryDN)));
- configValid = false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CLIENT_AUTH_POLICY;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine which SSL certificate to use.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME;
- StringConfigAttribute certNameStub =
- new StringConfigAttribute(ATTR_SSL_CERT_NICKNAME, getMessage(msgID),
- false, false, true);
- try
- {
- StringConfigAttribute certNameAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(certNameStub);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the set of SSL protocols to allow.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_PROTOCOLS;
- StringConfigAttribute sslProtocolsStub =
- new StringConfigAttribute(ATTR_SSL_PROTOCOLS, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute sslProtocolsAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(sslProtocolsStub);
- // FIXME -- Is there a good way to determine the set of supported
- // protocols to validate what the user has provided?
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_PROTOCOLS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the set of SSL cipher suites to allow.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_CIPHERS;
- StringConfigAttribute sslCiphersStub =
- new StringConfigAttribute(ATTR_SSL_CIPHERS, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute sslCiphersAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(sslCiphersStub);
- // FIXME -- Is there a good way to determine the set of supported cipher
- // suites to validate what the user has provided?
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CIPHERS;
- unacceptableReasons.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- configValid = false;
- }
-
-
- // Determine the key manager provider to use.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN;
- DNConfigAttribute keyManagerStub =
- new DNConfigAttribute(ATTR_KEYMANAGER_DN, getMessage(msgID), false,
- false, false);
- try
- {
- DNConfigAttribute keyManagerAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(keyManagerStub);
- if (keyManagerAttr != null)
- {
- DN keyManagerProviderDN = keyManagerAttr.activeValue();
- KeyManagerProvider provider =
- DirectoryServer.getKeyManagerProvider(keyManagerProviderDN);
- if (provider == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_KEYMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(keyManagerProviderDN));
- unacceptableReasons.add(message);
- configValid = false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- configValid = false;
- }
-
-
- // Determine the trust manager provider to use.
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN;
- DNConfigAttribute trustManagerStub =
- new DNConfigAttribute(ATTR_TRUSTMANAGER_DN, getMessage(msgID), false,
- false, false);
- try
- {
- DNConfigAttribute trustManagerAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(trustManagerStub);
- if (trustManagerAttr != null)
- {
- DN trustManagerProviderDN = trustManagerAttr.activeValue();
- TrustManagerProvider provider =
- DirectoryServer.getTrustManagerProvider(trustManagerProviderDN);
- if (provider == null)
- {
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_TRUSTMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(trustManagerProviderDN));
- unacceptableReasons.add(message);
- configValid = false;
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_TRUSTMANAGER_DN;
- String message = getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e));
- unacceptableReasons.add(message);
- configValid = false;
- }
-
-
- return configValid;
- }
-
-
-
- /**
- * Makes a best-effort attempt to apply the configuration contained in the
- * provided entry. Information about the result of this processing should be
- * added to the provided message list. Information should always be added to
- * this list if a configuration change could not be applied. If detailed
- * results are requested, then information about the changes applied
- * successfully (and optionally about parameters that were not changed) should
- * also be included.
- *
- * @param configEntry The entry containing the new configuration to
- * apply for this component.
- * @param detailedResults Indicates whether detailed information about the
- * processing should be added to the list.
- *
- * @return Information about the result of the configuration update.
- */
- public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
- boolean detailedResults)
- {
- // Create variables to include in the response.
- ResultCode resultCode = ResultCode.SUCCESS;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
-
- // The set of addresses and the port on which to listen are not dynamically
- // reconfigurable, so we can skip them.
-
-
- // The backlog is not dynamically reconfigurable, so we can skip it.
-
-
- // Determine the set of allowed clients.
- HashSet<AddressMask> newAllowedClients = null;
- int msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOWED_CLIENTS;
- StringConfigAttribute allowedStub =
- new StringConfigAttribute(ATTR_ALLOWED_CLIENT, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute allowedAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(allowedStub);
- if (allowedAttr != null)
- {
- newAllowedClients = new HashSet<AddressMask>();
-
- for (String s : allowedAttr.pendingValues())
- {
- try
- {
- newAllowedClients.add(AddressMask.decode(s));
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_ADDRESS_MASK;
- messages.add(getMessage(msgID, s, ATTR_ALLOWED_CLIENT,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(ce)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- }
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOWED_CLIENTS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
- boolean allowedClientsChanged = false;
- if (resultCode == ResultCode.SUCCESS)
- {
- if ((allowedClients == null) || (allowedClients.length == 0))
- {
- allowedClientsChanged = (! ((newAllowedClients == null) ||
- newAllowedClients.isEmpty()));
- }
- else if ((newAllowedClients == null) || newAllowedClients.isEmpty())
- {
- allowedClientsChanged = true;
- }
- else if (allowedClients.length != newAllowedClients.size())
- {
- allowedClientsChanged = true;
- }
- else
- {
- for (AddressMask m : allowedClients)
- {
- if (! newAllowedClients.contains(m))
- {
- allowedClientsChanged = true;
- break;
- }
- }
- }
- }
-
-
- // Determine the set of denied clients.
- HashSet<AddressMask> newDeniedClients = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_DENIED_CLIENTS;
- StringConfigAttribute deniedStub =
- new StringConfigAttribute(ATTR_DENIED_CLIENT, getMessage(msgID),
- false, true, false);
- try
- {
- StringConfigAttribute deniedAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(deniedStub);
- if (deniedAttr != null)
- {
- newDeniedClients = new HashSet<AddressMask>();
-
- for (String s : deniedAttr.pendingValues())
- {
- try
- {
- newDeniedClients.add(AddressMask.decode(s));
- }
- catch (ConfigException ce)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, ce);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_ADDRESS_MASK;
- messages.add(getMessage(msgID, s, ATTR_DENIED_CLIENT,
- String.valueOf(configEntryDN),
- stackTraceToSingleLineString(ce)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.INVALID_ATTRIBUTE_SYNTAX;
- }
- }
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_DENIED_CLIENTS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
- }
-
- boolean deniedClientsChanged = false;
- if (resultCode == ResultCode.SUCCESS)
- {
- if ((deniedClients == null) || (deniedClients.length == 0))
- {
- deniedClientsChanged = (! ((newDeniedClients == null) ||
- newDeniedClients.isEmpty()));
- }
- else if ((newDeniedClients == null) || newDeniedClients.isEmpty())
- {
- deniedClientsChanged = true;
- }
- else if (deniedClients.length != newDeniedClients.size())
- {
- deniedClientsChanged = true;
- }
- else
- {
- for (AddressMask m : deniedClients)
- {
- if (! newDeniedClients.contains(m))
- {
- deniedClientsChanged = true;
- break;
- }
- }
- }
- }
-
-
- // Determine whether to allow LDAPv2 clients.
- boolean newAllowLDAPv2;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_LDAPV2;
- BooleanConfigAttribute allowLDAPv2Stub =
- new BooleanConfigAttribute(ATTR_ALLOW_LDAPV2, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute allowLDAPv2Attr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(allowLDAPv2Stub);
- if (allowLDAPv2Attr == null)
- {
- newAllowLDAPv2 = DEFAULT_ALLOW_LDAPV2;
- }
- else
- {
- newAllowLDAPv2 = allowLDAPv2Attr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_LDAPV2;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newAllowLDAPv2 = DEFAULT_ALLOW_LDAPV2;
- }
-
-
- // Determine whether to keep LDAP statistics.
- boolean newKeepStats;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEEP_STATS;
- BooleanConfigAttribute keepStatsStub =
- new BooleanConfigAttribute(ATTR_KEEP_LDAP_STATS, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute keepStatsAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(keepStatsStub);
- if (keepStatsAttr == null)
- {
- newKeepStats = DEFAULT_KEEP_LDAP_STATS;
- }
- else
- {
- newKeepStats = keepStatsAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEEP_STATS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newKeepStats = DEFAULT_KEEP_LDAP_STATS;
- }
-
-
- // The number of request handlers to maintain is not dynamically
- // reconfigurable, so we can skip it.
-
-
- // Determine whether to send a notice to clients on rejection.
- boolean newSendRejectionNotice;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SEND_REJECTION_NOTICE;
- BooleanConfigAttribute notifyRejectsStub =
- new BooleanConfigAttribute(ATTR_SEND_REJECTION_NOTICE,
- getMessage(msgID), false);
- try
- {
- BooleanConfigAttribute notifyRejectsAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(notifyRejectsStub);
- if (notifyRejectsAttr == null)
- {
- newSendRejectionNotice = DEFAULT_SEND_REJECTION_NOTICE;
- }
- else
- {
- newSendRejectionNotice = notifyRejectsAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SEND_REJECTION_NOTICE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newSendRejectionNotice = DEFAULT_SEND_REJECTION_NOTICE;
- }
-
-
- // Determine whether to use TCP keepalive.
- boolean newUseKeepAlive;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_KEEPALIVE;
- BooleanConfigAttribute keepAliveStub =
- new BooleanConfigAttribute(ATTR_USE_TCP_KEEPALIVE, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute keepAliveAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(keepAliveStub);
- if (keepAliveAttr == null)
- {
- newUseKeepAlive = DEFAULT_USE_TCP_KEEPALIVE;
- }
- else
- {
- newUseKeepAlive = keepAliveAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_KEEPALIVE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newUseKeepAlive = DEFAULT_USE_TCP_KEEPALIVE;
- }
-
-
- // Determine whether to use TCP nodelay.
- boolean newUseTCPNoDelay;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_NODELAY;
- BooleanConfigAttribute noDelayStub =
- new BooleanConfigAttribute(ATTR_USE_TCP_NODELAY, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute noDelayAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(noDelayStub);
- if (noDelayAttr == null)
- {
- newUseTCPNoDelay = DEFAULT_USE_TCP_NODELAY;
- }
- else
- {
- newUseTCPNoDelay = noDelayAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_NODELAY;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newUseTCPNoDelay = DEFAULT_USE_TCP_NODELAY;
- }
-
-
- // The reuse address option isn't dynamically reconfigurable, so we can skip
- // it.
-
-
- // Determine the maximum allowed request size.
- int newMaxRequestSize;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_MAX_REQUEST_SIZE;
- IntegerWithUnitConfigAttribute maxReqSizeStub =
- new IntegerWithUnitConfigAttribute(ATTR_MAX_REQUEST_SIZE,
- getMessage(msgID), false,
- SIZE_UNITS, true, 0, true,
- MAX_REQUEST_SIZE_LIMIT);
- try
- {
- IntegerWithUnitConfigAttribute maxReqSizeAttr =
- (IntegerWithUnitConfigAttribute)
- configEntry.getConfigAttribute(maxReqSizeStub);
- if (maxReqSizeAttr == null)
- {
- newMaxRequestSize = DEFAULT_MAX_REQUEST_SIZE;
- }
- else
- {
- newMaxRequestSize = (int) maxReqSizeAttr.pendingCalculatedValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_MAX_REQUEST_SIZE;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newMaxRequestSize = DEFAULT_MAX_REQUEST_SIZE;
- }
-
-
- // The flag specifying whether to use SSL is not dynamically reconfigurable,
- // so we can skip it.
-
-
- // Determine whether to allow the StartTLS extended operation.
- boolean newAllowStartTLS;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_STARTTLS;
- BooleanConfigAttribute startTLSStub =
- new BooleanConfigAttribute(ATTR_ALLOW_STARTTLS, getMessage(msgID),
- false);
- try
- {
- BooleanConfigAttribute startTLSAttr =
- (BooleanConfigAttribute)
- configEntry.getConfigAttribute(startTLSStub);
- if (startTLSAttr == null)
- {
- // This is fine -- we'll just use the default.
- newAllowStartTLS = DEFAULT_ALLOW_STARTTLS;
- }
- else
- {
- newAllowStartTLS = startTLSAttr.pendingValue();
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_STARTTLS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newAllowStartTLS = DEFAULT_ALLOW_STARTTLS;
- }
-
-
- // The SSL client authentication policy and SSL certificate nickname are not
- // dynamically reconfigurable, so we can skip them.
-
-
- // Determine the set of SSL protocols to allow.
- String[] newSSLProtocols;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_PROTOCOLS;
- StringConfigAttribute sslProtocolsStub =
- new StringConfigAttribute(ATTR_SSL_PROTOCOLS, getMessage(msgID), false,
- true, false);
- try
- {
- StringConfigAttribute sslProtocolsAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(sslProtocolsStub);
- if (sslProtocolsAttr == null)
- {
- newSSLProtocols = null;
- }
- else
- {
- // FIXME -- Is there a good way to validate the provided set of values?
- newSSLProtocols = listToArray(sslProtocolsAttr.pendingValues());
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_PROTOCOLS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newSSLProtocols = null;
- }
-
-
-
- // Determine the set of SSL cipher suites to allow.
- String[] newSSLCiphers;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_CIPHERS;
- StringConfigAttribute sslCiphersStub =
- new StringConfigAttribute(ATTR_SSL_CIPHERS, getMessage(msgID), false,
- true, false);
- try
- {
- StringConfigAttribute sslCiphersAttr =
- (StringConfigAttribute)
- configEntry.getConfigAttribute(sslCiphersStub);
- if (sslCiphersAttr == null)
- {
- newSSLCiphers = null;
- }
- else
- {
- // FIXME -- Is there a good way to validate the provided set of values?
- newSSLCiphers = listToArray(sslCiphersAttr.pendingValues());
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CIPHERS;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = DirectoryServer.getServerErrorResultCode();
- }
-
- newSSLCiphers = null;
- }
-
-
- // Determine the key manager provider to use.
- DN newKeyManagerDN = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN;
- DNConfigAttribute keyManagerStub =
- new DNConfigAttribute(ATTR_KEYMANAGER_DN, getMessage(msgID), false,
- false, false);
- try
- {
- DNConfigAttribute keyManagerAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(keyManagerStub);
- if (keyManagerAttr != null)
- {
- newKeyManagerDN = keyManagerAttr.activeValue();
- KeyManagerProvider provider =
- DirectoryServer.getKeyManagerProvider(newKeyManagerDN);
- if (provider == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_KEYMANAGER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(newKeyManagerDN)));
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
-
- // Determine the trust manager provider to use.
- DN newTrustManagerDN = null;
- msgID = MSGID_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN;
- DNConfigAttribute trustManagerStub =
- new DNConfigAttribute(ATTR_TRUSTMANAGER_DN, getMessage(msgID), false,
- false, false);
- try
- {
- DNConfigAttribute trustManagerAttr =
- (DNConfigAttribute) configEntry.getConfigAttribute(trustManagerStub);
- if (trustManagerAttr != null)
- {
- newTrustManagerDN = trustManagerAttr.activeValue();
- TrustManagerProvider provider =
- DirectoryServer.getTrustManagerProvider(newTrustManagerDN);
- if (provider == null)
- {
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_INVALID_TRUSTMANAGER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- String.valueOf(newTrustManagerDN)));
- }
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- debugCaught(DebugLogLevel.ERROR, e);
- }
-
- if (resultCode == ResultCode.SUCCESS)
- {
- resultCode = ResultCode.CONSTRAINT_VIOLATION;
- }
-
- msgID = MSGID_LDAP_CONNHANDLER_CANNOT_DETERMINE_TRUSTMANAGER_DN;
- messages.add(getMessage(msgID, String.valueOf(configEntryDN),
- stackTraceToSingleLineString(e)));
- }
-
-
- // If the provided configuration is acceptable, then apply it.
- if (resultCode == ResultCode.SUCCESS)
- {
- if (allowedClientsChanged)
- {
- AddressMask[] newAllowedArray;
- if ((newAllowedClients == null) || newAllowedClients.isEmpty())
- {
- newAllowedArray = null;
- }
- else
- {
- newAllowedArray = new AddressMask[newAllowedClients.size()];
- newAllowedClients.toArray(newAllowedArray);
- }
-
- allowedClients = newAllowedArray;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_ALLOWED_CLIENTS,
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (deniedClientsChanged)
- {
- AddressMask[] newDeniedArray;
- if ((newDeniedClients == null) || newDeniedClients.isEmpty())
- {
- newDeniedArray = null;
- }
- else
- {
- newDeniedArray = new AddressMask[newDeniedClients.size()];
- newDeniedClients.toArray(newDeniedArray);
- }
-
- deniedClients = newDeniedArray;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_DENIED_CLIENTS,
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (allowLDAPv2 != newAllowLDAPv2)
- {
- allowLDAPv2 = newAllowLDAPv2;
- if (allowLDAPv2)
- {
- if (statTracker == null)
- {
- statTracker = new LDAPStatistics(handlerName + " Statistics");
- }
- else
- {
- statTracker.clearStatistics();
- }
- }
-
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_ALLOW_LDAPV2,
- String.valueOf(newAllowLDAPv2),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (keepStats != newKeepStats)
- {
- keepStats = newKeepStats;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_KEEP_STATS,
- String.valueOf(newKeepStats),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (sendRejectionNotice != newSendRejectionNotice)
- {
- sendRejectionNotice = newSendRejectionNotice;
- if (detailedResults)
- {
- messages.add(getMessage(
- MSGID_LDAP_CONNHANDLER_NEW_SEND_REJECTION_NOTICE,
- String.valueOf(newSendRejectionNotice),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (useKeepAlive != newUseKeepAlive)
- {
- useKeepAlive = newUseKeepAlive;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_USE_KEEPALIVE,
- String.valueOf(newUseKeepAlive),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (useTCPNoDelay != newUseTCPNoDelay)
- {
- useTCPNoDelay = newUseTCPNoDelay;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_USE_TCP_NODELAY,
- String.valueOf(newUseTCPNoDelay),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (maxRequestSize != newMaxRequestSize)
- {
- maxRequestSize = newMaxRequestSize;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_MAX_REQUEST_SIZE,
- String.valueOf(newMaxRequestSize),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- if (allowStartTLS != newAllowStartTLS)
- {
- allowStartTLS = newAllowStartTLS;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_ALLOW_STARTTLS,
- String.valueOf(newAllowStartTLS),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- // Update enabled SSL protocols.
- if (! Arrays.equals(enabledSSLProtocols, newSSLProtocols))
- {
- enabledSSLProtocols = newSSLProtocols;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_SSL_PROTOCOLS,
- Arrays.toString(newSSLProtocols),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- // Update enabled SSL cipher suites.
- if (! Arrays.equals(enabledSSLCipherSuites, newSSLCiphers))
- {
- enabledSSLCipherSuites = newSSLCiphers;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_SSL_CIPHERS,
- Arrays.toString(newSSLCiphers),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- // Update the key manager provider DN.
- if (keyManagerProviderDN == null)
- {
- if (newKeyManagerDN != null)
- {
- keyManagerProviderDN = newKeyManagerDN;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_KEYMANAGER_DN,
- String.valueOf(newKeyManagerDN),
- String.valueOf(configEntryDN)));
- }
- }
- }
- else if ((newKeyManagerDN == null) ||
- (! keyManagerProviderDN.equals(newKeyManagerDN)))
- {
- keyManagerProviderDN = newKeyManagerDN;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_KEYMANAGER_DN,
- String.valueOf(newKeyManagerDN),
- String.valueOf(configEntryDN)));
- }
- }
-
-
- // Update the trust manager provider DN.
- if (trustManagerProviderDN == null)
- {
- if (newTrustManagerDN != null)
- {
- trustManagerProviderDN = newTrustManagerDN;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_TRUSTMANAGER_DN,
- String.valueOf(newTrustManagerDN),
- String.valueOf(configEntryDN)));
- }
- }
- }
- else if ((newTrustManagerDN == null) ||
- (! trustManagerProviderDN.equals(newTrustManagerDN)))
- {
- trustManagerProviderDN = newTrustManagerDN;
- if (detailedResults)
- {
- messages.add(getMessage(MSGID_LDAP_CONNHANDLER_NEW_TRUSTMANAGER_DN,
- String.valueOf(newTrustManagerDN),
- String.valueOf(configEntryDN)));
- }
- }
- }
-
-
- return new ConfigChangeResult(resultCode, adminActionRequired, messages);
- }
-
-
- /**
- * Appends a string representation of this connection handler to the provided
- * buffer.
- *
- * @param buffer The buffer to which the information should be appended.
- */
- public void toString(StringBuilder buffer)
- {
+ public void toString(StringBuilder buffer) {
buffer.append(handlerName);
}
/**
- * Retrieves the DN of the configuration entry with which this alert generator
- * is associated.
+ * Indicates whether this connection handler should use SSL to
+ * communicate with clients.
*
- * @return The DN of the configuration entry with which this alert generator
- * is associated.
+ * @return {@code true} if this connection handler should use SSL to
+ * communicate with clients, or {@code false} if not.
*/
- public DN getComponentEntryDN()
- {
- return configEntryDN;
+ public boolean useSSL() {
+ return currentConfig.isUseSSL();
}
/**
- * Retrieves the fully-qualified name of the Java class for this alert
- * generator implementation.
- *
- * @return The fully-qualified name of the Java class for this alert
- * generator implementation.
+ * Cleans up the contents of the selector, closing any server socket
+ * channels that might be associated with it. Any connections that
+ * might have been established through those channels should not be
+ * impacted.
*/
- public String getClassName()
- {
- return CLASS_NAME;
- }
+ private void cleanUpSelector() {
+ try {
+ Iterator<SelectionKey> iterator = selector.keys().iterator();
+ while (iterator.hasNext()) {
+ SelectionKey key = iterator.next();
+ try {
+ key.cancel();
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
-
- /**
- * Retrieves information about the set of alerts that this generator may
- * produce. The map returned should be between the notification type for a
- * particular notification and the human-readable description for that
- * notification. This alert generator must not generate any alerts with types
- * that are not contained in this list.
- *
- * @return Information about the set of alerts that this generator may
- * produce.
- */
- public LinkedHashMap<String,String> getAlerts()
- {
- LinkedHashMap<String,String> alerts = new LinkedHashMap<String,String>();
-
- alerts.put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES,
- ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES);
- alerts.put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR,
- ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR);
-
- return alerts;
+ try {
+ key.channel().close();
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
+ }
+ } catch (Exception e) {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ }
}
}
-
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AdminTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AdminTestCase.java
new file mode 100644
index 0000000..3460d5f
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AdminTestCase.java
@@ -0,0 +1,38 @@
+/*
+ * 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.admin;
+
+import org.opends.server.DirectoryServerTestCase;
+import org.testng.annotations.Test;
+
+/**
+ * An abstract class that all admin unit tests should extend.
+ */
+@Test(groups = { "precommit", "admin" })
+public abstract class AdminTestCase extends DirectoryServerTestCase {
+ // No implementation required.
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AttributeTypePropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AttributeTypePropertyDefinitionTest.java
new file mode 100644
index 0000000..168bb9b
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AttributeTypePropertyDefinitionTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.admin;
+
+
+
+import static org.testng.Assert.assertEquals;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.AttributeType;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * AttributeTypePropertyDefinition Tester.
+ */
+public class AttributeTypePropertyDefinitionTest {
+
+ /**
+ * Sets up tests.
+ *
+ * @throws Exception
+ * If the server could not be started.
+ */
+ @BeforeClass
+ public void setUp() throws Exception {
+ // This test suite depends on having the schema available, so
+ // we'll start the server.
+ TestCaseUtils.startServer();
+ }
+
+
+
+ /**
+ * Tests validateValue() with valid data
+ */
+ @Test
+ public void testValidateValue() {
+ AttributeTypePropertyDefinition.setCheckSchema(true);
+ AttributeTypePropertyDefinition d = createPropertyDefinition();
+ d.validateValue(DirectoryServer.getAttributeType("cn"));
+ }
+
+
+
+ /**
+ * @return data for testing
+ */
+ @DataProvider(name = "testDecodeValueLegalData")
+ public Object[][] createValidateValueLegalData() {
+ return new Object[][] { { "cn" }, { "o" }, { "ou" } };
+ }
+
+
+
+ /**
+ * Tests decodeValue()
+ *
+ * @param value
+ * to decode
+ */
+ @Test(dataProvider = "testDecodeValueLegalData")
+ public void testDecodeValue(String value) {
+ AttributeTypePropertyDefinition.setCheckSchema(true);
+ AttributeTypePropertyDefinition d = createPropertyDefinition();
+ AttributeType expected = DirectoryServer.getAttributeType(value);
+ assertEquals(d.decodeValue(value), expected);
+ }
+
+
+
+ /**
+ * @return data for testing illegal values
+ */
+ @DataProvider(name = "testDecodeValueIllegalData")
+ public Object[][] createValidateValueIllegalData() {
+ return new Object[][] { { "dummy-type-xxx" } };
+ }
+
+
+
+ /**
+ * Tests decodeValue() with illegal data
+ *
+ * @param value
+ * to decode
+ */
+ @Test(dataProvider = "testDecodeValueIllegalData", expectedExceptions = { IllegalPropertyValueStringException.class })
+ public void testDecodeValue2(String value) {
+ AttributeTypePropertyDefinition.setCheckSchema(true);
+ AttributeTypePropertyDefinition d = createPropertyDefinition();
+ d.decodeValue(value);
+ }
+
+
+
+ /**
+ * Tests decodeValue() with illegal data with schema checking off.
+ *
+ * @param value
+ * to decode
+ */
+ @Test(dataProvider = "testDecodeValueIllegalData")
+ public void testDecodeValue3(String value) {
+ AttributeTypePropertyDefinition.setCheckSchema(false);
+ AttributeTypePropertyDefinition d = createPropertyDefinition();
+ AttributeType type = d.decodeValue(value);
+ assertEquals(type.getNameOrOID(), value);
+ }
+
+
+
+ // Create a new definition.
+ private AttributeTypePropertyDefinition createPropertyDefinition() {
+ AttributeTypePropertyDefinition.Builder builder = AttributeTypePropertyDefinition
+ .createBuilder("test-property");
+ return builder.getInstance();
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/BooleanPropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/BooleanPropertyDefinitionTest.java
new file mode 100644
index 0000000..49da174
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/BooleanPropertyDefinitionTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+
+import java.util.EnumSet;
+
+/**
+ * BooleanPropertyDefinition Tester.
+ */
+public class BooleanPropertyDefinitionTest {
+
+ BooleanPropertyDefinition.Builder builder = null;
+
+ /**
+ * Sets up tests
+ */
+ @BeforeClass
+ public void setUp() {
+ builder = BooleanPropertyDefinition.createBuilder("test-property");
+ }
+
+ /**
+ * Tests validateValue() with valid data
+ */
+ @Test
+ public void testValidateValue1() {
+ BooleanPropertyDefinition d = createPropertyDefinition();
+ d.validateValue(Boolean.TRUE);
+ }
+
+ /**
+ * Tests validateValue() with illegal data
+ */
+ @Test(expectedExceptions = AssertionError.class)
+ public void testValidateValue2() {
+ BooleanPropertyDefinition d = createPropertyDefinition();
+ d.validateValue(null);
+ }
+
+ /**
+ * @return data for testing
+ */
+ @DataProvider(name = "testDecodeValueData")
+ public Object[][] createvalidateValueData() {
+ return new Object[][]{
+ {"0", Boolean.FALSE},
+ {"no", Boolean.FALSE},
+ {"off", Boolean.FALSE},
+ {"false", Boolean.FALSE},
+ {"disable", Boolean.FALSE},
+ {"disabled", Boolean.FALSE},
+ {"1", Boolean.TRUE},
+ {"yes", Boolean.TRUE},
+ {"on", Boolean.TRUE},
+ {"true", Boolean.TRUE},
+ {"enable", Boolean.TRUE},
+ {"enabled", Boolean.TRUE},
+ };
+ }
+
+ /**
+ * Tests decodeValue()
+ * @param value to decode
+ * @param expected value
+ */
+ @Test(dataProvider = "testDecodeValueData")
+ public void testDecodeValue(String value, Boolean expected) {
+ BooleanPropertyDefinition d = createPropertyDefinition();
+ assertEquals(d.decodeValue(value), expected);
+ }
+
+ /**
+ * @return data for testing illegal values
+ */
+ @DataProvider(name = "testDecodeValueData2")
+ public Object[][] createvalidateValueData2() {
+ return new Object[][]{
+ {null},{"abc"}
+ };
+ }
+
+ /**
+ * Tests decodeValue() with illegal data
+ * @param value to decode
+ */
+ @Test(dataProvider = "testDecodeValueData2",
+ expectedExceptions = {AssertionError.class,IllegalPropertyValueStringException.class})
+ public void testDecodeValue2(String value) {
+ BooleanPropertyDefinition d = createPropertyDefinition();
+ d.decodeValue(value);
+ }
+
+ private BooleanPropertyDefinition createPropertyDefinition() {
+ return builder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<Boolean>());
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ClassPropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ClassPropertyDefinitionTest.java
new file mode 100644
index 0000000..ea2686b
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ClassPropertyDefinitionTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+
+import java.util.EnumSet;
+import java.util.List;
+
+/**
+ * ClassPropertyDefinition Tester.
+ */
+public class ClassPropertyDefinitionTest {
+
+ ClassPropertyDefinition.Builder builder = null;
+
+ /**
+ * Sets up tests
+ */
+ @BeforeClass
+ public void setUp() {
+ ClassPropertyDefinition.setAllowClassValidation(true);
+ }
+
+ /**
+ * @return data for testing
+ */
+ @DataProvider(name = "testBuilderAddInstanceOf")
+ public Object[][] createBuilderAddInstanceOfData() {
+ return new Object[][]{
+ { "java.awt.Container" },
+ { "java.awt.Container$1" },
+ { "java.awt.Container$2$1" },
+ { "java.awt.Container$2" },
+ { "java.awt.Container$AccessibleAWTContainer$AccessibleContainerHandler" },
+ { "java.awt.Container$DropTargetEventTargetFilter" },
+ { "java.awt.Container$EventTargetFilter" },
+ { "java.awt.Container$MouseEventTargetFilter" },
+ { "java.awt.Container$WakingRunnable" },
+ { "java.awt.Container$AccessibleAWTContainer" }
+ };
+ }
+
+ /**
+ * Tests builder.addInstanceOf with valid data
+ * @param className name of class name to add
+ */
+ @Test(dataProvider = "testBuilderAddInstanceOf")
+ public void testBuilderAddInstanceOf(String className) {
+ ClassPropertyDefinition.Builder localBuilder =
+ ClassPropertyDefinition.createBuilder("test-property");
+ localBuilder.addInstanceOf(className);
+ ClassPropertyDefinition cpd = localBuilder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<String>());
+ List<String> instances = cpd.getInstanceOfInterface();
+ assertTrue(instances.contains(className));
+ }
+
+ /**
+ * @return data for testing with illegal values
+ */
+ @DataProvider(name = "testBuilderAddInstanceOf2")
+ public Object[][] createBuilderAddInstanceOfData2() {
+ return new Object[][]{
+ { "1" },
+ { "abc." },
+ { "abc.123" },
+ { "abc.123$" },
+ };
+ }
+
+ /**
+ * Tests builder.addInstanceOf with valid data
+ * @param className name of class to add
+ */
+ @Test(dataProvider = "testBuilderAddInstanceOf2",
+ expectedExceptions = {IllegalArgumentException.class})
+ public void testBuilderAddInstanceOf2(String className) {
+ ClassPropertyDefinition.Builder localBuilder =
+ ClassPropertyDefinition.createBuilder("test-property");
+ localBuilder.addInstanceOf(className);
+ ClassPropertyDefinition cpd = localBuilder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<String>());
+ List<String> instances = cpd.getInstanceOfInterface();
+ assertTrue(instances.contains(className));
+ }
+
+ /**
+ * @return data for testing with illegal values
+ */
+ @DataProvider(name = "testLoadClassData")
+ public Object[][] createTestLoadData() {
+ return new Object[][]{
+ { "java.io.Serializable",
+ "java.lang.String",
+ Object.class,
+ String.class },
+ { "java.io.Serializable",
+ "java.lang.String",
+ String.class,
+ String.class },
+ { "java.lang.Number", // abstract class
+ "java.lang.Long",
+ Number.class,
+ Long.class },
+ };
+ }
+
+ @Test(dataProvider = "testLoadClassData")
+ public <T> void testLoadClass(String interfaceName, String loadClassName,
+ Class<T> instanceOfClass, Class expectedClass) {
+ ClassPropertyDefinition.Builder localBuilder =
+ ClassPropertyDefinition.createBuilder("test-property");
+ localBuilder.addInstanceOf(interfaceName);
+ ClassPropertyDefinition cpd = localBuilder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<String>());
+ Class clazz = cpd.loadClass(loadClassName, instanceOfClass);
+ assertEquals(clazz, expectedClass);
+ }
+
+ /**
+ * @return data for testing with illegal values
+ */
+ @DataProvider(name = "testLoadClassData2")
+ public Object[][] createTestLoadData2() {
+ return new Object[][]{
+ { "java.lang.Runnable",
+ "java.lang.String",
+ Object.class,
+ String.class },
+ { "java.lang.Runnable",
+ "some.bogus.ClassName",
+ Object.class,
+ String.class },
+ { "java.lang.Runnable",
+ "java.lang.String",
+ Number.class,
+ Number.class },
+ };
+ }
+
+ @Test(dataProvider = "testLoadClassData2",
+ expectedExceptions = {IllegalPropertyValueException.class})
+ public <T> void testLoadClass2(String interfaceName, String loadClassName,
+ Class<T> instanceOfClass, Class expectedClass) {
+ ClassPropertyDefinition.Builder localBuilder =
+ ClassPropertyDefinition.createBuilder("test-property");
+ localBuilder.addInstanceOf(interfaceName);
+ ClassPropertyDefinition cpd = localBuilder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<String>());
+ Class clazz = cpd.loadClass(loadClassName, instanceOfClass);
+ assertEquals(clazz, String.class);
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DNPropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DNPropertyDefinitionTest.java
new file mode 100644
index 0000000..9136d16
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DNPropertyDefinitionTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.admin;
+
+
+
+import static org.testng.Assert.assertEquals;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * ClassPropertyDefinition Tester.
+ */
+public class DNPropertyDefinitionTest {
+
+ /**
+ * Sets up tests
+ *
+ * @throws Exception
+ * If the server could not be initialized.
+ */
+ @BeforeClass
+ public void setUp() throws Exception {
+ // This test suite depends on having the schema available, so
+ // we'll start the server.
+ TestCaseUtils.startServer();
+ }
+
+
+
+ /**
+ * @return data for testing
+ */
+ @DataProvider(name = "testBuilderSetBaseDN")
+ public Object[][] createBuilderSetBaseDN() {
+ return new Object[][] { { null },
+ { "cn=key manager providers, cn=config" } };
+ }
+
+
+
+ /**
+ * Tests builder.setBaseDN with valid data.
+ *
+ * @param baseDN
+ * The base DN.
+ * @throws DirectoryException
+ * If the DN could not be decoded.
+ */
+ @Test(dataProvider = "testBuilderSetBaseDN")
+ public void testBuilderSetBaseDN(String baseDN)
+ throws DirectoryException {
+ DNPropertyDefinition.Builder localBuilder = DNPropertyDefinition
+ .createBuilder("test-property");
+ localBuilder.setBaseDN(baseDN);
+ DNPropertyDefinition pd = localBuilder.getInstance();
+
+ DN actual = pd.getBaseDN();
+ DN expected = baseDN == null ? null : DN.decode(baseDN);
+
+ assertEquals(actual, expected);
+ }
+
+
+
+ /**
+ * @return data for testing
+ */
+ @DataProvider(name = "testLegalValues")
+ public Object[][] createLegalValues() {
+ return new Object[][] {
+ { null, "cn=config" },
+ { null, "dc=example,dc=com" },
+ { "", "cn=config" },
+ { "cn=config", "cn=key manager providers, cn=config" },
+ { "cn=key manager providers, cn=config",
+ "cn=my provider, cn=key manager providers, cn=config" }, };
+ }
+
+
+
+ /**
+ * @return data for testing
+ */
+ @DataProvider(name = "testIllegalValues")
+ public Object[][] createIllegalValues() {
+ return new Object[][] {
+ // Above base DN.
+ { "cn=config", "" },
+
+ // Same as base DN.
+ { "cn=config", "cn=config" },
+
+ // Same as base DN.
+ { "cn=key manager providers, cn=config",
+ "cn=key manager providers, cn=config" },
+
+ // Too far beneath base DN.
+ { "cn=config",
+ "cn=my provider, cn=key manager providers, cn=config" },
+
+ // Unrelated to base DN.
+ { "cn=config", "dc=example, dc=com" }, };
+ }
+
+
+
+ /**
+ * Tests validation with valid data.
+ *
+ * @param baseDN
+ * The base DN.
+ * @param value
+ * The value to be validated.
+ * @throws DirectoryException
+ * If the DN could not be decoded.
+ */
+ @Test(dataProvider = "testLegalValues")
+ public void testValidateLegalValues(String baseDN, String value)
+ throws DirectoryException {
+ DNPropertyDefinition.Builder localBuilder = DNPropertyDefinition
+ .createBuilder("test-property");
+ localBuilder.setBaseDN(baseDN);
+ DNPropertyDefinition pd = localBuilder.getInstance();
+ pd.validateValue(DN.decode(value));
+ }
+
+
+
+ /**
+ * Tests validation with invalid data.
+ *
+ * @param baseDN
+ * The base DN.
+ * @param value
+ * The value to be validated.
+ * @throws DirectoryException
+ * If the DN could not be decoded.
+ */
+ @Test(dataProvider = "testIllegalValues", expectedExceptions = IllegalPropertyValueException.class)
+ public void testValidateIllegalValues(String baseDN, String value)
+ throws DirectoryException {
+ DNPropertyDefinition.Builder localBuilder = DNPropertyDefinition
+ .createBuilder("test-property");
+ localBuilder.setBaseDN(baseDN);
+ DNPropertyDefinition pd = localBuilder.getInstance();
+ pd.validateValue(DN.decode(value));
+ }
+
+
+
+ /**
+ * Tests decoding with valid data.
+ *
+ * @param baseDN
+ * The base DN.
+ * @param value
+ * The value to be validated.
+ */
+ @Test(dataProvider = "testLegalValues")
+ public void testDecodeLegalValues(String baseDN, String value) {
+ DNPropertyDefinition.Builder localBuilder = DNPropertyDefinition
+ .createBuilder("test-property");
+ localBuilder.setBaseDN(baseDN);
+ DNPropertyDefinition pd = localBuilder.getInstance();
+ pd.decodeValue(value);
+ }
+
+
+
+ /**
+ * Tests validation with invalid data.
+ *
+ * @param baseDN
+ * The base DN.
+ * @param value
+ * The value to be validated.
+ */
+ @Test(dataProvider = "testIllegalValues", expectedExceptions = IllegalPropertyValueStringException.class)
+ public void testDecodeIllegalValues(String baseDN, String value) {
+ DNPropertyDefinition.Builder localBuilder = DNPropertyDefinition
+ .createBuilder("test-property");
+ localBuilder.setBaseDN(baseDN);
+ DNPropertyDefinition pd = localBuilder.getInstance();
+ pd.decodeValue(value);
+ }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationPropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationPropertyDefinitionTest.java
new file mode 100644
index 0000000..6264dc9
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationPropertyDefinitionTest.java
@@ -0,0 +1,450 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+
+import java.util.EnumSet;
+
+/**
+ * DurationPropertyDefinition Tester.
+ */
+public class DurationPropertyDefinitionTest {
+
+ /**
+ * Tests creation of builder succeeds
+ */
+ @Test
+ public void testCreateBuilder() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ assertNotNull(builder);
+ }
+
+ /**
+ * Tests setting/getting of lower limit as long
+ */
+ @Test
+ public void testLowerLimit1() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit((long) 1);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == 1;
+ }
+
+ /**
+ * Creates data for testing string-based limit values
+ * @return data
+ */
+ @DataProvider(name = "longLimitData")
+ public Object[][] createlongLimitData() {
+ return new Object[][]{
+ {1L, 1L},
+ // { null, 0 }
+ };
+ }
+
+ /**
+ * Creates data for testing limit values
+ * @return data
+ */
+ @DataProvider(name = "illegalLimitData")
+ public Object[][] createIllegalLimitData() {
+ return new Object[][]{
+ {-1L, 0L, true}, // lower, upper, lower first
+ {0L, -1L, false},
+ {2L, 1L, true},
+ {2L, 1L, false}
+ };
+ }
+
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param limit unit limit
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "longLimitData")
+ public void testLowerLimit2(long limit, Long expectedValue) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(limit);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == expectedValue;
+ }
+
+ /**
+ * Tests setting/getting of lower limit as long
+ */
+ @Test
+ public void testUpperLimit1() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit((long) 1);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == 1;
+ }
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param limit upper limit
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "longLimitData")
+ public void testUpperLimit2(long limit, long expectedValue) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setUpperLimit(limit);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getUpperLimit().equals(expectedValue);
+ }
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param upper upper limit
+ * @param lower lower limit
+ * @param lowerFirst when true sets the lower limit property first
+ */
+ @Test(dataProvider = "illegalLimitData", expectedExceptions = IllegalArgumentException.class)
+ public void testIllegalLimits(long lower, long upper, boolean lowerFirst) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ if (lowerFirst) {
+ builder.setLowerLimit(lower);
+ builder.setUpperLimit(upper);
+ } else {
+ builder.setUpperLimit(upper);
+ builder.setLowerLimit(lower);
+ }
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test
+ public void testIsAllowUnlimited1() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.decodeValue("unlimited");
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test(expectedExceptions = IllegalPropertyValueStringException.class)
+ public void testIsAllowUnlimited2() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(false);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.decodeValue("unlimited");
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test(expectedExceptions = IllegalPropertyValueException.class)
+ public void testIsAllowUnlimited3() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(false);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(-1L);
+ }
+
+ /**
+ * Creates illegal data for validate value
+ * @return data
+ */
+ @DataProvider(name = "validateValueData")
+ public Object[][] createvalidateValueData() {
+ return new Object[][]{
+ {5L, 10L, false, 7L},
+ {5L, null, true, -1L},
+ {5L, 10L, false, 5L},
+ {5L, 10L, false, 10L},
+ {5L, null, false, 10000L}
+ };
+ }
+
+ /**
+ * Tests that validateValue works
+ * @param allowUnlimited when true allows unlimited
+ * @param high upper limit
+ * @param low lower limit
+ * @param value to validate
+ */
+ @Test(dataProvider = "validateValueData")
+ public void testValidateValue1(Long low, Long high, boolean allowUnlimited, Long value) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(low);
+ builder.setUpperLimit(high);
+ builder.setAllowUnlimited(allowUnlimited);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(value);
+ }
+
+ /**
+ * Creates illegal data for validate value
+ * @return data
+ */
+ @DataProvider(name = "illegalValidateValueData")
+ public Object[][] createIllegalValidateValueData() {
+ return new Object[][]{
+ {5L, 10L, false, null},
+ {5L, 10L, false, 1L},
+ {5L, 10L, false, 11L},
+ {5L, 10L, false, -1L}
+ };
+ }
+
+ /**
+ * Tests that validateValue throws exceptions
+ * @param low lower limit
+ * @param high upper limit
+ * @param allowUnlimited when true allows unlimited
+ * @param value to validate
+ */
+ @Test(dataProvider = "illegalValidateValueData",
+ expectedExceptions = {AssertionError.class,NullPointerException.class,IllegalPropertyValueException.class})
+ public void testValidateValue2(Long low, Long high, boolean allowUnlimited, Long value) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(low);
+ builder.setUpperLimit(high);
+ builder.setAllowUnlimited(allowUnlimited);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(value);
+ }
+
+ /**
+ * Creates encode test data
+ * @return data
+ */
+ @DataProvider(name = "encodeValueData")
+ public Object[][] createEncodeValueData() {
+ return new Object[][]{
+ {-1L, "unlimited"},
+ {0L, "0s"},
+ {1L, "1s"},
+ {2L, "2s"},
+ {999L, "999s"},
+ {1000L, "1000s"},
+ {1001L, "1001s"},
+ {1023L, "1023s"},
+ {1024L, "1024s"},
+ {1025L, "1025s"},
+ {1000L * 1000L, "1000000s"},
+ };
+ }
+
+ /**
+ * Tests encode value
+ * @param value to encode
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "encodeValueData")
+ public void testEncodeValue(Long value, String expectedValue) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ assertEquals(spd.encodeValue(value), expectedValue);
+ }
+
+ /**
+ * Test that accept doesn't throw and exception
+ */
+ @Test
+ public void testAccept() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+
+ PropertyDefinitionVisitor<Boolean, Void> v = new AbstractPropertyDefinitionVisitor<Boolean, Void>() {
+
+ public Boolean visitDuration(DurationPropertyDefinition d,
+ Void o) {
+ return true;
+ }
+
+ public Boolean visitUnknown(PropertyDefinition d, Void o)
+ throws UnknownPropertyDefinitionException {
+ return false;
+ }
+
+ };
+
+ assertEquals((boolean) spd.accept(v, null), true);
+ }
+
+ /**
+ * Make sure toString doesn't barf
+ */
+ @Test
+ public void testToString() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.toString();
+ }
+
+ /**
+ * Make sure toString doesn't barf
+ */
+ @Test
+ public void testToString2() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setUpperLimit(10L);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.toString();
+ }
+
+ /**
+ * Test value comparisons.
+ */
+ @Test
+ public void testCompare() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.compare(1L, 2L);
+ }
+
+ /**
+ * Test setting a default behavior provider.
+ */
+ @Test
+ public void testSetDefaultBehaviorProvider() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ builder.setDefaultBehaviorProvider(new DefaultBehaviorProvider<Long>() {
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<Long, R, P> v, P p) {
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Test setting a property option.
+ */
+ @Test
+ public void testSetOption() {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setOption(PropertyOption.HIDDEN);
+ }
+
+ /**
+ * Creates encode test data
+ * @return data
+ */
+ @DataProvider(name = "decodeValueData")
+ public Object[][] createDecodeValueData() {
+ return new Object[][]{
+ // syntax tests
+ {"unlimited", -1L},
+ {"0h", 0L},
+ {"0.h", 0L},
+ {"0.0h", 0L},
+ {"0.00h", 0L},
+ {"0 h", 0L},
+ {"0. h", 0L},
+ {"0.00 h", 0L},
+ {"1h", 1L},
+ {"1.h", 1L},
+ {"1.1h", 1L},
+ {"1 h", 1L},
+ {"1. h", 1L},
+ {"1.1 h", 1L},
+
+ // conversion tests
+ {"1 d", 24L},
+ {"2 d", 48L},
+ {"0.5 d", 12L}
+ };
+ }
+
+ /**
+ * Tests decodeValue()
+ * @param value to decode
+ * @param expectedValue for comparison
+ */
+ @Test(dataProvider = "decodeValueData")
+ public void testDecodeValue(String value, Long expectedValue) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ builder.setBaseUnit(DurationUnit.HOURS);
+ builder.setMaximumUnit(DurationUnit.DAYS);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+// if (spd.decodeValue(value) != expectedValue) {
+// System.out.println(spd.decodeValue(value) + "!=" + expectedValue);
+// }
+ assert(spd.decodeValue(value) == expectedValue);
+ }
+
+ /**
+ * Creates encode test data
+ * @return data
+ */
+ @DataProvider(name = "decodeValueData2")
+ public Object[][] createDecodeValueData2() {
+ return new Object[][]{
+ {"a s"},
+ {"1 x"},
+ {"30 m"}, // unit too small violation
+ {"60 m"}, // unit too small violation
+ {"1 w"}, // unit too big violation
+ {"7 w"}, // unit too big violation
+ {"1 x"},
+ {"1 d"}, // upper limit violation
+ {"2 h"}, // lower limit violation
+ {"-1 h"} // unlimited violation
+ };
+ }
+
+ /**
+ * Tests decodeValue()
+ * @param value to decode
+ */
+ @Test(dataProvider = "decodeValueData2",
+ expectedExceptions = {IllegalPropertyValueStringException.class})
+ public void testDecodeValue(String value) {
+ DurationPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(false);
+ builder.setBaseUnit(DurationUnit.HOURS);
+ builder.setMaximumUnit(DurationUnit.DAYS);
+ builder.setLowerLimit(5L);
+ builder.setUpperLimit(10L);
+ DurationPropertyDefinition spd = buildTestDefinition(builder);
+ spd.decodeValue(value);
+ }
+
+ private DurationPropertyDefinition.Builder createTestBuilder() {
+ return DurationPropertyDefinition.createBuilder("test-property-name");
+ }
+
+ private DurationPropertyDefinition buildTestDefinition(DurationPropertyDefinition.Builder builder) {
+ return builder.buildInstance("test-prop",
+ EnumSet.noneOf(PropertyOption.class),
+ new DefinedDefaultBehaviorProvider<Long>("0"));
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationUnitTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationUnitTest.java
new file mode 100644
index 0000000..367cfab
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/DurationUnitTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.admin;
+
+import static org.opends.server.admin.DurationUnit.*;
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+
+/**
+ * DurationUnit Tester.
+ */
+public class DurationUnitTest {
+
+ /**
+ * @return test data for testing getUnit
+ */
+ @DataProvider(name = "testGetUnitData")
+ public Object[][] createStringToSizeLimitData() {
+ return new Object[][]{
+ { "ms", MILLI_SECONDS },
+ { "milliseconds", MILLI_SECONDS },
+ { "s", SECONDS },
+ { "seconds", SECONDS },
+ { "m", MINUTES },
+ { "minutes", MINUTES },
+ { "h", HOURS },
+ { "hours", HOURS },
+ { "d", DAYS },
+ { "days", DAYS },
+ { "w", WEEKS },
+ { "weeks", WEEKS }
+ };
+ }
+
+
+ /**
+ * Tests getUnit()
+ * @param unitString for creating a duration unit
+ * @param unit for comparison
+ */
+ @Test(dataProvider = "testGetUnitData")
+ public void testGetUnit1(String unitString, DurationUnit unit) {
+ assertEquals(getUnit(unitString), unit);
+ }
+
+ /**
+ * Tests that getUnit() throws an exception of non-duration unit strings
+ */
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testGetUnit2() {
+ getUnit("xxx");
+ }
+
+ /**
+ * @return test data for testing getUnit
+ */
+ @DataProvider(name = "testGetBestFitUnit")
+ public Object[][] createGetBestFitData() {
+ return new Object[][]{
+ { MINUTES, 0, MINUTES },
+ { MINUTES, .5D, SECONDS },
+ { MINUTES, 119D, MINUTES },
+ { MINUTES, 120D, HOURS },
+ { MINUTES, 121D, MINUTES },
+ { MINUTES, Double.MAX_VALUE, MINUTES },
+ { MINUTES, Double.MIN_VALUE, MINUTES }
+ };
+ }
+
+ /**
+ * @param unit of best fit value
+ * @param value ordinal value
+ * @param expectedValue for comparison
+ */
+ @Test(dataProvider = "testGetBestFitUnit")
+ public void testGetBestFitUnit(DurationUnit unit, double value, DurationUnit expectedValue) {
+ assertEquals(unit.getBestFitUnit(value), expectedValue);
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/EnumPropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/EnumPropertyDefinitionTest.java
new file mode 100644
index 0000000..e04a805
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/EnumPropertyDefinitionTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+
+import java.util.EnumSet;
+
+/**
+ * EnumPropertyDefinition Tester.
+ */
+public class EnumPropertyDefinitionTest {
+
+ private enum TestEnum { ONE, TWO, THREE }
+
+ private EnumPropertyDefinition.Builder<TestEnum> builder = null;
+
+ @BeforeClass
+ public void setUp() {
+ builder = EnumPropertyDefinition.createBuilder("test-property");
+ builder.setEnumClass(TestEnum.class);
+ }
+
+ @Test
+ public void testCreateBuilder() {
+ assertNotNull(builder);
+ }
+
+ /**
+ * Tests that exception thrown when no enum class
+ * specified by builder
+ */
+ @Test
+ public void testBuildInstance() {
+ EnumPropertyDefinition epd = builder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<TestEnum>());
+ assertEquals(epd.getEnumClass(), TestEnum.class);
+ }
+
+ /**
+ * Tests that exception thrown when no enum class
+ * specified by builder
+ */
+ @Test(expectedExceptions = {IllegalStateException.class})
+ public void testBuildInstance2() {
+ EnumPropertyDefinition.Builder<TestEnum> localBuilder =
+ EnumPropertyDefinition.createBuilder("test-property");
+ localBuilder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<TestEnum>());
+ }
+
+ /**
+ * Creates data decodeValue test
+ * @return data
+ */
+ @DataProvider(name = "decodeValueData")
+ public Object[][] createDecodeValueData() {
+ return new Object[][]{
+ { "ONE", TestEnum.ONE }
+ };
+ }
+
+ /**
+ * Tests decodeValue()
+ * @param value to decode
+ * @param expectedValue enum expected
+ */
+ @Test(dataProvider = "decodeValueData")
+ public void testDecodeValue(String value, TestEnum expectedValue) {
+ EnumPropertyDefinition epd = builder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<TestEnum>());
+ assertEquals(epd.decodeValue(value), expectedValue);
+ }
+
+ /**
+ * Creates illegal data for decode value test
+ * @return data
+ */
+ @DataProvider(name = "decodeValueData2")
+ public Object[][] createDecodeValueData2() {
+ return new Object[][]{
+ { "xxx" },
+ { null }
+ };
+ }
+
+ /**
+ * Tests decodeValue()
+ * @param value to decode
+ */
+ @Test(dataProvider = "decodeValueData2",
+ expectedExceptions = {AssertionError.class,
+ IllegalPropertyValueStringException.class} )
+ public void testDecodeValue2(String value) {
+ EnumPropertyDefinition epd = builder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<TestEnum>());
+ epd.decodeValue(value);
+ }
+
+ /**
+ * Tests normalization
+ */
+ @Test
+ public void testNormalizeValue() {
+ EnumPropertyDefinition<TestEnum> epd = builder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<TestEnum>());
+ assertEquals(epd.normalizeValue(TestEnum.ONE), "one");
+ }
+
+ /**
+ * Tests validation
+ */
+ @Test
+ public void testValidateValue() {
+ EnumPropertyDefinition<TestEnum> epd = builder.buildInstance("test-property",
+ EnumSet.noneOf(PropertyOption.class),
+ new UndefinedDefaultBehaviorProvider<TestEnum>());
+ epd.validateValue(TestEnum.ONE);
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/IntegerPropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/IntegerPropertyDefinitionTest.java
new file mode 100644
index 0000000..45e7584
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/IntegerPropertyDefinitionTest.java
@@ -0,0 +1,336 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+
+import org.testng.annotations.*;
+
+import java.util.EnumSet;
+
+/**
+ * IntegerPropertyDefinition Tester.
+ */
+public class IntegerPropertyDefinitionTest {
+
+ /**
+ * Tests creation of builder succeeds
+ */
+ @Test
+ public void testCreateBuilder() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ assertNotNull(builder);
+ }
+
+ /**
+ * Tests setting/getting of lower limit as long
+ */
+ @Test
+ public void testLowerLimit1() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(1);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == 1;
+ }
+
+ /**
+ * Creates data for testing string-based limit values
+ * @return data
+ */
+ @DataProvider(name = "limitData")
+ public Object[][] createlimitData() {
+ return new Object[][]{
+ {1, 1},
+ // { null, 0 }
+ };
+ }
+
+ /**
+ * Creates data for testing limit values
+ * @return data
+ */
+ @DataProvider(name = "illegalLimitData")
+ public Object[][] createIllegalLimitData() {
+ return new Object[][]{
+ {-1, 0, true}, // lower, upper, lower first
+ {0, -1, false},
+ {2, 1, true},
+ {2, 1, false}
+ };
+ }
+
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param limit unit limit
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "limitData")
+ public void testLowerLimit2(int limit, int expectedValue) {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(limit);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == expectedValue;
+ }
+
+ /**
+ * Tests setting/getting of lower limit as long
+ */
+ @Test
+ public void testUpperLimit1() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(1);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == 1;
+ }
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param limit upper limit
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "limitData")
+ public void testUpperLimit2(int limit, int expectedValue) {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setUpperLimit(limit);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getUpperLimit().equals(expectedValue);
+ }
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param upper upper limit
+ * @param lower lower limit
+ * @param lowerFirst when true sets the lower limit property first
+ */
+ @Test(dataProvider = "illegalLimitData", expectedExceptions = IllegalArgumentException.class)
+ public void testIllegalLimits(int lower, int upper, boolean lowerFirst) {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ if (lowerFirst) {
+ builder.setLowerLimit(lower);
+ builder.setUpperLimit(upper);
+ } else {
+ builder.setUpperLimit(upper);
+ builder.setLowerLimit(lower);
+ }
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test
+ public void testIsAllowUnlimited1() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ spd.decodeValue("unlimited");
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test(expectedExceptions = IllegalPropertyValueStringException.class)
+ public void testIsAllowUnlimited2() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(false);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ spd.decodeValue("unlimited");
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test(expectedExceptions = IllegalPropertyValueException.class)
+ public void testIsAllowUnlimited3() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(false);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(-1);
+ }
+
+ /**
+ * Creates illegal data for validate value
+ * @return data
+ */
+ @DataProvider(name = "validateValueData")
+ public Object[][] createvalidateValueData() {
+ return new Object[][]{
+ {5, 10, false, 7},
+ {5, null, true, -1},
+ {5, 10, true, -1},
+ };
+ }
+
+ /**
+ * Tests that validateValue works
+ * @param value to validate
+ * @param allowUnlimited when true allows unlimited
+ * @param high upper limit
+ * @param low lower limit
+ */
+ @Test(dataProvider = "validateValueData")
+ public void testValidateValue1(Integer low, Integer high, boolean allowUnlimited, Integer value) {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(low);
+ builder.setUpperLimit(high);
+ builder.setAllowUnlimited(allowUnlimited);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(value);
+ }
+
+ /**
+ * Creates illegal data for validate value
+ * @return data
+ */
+ @DataProvider(name = "illegalValidateValueData")
+ public Object[][] createIllegalValidateValueData() {
+ return new Object[][]{
+ {5, 10, false, null},
+ {5, 10, false, 1},
+ {5, 10, false, 11},
+ {5, 10, false, -1},
+ {5, 10, true, 2},
+ {5, 10, true, 11}
+ };
+ }
+
+ /**
+ * Tests that validateValue throws exceptions
+ * @param value to validate
+ * @param low lower limit
+ * @param high upper limit
+ * @param allowUnlimited when true allows unlimited
+ */
+ @Test(dataProvider = "illegalValidateValueData",
+ expectedExceptions = {AssertionError.class,NullPointerException.class,IllegalPropertyValueException.class})
+ public void testValidateValue2(Integer low, Integer high, boolean allowUnlimited, Integer value) {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(low);
+ builder.setUpperLimit(high);
+ builder.setAllowUnlimited(allowUnlimited);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(value);
+ }
+
+ /**
+ * Creates encode test data
+ * @return data
+ */
+ @DataProvider(name = "encodeValueData")
+ public Object[][] createEncodeValueData() {
+ return new Object[][]{
+ {-1, "unlimited"},
+ {1, "1"},
+ };
+ }
+
+ /**
+ * Tests encode value
+ * @param value to encode
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "encodeValueData")
+ public void testEncodeValue(Integer value, String expectedValue) {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ assertEquals(spd.encodeValue(value), expectedValue);
+ }
+
+ /**
+ * Test that accept doesn't throw and exception
+ */
+ @Test
+ public void testAccept() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ PropertyDefinitionVisitor<Boolean, Void> v = new AbstractPropertyDefinitionVisitor<Boolean, Void>() {
+
+ public Boolean visitInteger(IntegerPropertyDefinition d,
+ Void o) {
+ return true;
+ }
+
+ public Boolean visitUnknown(PropertyDefinition d, Void o)
+ throws UnknownPropertyDefinitionException {
+ return false;
+ }
+
+ };
+
+ assertEquals((boolean) spd.accept(v, null), true);
+ }
+
+ /**
+ * Make sure toString doesn't barf
+ */
+ @Test
+ public void testToString() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ spd.toString();
+ }
+
+ @Test
+ public void testCompare() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ IntegerPropertyDefinition spd = buildTestDefinition(builder);
+ spd.compare(1, 2);
+ }
+
+ @Test
+ public void testSetDefaultBehaviorProvider() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ builder.setDefaultBehaviorProvider(new DefaultBehaviorProvider<Integer>() {
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<Integer, R, P> v, P p) {
+ return null;
+ }
+ });
+ }
+
+ @Test
+ public void testSetOption() {
+ IntegerPropertyDefinition.Builder builder = createTestBuilder();
+ builder.setOption(PropertyOption.HIDDEN);
+ }
+
+ private IntegerPropertyDefinition.Builder createTestBuilder() {
+ return IntegerPropertyDefinition.createBuilder("test-property-name");
+ }
+
+ private IntegerPropertyDefinition buildTestDefinition(IntegerPropertyDefinition.Builder builder) {
+ return builder.buildInstance("test-prop",
+ EnumSet.noneOf(PropertyOption.class),
+ new DefinedDefaultBehaviorProvider<Integer>("0"));
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/LDAPProfileTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/LDAPProfileTest.java
new file mode 100644
index 0000000..408b072
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/LDAPProfileTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+import org.opends.server.admin.std.meta.GlobalCfgDefn;
+
+import java.util.List;
+
+/**
+ * LDAPProfile Tester.
+ */
+public class LDAPProfileTest {
+
+ /**
+ * Tests execution of getObjectClasses() and makes sure the
+ * returned list contains "top"
+ */
+ @Test
+ public void testGetObjectClasses() {
+ LDAPProfile lp = LDAPProfile.getInstance();
+ List<String> ocs = lp.getObjectClasses(GlobalCfgDefn.getInstance());
+ assertTrue(ocs.contains("top"));
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResourceTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResourceTest.java
new file mode 100644
index 0000000..0005d00
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ManagedObjectDefinitionI18NResourceTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+import org.opends.server.admin.std.meta.GlobalCfgDefn;
+
+import java.util.Locale;
+
+/**
+ * ManagedObjectDefinitionI18NResource Tester.
+ */
+public class ManagedObjectDefinitionI18NResourceTest {
+ ManagedObjectDefinitionI18NResource modr = null;
+
+ /**
+ * Creates the resource
+ */
+ @BeforeClass
+ public void setUp() {
+ modr = ManagedObjectDefinitionI18NResource.createForProfile("ldap");
+ }
+
+ /**
+ * Tests ability to get a message
+ */
+ @Test
+ public void testGetMessage() {
+
+ // Ideally we should test getting messages with arguments
+ // but I couldn't find any existing properties files with
+ // args
+
+ assertNotNull(modr.getMessage(
+ GlobalCfgDefn.getInstance(),
+ "objectclass",
+ Locale.getDefault()));
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
new file mode 100644
index 0000000..cc4043d
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProviderTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeClass;
+
+/**
+ * RelativeInheritedDefaultBehaviorProvider Tester.
+ */
+public class RelativeInheritedDefaultBehaviorProviderTest {
+
+ static private final String PROPERTY_NAME = "test-property";
+ static private final int OFFSET = 0;
+
+ private RelativeInheritedDefaultBehaviorProvider<Object> ridbp = null;
+
+ @BeforeClass
+ public void setUp() {
+ this.ridbp = new RelativeInheritedDefaultBehaviorProvider<Object>(OFFSET, PROPERTY_NAME);
+ }
+
+ @Test
+ public void testAccept() {
+ ridbp.accept(new DefaultBehaviorProviderVisitor<Object,Object,Object>(){
+
+ public Object visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider d, Object o) {
+ return null;
+ }
+
+ public Object visitAlias(AliasDefaultBehaviorProvider d, Object o) {
+ return null;
+ }
+
+ public Object visitDefined(DefinedDefaultBehaviorProvider d, Object o) {
+ return null;
+ }
+
+ public Object visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider d, Object o) {
+ return null;
+ }
+
+ public Object visitUndefined(UndefinedDefaultBehaviorProvider d, Object o) {
+ return null;
+ }
+ }, new Object());
+ }
+
+ @Test
+ public void testGetManagedObjectPath() {
+ ridbp.getManagedObjectPath(ManagedObjectPath.emptyPath());
+ }
+
+ @Test
+ public void testGetPropertyName() {
+ assertEquals(ridbp.getPropertyName(), PROPERTY_NAME);
+ }
+
+ @Test
+ public void testGetRelativeOffset() {
+ assertEquals(ridbp.getRelativeOffset(), OFFSET);
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java
new file mode 100644
index 0000000..95d0cc5
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizePropertyDefinitionTest.java
@@ -0,0 +1,349 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.EnumSet;
+
+/**
+ * SizePropertyDefinition Tester.
+ */
+public class SizePropertyDefinitionTest {
+
+ /**
+ * Tests creation of builder succeeds
+ */
+ @Test
+ public void testCreateBuilder() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ assertNotNull(builder);
+ }
+
+ /**
+ * Tests setting/getting of lower limit as long
+ */
+ @Test
+ public void testLowerLimit1() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit((long) 1);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == 1;
+ }
+
+ /**
+ * Creates data for testing string-based limit values
+ * @return data
+ */
+ @DataProvider(name = "stringLimitData")
+ public Object[][] createStringLimitData() {
+ return new Object[][]{
+ {"1 b", 1L},
+ // { null, 0 }
+ };
+ }
+
+ /**
+ * Creates data for testing limit values
+ * @return data
+ */
+ @DataProvider(name = "illegalLimitData")
+ public Object[][] createIllegalLimitData() {
+ return new Object[][]{
+ {-1L, 0L, true}, // lower, upper, lower first
+ {0L, -1L, false},
+ {2L, 1L, true},
+ {2L, 1L, false}
+ };
+ }
+
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param limit unit limit
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "stringLimitData")
+ public void testLowerLimit2(String limit, Long expectedValue) {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(limit);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == expectedValue;
+ }
+
+ /**
+ * Tests setting/getting of lower limit as long
+ */
+ @Test
+ public void testUpperLimit1() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit((long) 1);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getLowerLimit() == 1;
+ }
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param limit upper limit
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "stringLimitData")
+ public void testUpperLimit2(String limit, long expectedValue) {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setUpperLimit(limit);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ assert spd.getUpperLimit().equals(expectedValue);
+ }
+
+ /**
+ * Tests setting/getting of lower limit as String
+ * @param upper upper limit
+ * @param lower lower limit
+ * @param lowerFirst when true sets the lower limit property first
+ */
+ @Test(dataProvider = "illegalLimitData", expectedExceptions = IllegalArgumentException.class)
+ public void testIllegalLimits(long lower, long upper, boolean lowerFirst) {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ if (lowerFirst) {
+ builder.setLowerLimit(lower);
+ builder.setUpperLimit(upper);
+ } else {
+ builder.setUpperLimit(upper);
+ builder.setLowerLimit(lower);
+ }
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test
+ public void testIsAllowUnlimited1() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ spd.decodeValue("unlimited");
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test(expectedExceptions = IllegalPropertyValueStringException.class)
+ public void testIsAllowUnlimited2() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(false);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ spd.decodeValue("unlimited");
+ }
+
+ /**
+ * Tests the allowUnlimited property
+ */
+ @Test(expectedExceptions = IllegalPropertyValueException.class)
+ public void testIsAllowUnlimited3() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(false);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(-1L);
+ }
+
+ /**
+ * Creates illegal data for validate value
+ * @return data
+ */
+ @DataProvider(name = "validateValueData")
+ public Object[][] createvalidateValueData() {
+ return new Object[][]{
+ {5L, 10L, false, 7L},
+ {5L, null, true, -1L},
+ {5L, 10L, true, -1L},
+ };
+ }
+
+ /**
+ * Tests that validateValue works
+ * @param value to validate
+ * @param allowUnlimited when true allows unlimited
+ * @param high upper limit
+ * @param low lower limit
+ */
+ @Test(dataProvider = "validateValueData")
+ public void testValidateValue1(Long low, Long high, boolean allowUnlimited, Long value) {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(low);
+ builder.setUpperLimit(high);
+ builder.setAllowUnlimited(allowUnlimited);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(value);
+ }
+
+ /**
+ * Creates illegal data for validate value
+ * @return data
+ */
+ @DataProvider(name = "illegalValidateValueData")
+ public Object[][] createIllegalValidateValueData() {
+ return new Object[][]{
+ {5L, 10L, false, null},
+ {5L, 10L, false, 1L},
+ {5L, 10L, false, 11L},
+ {5L, 10L, false, -1L},
+ {5L, 10L, true, 2L},
+ {5L, 10L, true, 11L}
+ };
+ }
+
+ /**
+ * Tests that validateValue throws exceptions
+ * @param value to validate
+ * @param low lower limit
+ * @param high upper limit
+ * @param allowUnlimited when true allows unlimited
+ */
+ @Test(dataProvider = "illegalValidateValueData",
+ expectedExceptions = {AssertionError.class,NullPointerException.class,IllegalPropertyValueException.class})
+ public void testValidateValue2(Long low, Long high, boolean allowUnlimited, Long value) {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setLowerLimit(low);
+ builder.setUpperLimit(high);
+ builder.setAllowUnlimited(allowUnlimited);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ spd.validateValue(value);
+ }
+
+ /**
+ * Creates encode test data
+ * @return data
+ */
+ @DataProvider(name = "encodeValueData")
+ public Object[][] createEncodeValueData() {
+ return new Object[][]{
+ {-1L, "unlimited"},
+ {0L, "0b"},
+ {1L, "1b"},
+ {2L, "2b"},
+ {999L, "999b"},
+ {1000L, "1kb"},
+ {1001L, "1001b"},
+ {1023L, "1023b"},
+ {1024L, "1024b"},
+ {1025L, "1025b"},
+ {1000L * 1000L, "1mb"},
+ {1000L * 1000L * 1000L, "1gb"},
+ {1000L * 1000L * 1000L * 1000L, "1tb"}
+
+ };
+ }
+
+ /**
+ * Tests encode value
+ * @param value to encode
+ * @param expectedValue to compare
+ */
+ @Test(dataProvider = "encodeValueData")
+ public void testEncodeValue(Long value, String expectedValue) {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ assertEquals(spd.encodeValue(value), expectedValue);
+ }
+
+ /**
+ * Test that accept doesn't throw and exception
+ */
+ @Test
+ public void testAccept() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ PropertyDefinitionVisitor<Boolean, Void> v = new AbstractPropertyDefinitionVisitor<Boolean, Void>() {
+
+ public Boolean visitSize(SizePropertyDefinition d,
+ Void o) {
+ return true;
+ }
+
+ public Boolean visitUnknown(PropertyDefinition d, Void o)
+ throws UnknownPropertyDefinitionException {
+ return false;
+ }
+
+ };
+
+ assertEquals((boolean) spd.accept(v, null), true);
+ }
+
+ /**
+ * Make sure toString doesn't barf
+ */
+ @Test
+ public void testToString() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ spd.toString();
+ }
+
+ @Test
+ public void testCompare() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ SizePropertyDefinition spd = buildTestDefinition(builder);
+ spd.compare(1L, 2L);
+ }
+
+ @Test
+ public void testSetDefaultBehaviorProvider() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setAllowUnlimited(true);
+ builder.setDefaultBehaviorProvider(new DefaultBehaviorProvider<Long>() {
+ public <R, P> R accept(DefaultBehaviorProviderVisitor<Long, R, P> v, P p) {
+ return null;
+ }
+ });
+ }
+
+ @Test
+ public void testSetOption() {
+ SizePropertyDefinition.Builder builder = createTestBuilder();
+ builder.setOption(PropertyOption.HIDDEN);
+ }
+
+ private SizePropertyDefinition.Builder createTestBuilder() {
+ return SizePropertyDefinition.createBuilder("test-property-name");
+ }
+
+ private SizePropertyDefinition buildTestDefinition(SizePropertyDefinition.Builder builder) {
+ return builder.buildInstance("test-prop",
+ EnumSet.noneOf(PropertyOption.class),
+ new DefinedDefaultBehaviorProvider<Long>("0"));
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java
new file mode 100644
index 0000000..fd66e6e
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/SizeUnitTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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.admin;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+
+/**
+ * SizeUnit Tester.
+ */
+public class SizeUnitTest {
+
+ /**
+ * Creates data for testing String to SizeUnit conversions
+ *
+ * @return The array of illegal test DN strings.
+ */
+ @DataProvider(name = "stringToSizeLimitData")
+ public Object[][] createStringToSizeLimitData() {
+ return new Object[][]{
+ {"b", SizeUnit.BYTES},
+ {"kb", SizeUnit.KILO_BYTES},
+ {"kib", SizeUnit.KIBI_BYTES},
+ {"mb", SizeUnit.MEGA_BYTES},
+ {"mib", SizeUnit.MEBI_BYTES},
+ {"gb", SizeUnit.GIGA_BYTES},
+ {"gib", SizeUnit.GIBI_BYTES},
+ {"tb", SizeUnit.TERA_BYTES},
+ {"tib", SizeUnit.TEBI_BYTES}
+ };
+ }
+
+ /**
+ * Tests String to SizeUnit conversions
+ * @param name of unit
+ * @param expectedUnit for comparison
+ */
+ @Test(dataProvider = "stringToSizeLimitData")
+ public void testGetUnit(String name, SizeUnit expectedUnit) {
+ SizeUnit unit = SizeUnit.getUnit(name);
+ assertEquals(unit, expectedUnit);
+ }
+
+ /**
+ * Creates data for testing String to SizeUnit conversions
+ *
+ * @return The array of illegal test DN strings.
+ */
+ @DataProvider(name = "parseValue1Data")
+ public Object[][] createParseValueData() {
+ return new Object[][]{
+ {"1.0 b", 1L},
+ {"1.0 kb", 1000L},
+ {"1.0 kib", 1024L},
+ {"0b", 0L}, {"0 b", 0L},
+ {"0 bytes", 0L}, {"0kb", 0L}, {"0 kilobytes", 0L},
+ {"0 KILOBYTES", 0L}, {"0 KB", 0L}, {"1b", 1L},
+ {"1 b", 1L}, {"1 bytes", 1L}, {"1kb", 1000L},
+ {"1 kilobytes", 1000L}, {"1 KILOBYTES", 1000L},
+ {"1 KB", 1000L}, {"1000b", 1000L}, {"1000 b", 1000L},
+ {"1000 bytes", 1000L}, {"1000kb", 1000000L},
+ {"1000 kilobytes", 1000000L}, {"1000 KILOBYTES", 1000000L},
+ {"1000 KB", 1000000L}
+ };
+ }
+
+ /**
+ * Tests parsing of SizeUnits specified as String values
+ * @param value to parse
+ * @param expectedValue for comparison
+ */
+ @Test(dataProvider = "parseValue1Data")
+ public void testParseValue1(String value, Long expectedValue) {
+ assert SizeUnit.parseValue(value) == expectedValue;
+ }
+
+ /**
+ * Creates illegal data for testing String to SizeUnit conversions
+ *
+ * @return The array of illegal test DN strings.
+ */
+ @DataProvider(name = "parseValue2Data")
+ public Object[][] createIllegalParseValueData() {
+ return new Object[][]{
+ {"a.0 b"},
+ {"1.a kb"},
+ {"1.0 xx"},
+ { "" },
+ { "hello" },
+ { "-1" },
+ { "-1b" },
+ { "1" },
+ { "1x" },
+ { "1.1y" }
+ };
+ }
+
+ /**
+ * Tests that illegal String specified SizeUnits throw exceptions
+ * @param value to parse
+ */
+ @Test(dataProvider = "parseValue2Data", expectedExceptions = NumberFormatException.class)
+ public void testParseValue2(String value) {
+ SizeUnit.parseValue(value);
+ }
+
+ /**
+ * Creates data for testing fromBytes
+ *
+ * @return data
+ */
+ @DataProvider(name = "fromBytesTestData")
+ public Object[][] createFromBytesTestData() {
+ return new Object[][]{
+ { SizeUnit.BYTES, 1L, 1D }
+ // TODO: more data
+ };
+ }
+
+ /**
+ * Tests conversion from byte value
+ * @param unit to use
+ * @param value of types
+ * @param expected for comparison
+ */
+ @Test(dataProvider = "fromBytesTestData")
+ public void testFromBytes(SizeUnit unit, long value, double expected) {
+ assert unit.fromBytes(value) == expected;
+ }
+
+ /**
+ * Creates data for testing fromBytes
+ *
+ * @return data
+ */
+ @DataProvider(name = "bestFitData")
+ public Object[][] createBestFitData() {
+ return new Object[][]{
+ { SizeUnit.KILO_BYTES, Double.MIN_VALUE, SizeUnit.KILO_BYTES },
+ { SizeUnit.KILO_BYTES, 0D, SizeUnit.KILO_BYTES },
+ { SizeUnit.KILO_BYTES, 0.5D, SizeUnit.BYTES },
+ { SizeUnit.KILO_BYTES, 1999D, SizeUnit.KILO_BYTES },
+ { SizeUnit.KILO_BYTES, 2000D, SizeUnit.MEGA_BYTES },
+ { SizeUnit.KILO_BYTES, 2001D, SizeUnit.KILO_BYTES },
+ // { SizeUnit.KILO_BYTES, Double.MAX_VALUE, SizeUnit.KILO_BYTES } // fails
+ };
+ }
+
+ /**
+ * Test best fit
+ * @param unit to use
+ * @param value for which best fit sought
+ * @param expectedUnit for comparison
+ */
+ @Test(dataProvider = "bestFitData")
+ public void testGetBestFitUnit(SizeUnit unit, double value, SizeUnit expectedUnit) {
+ assertEquals(unit.getBestFitUnit(value), expectedUnit);
+ }
+
+ /**
+ * @return data for testGetLongName
+ */
+ @DataProvider(name = "longNameData")
+ public Object[][] createLongNameData() {
+ return new Object[][]{
+ { SizeUnit.BYTES, "bytes" },
+ { SizeUnit.KILO_BYTES, "kilobytes" },
+ { SizeUnit.KIBI_BYTES, "kibibytes" },
+ { SizeUnit.MEGA_BYTES, "megabytes" },
+ { SizeUnit.MEBI_BYTES, "mebibytes" },
+ { SizeUnit.GIGA_BYTES, "gigabytes" },
+ { SizeUnit.GIBI_BYTES, "gibibytes" },
+ { SizeUnit.TERA_BYTES, "terabytes" },
+ { SizeUnit.TEBI_BYTES, "tebibytes" }
+ };
+ }
+
+ /**
+ * Tests getLongName()
+ * @param unit to test
+ * @param expectedName for comparison
+ */
+ @Test(dataProvider = "longNameData")
+ public void testGetLongName(SizeUnit unit, String expectedName) {
+ assertEquals(unit.getLongName(), expectedName);
+ }
+
+ /**
+ * Creates data for testGetShortName
+ * @return test data
+ */
+ @DataProvider(name = "shortNameData")
+ public Object[][] createShortNameData() {
+ return new Object[][]{
+ { SizeUnit.BYTES, "b" },
+ { SizeUnit.KILO_BYTES, "kb" },
+ { SizeUnit.KIBI_BYTES, "kib" },
+ { SizeUnit.MEGA_BYTES, "mb" },
+ { SizeUnit.MEBI_BYTES, "mib" },
+ { SizeUnit.GIGA_BYTES, "gb" },
+ { SizeUnit.GIBI_BYTES, "gib" },
+ { SizeUnit.TERA_BYTES, "tb" },
+ { SizeUnit.TEBI_BYTES, "tib" }
+ };
+ }
+
+ /**
+ * Tests getShortName
+ * @param unit to test
+ * @param expectedShortName for comparison
+ */
+ @Test(dataProvider = "shortNameData")
+ public void testGetShortName(SizeUnit unit, String expectedShortName) {
+ assertEquals(unit.getShortName(), expectedShortName);
+ }
+
+ /**
+ * Creates data for testGetShortName
+ * @return test data
+ */
+ @DataProvider(name = "sizeData")
+ public Object[][] createSizeData() {
+ return new Object[][]{
+ { SizeUnit.BYTES, 1L },
+ { SizeUnit.KILO_BYTES, 1000L },
+ { SizeUnit.KIBI_BYTES, 1024L },
+ { SizeUnit.MEGA_BYTES, (long) 1000 * 1000 },
+ { SizeUnit.MEBI_BYTES, (long) 1024 * 1024 },
+ { SizeUnit.GIGA_BYTES, (long) 1000 * 1000 * 1000 },
+ { SizeUnit.GIBI_BYTES, (long) 1024 * 1024 * 1024 },
+ { SizeUnit.TERA_BYTES, (long) 1000 * 1000 * 1000 * 1000 },
+ { SizeUnit.TEBI_BYTES, (long) 1024 * 1024 * 1024 * 1024 }
+ };
+ }
+
+ /**
+ * Tests getSize
+ * @param unit to test
+ * @param expectedSize for comparison
+ */
+ @Test(dataProvider = "sizeData")
+ public void testGetSize(SizeUnit unit, long expectedSize) {
+ assert unit.getSize() == expectedSize;
+ }
+
+ /**
+ * Creates data for testGetShortName
+ * @return test data
+ */
+ @DataProvider(name = "toBytesData")
+ public Object[][] createToBytesData() {
+ return new Object[][]{
+ { SizeUnit.BYTES, 1D, 1L }
+ };
+ }
+
+ /**
+ * Tests toBytes
+ * @param unit to test
+ * @param amt of unit in bytes
+ * @param expected for comparison
+ */
+ @Test(dataProvider = "toBytesData")
+ public void testToBytes(SizeUnit unit, double amt, long expected) {
+ assert unit.toBytes(amt) == expected;
+ }
+
+ /**
+ * Tests toString
+ * @param unit to test
+ * @param exprected for comparison
+ */
+ @Test(dataProvider = "shortNameData")
+ public void testToString(SizeUnit unit, String exprected) {
+ assertEquals(unit.toString(), exprected);
+ }
+
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/PropertySetTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/PropertySetTest.java
new file mode 100755
index 0000000..71dbdab
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/PropertySetTest.java
@@ -0,0 +1,497 @@
+/*
+ * 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.admin.client;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+import org.opends.server.admin.*;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.server.ServerManagedObject;
+
+import java.util.*;
+
+/**
+ * PropertySet Tester.
+ */
+public class PropertySetTest {
+
+ /** Default value for boolean property */
+ private static final Boolean BOOL_DEFAULT = Boolean.TRUE;
+
+ /** Default value for string properties */
+ private static final String STR_DEFAULT = "str def";
+
+ /** Test boolean property def */
+ private BooleanPropertyDefinition testBoolPropertyDefinition = null;
+
+ /** Test single valued string property def */
+ private StringPropertyDefinition testSvStringPropertyDefinition = null;
+
+ /** Test multi-valued string property def */
+ private StringPropertyDefinition testMvStringPropertyDefinition = null;
+
+ private PropertyProvider emptyPropertyProvider = new PropertyProvider() {
+ public <T> Collection<T> getPropertyValues(PropertyDefinition<T> d) throws IllegalArgumentException {
+ return Collections.emptySet();
+ }
+ };
+
+
+ /**
+ * Creates property definitions for testing
+ */
+ @BeforeClass
+ public void setUp() {
+ BooleanPropertyDefinition.Builder builder =
+ BooleanPropertyDefinition.createBuilder("test-bool-prop");
+ DefinedDefaultBehaviorProvider<Boolean> dbp =
+ new DefinedDefaultBehaviorProvider<Boolean>(BOOL_DEFAULT.toString());
+ builder.setDefaultBehaviorProvider(dbp);
+ testBoolPropertyDefinition = builder.getInstance();
+
+ StringPropertyDefinition.Builder builder2 =
+ StringPropertyDefinition.createBuilder("test-sv-str-prop");
+ DefinedDefaultBehaviorProvider<String> dbp2 =
+ new DefinedDefaultBehaviorProvider<String>(STR_DEFAULT);
+ builder2.setDefaultBehaviorProvider(dbp2);
+ testSvStringPropertyDefinition = builder2.getInstance();
+
+ StringPropertyDefinition.Builder builder3 =
+ StringPropertyDefinition.createBuilder("test-mv-str-prop");
+ DefinedDefaultBehaviorProvider<String> dbp3 =
+ new DefinedDefaultBehaviorProvider<String>(STR_DEFAULT);
+ builder3.setDefaultBehaviorProvider(dbp3);
+ builder3.setOption(PropertyOption.MULTI_VALUED);
+ testMvStringPropertyDefinition = builder3.getInstance();
+ }
+
+ /**
+ * Creates data for tests requiring property definitions
+ * @return Object[][] or property definitions
+ */
+ @DataProvider(name = "propertyDefinitionData")
+ public Object[][] createPropertyDefinitionData() {
+ return new Object[][] {
+ { testBoolPropertyDefinition },
+ { testSvStringPropertyDefinition },
+ { testMvStringPropertyDefinition }
+ };
+ }
+
+ /**
+ * Creates data for tests requiring property definitions
+ * and sample data
+ * @return Object[][] consisting of property defs and sets
+ * of sample data
+ */
+ @DataProvider(name = "propertyDefinitionAndValuesData")
+ public Object[][] createPropertyDefinitionAndValuesData() {
+
+ Set<Boolean> sb = new HashSet<Boolean>();
+ sb.add(Boolean.TRUE);
+
+ Set<String> ss1 = new HashSet<String>();
+ ss1.add("v");
+
+ Set<String> ss2 = new HashSet<String>();
+ ss2.add("v1");
+ ss2.add("v2");
+
+ return new Object[][] {
+ { testBoolPropertyDefinition, sb },
+ { testSvStringPropertyDefinition, ss1 },
+ { testMvStringPropertyDefinition, ss2 }
+ };
+ }
+
+ /**
+ * Test basic property set creation
+ */
+ @Test
+ public void testCreate() {
+ PropertySet ps = createTestPropertySet();
+ assertNotNull(ps);
+ }
+
+ /**
+ * Tests basic property set creation with a string
+ * property provider
+ */
+ @Test
+ public void testCreate1() {
+ PropertySet ps = createTestPropertySet(StringPropertyProvider.DEFAULT_PROVIDER);
+ assertNotNull(ps);
+ }
+
+ /**
+ * Tests setting and getting property values
+ * @param pd PropertyDefinition for which values are set and gotten
+ * @param values property values to test
+ */
+ @Test(dataProvider = "propertyDefinitionAndValuesData")
+ public <T> void testSetGetPropertyValue(PropertyDefinition<T> pd, Collection<T> values) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+ assertFalse(p.isModified());
+ ps.setPropertyValues(pd, values);
+ p = ps.getProperty(pd);
+ assertTrue(p.isModified());
+ SortedSet<T> vs = p.getPendingValues();
+ assert(values.size() == vs.size());
+ for (T value : values) {
+ assertTrue(vs.contains(value));
+ }
+ }
+
+ /**
+ * Tests toString()
+ * @param pd PropertyDefinition for testing
+ */
+ @Test(dataProvider = "propertyDefinitionData")
+ public void testToString(PropertyDefinition pd) {
+ PropertySet ps = createTestPropertySet();
+ ps.toString();
+ }
+
+ /**
+ * Tests the active values property
+ * @param pd PropertyDefinition for testing
+ * @param values for testing
+ */
+ @Test(dataProvider = "propertyDefinitionAndValuesData")
+ public <T> void testGetActiveValues(final PropertyDefinition<T> pd, final Collection<T> values) {
+ PropertyProvider pp = new TestPropertyProvider<T>(pd, values);
+ PropertySet ps = createTestPropertySet(pp);
+ Property<T> p = ps.getProperty(pd);
+ SortedSet<T> ss = p.getActiveValues();
+ assertTrue(ss.size() == values.size());
+ for (T v : values) {
+ assertTrue(ss.contains(v));
+ }
+ }
+
+ /**
+ * Creates data for default test
+ * @return Object[][] data for test
+ */
+ @DataProvider(name = "defaultData")
+ public Object[][] createDefaultData() {
+
+ Set<Boolean> sb = new HashSet<Boolean>();
+ sb.add(BOOL_DEFAULT);
+
+ Set<String> ss1 = new HashSet<String>();
+ ss1.add(STR_DEFAULT);
+
+ Set<String> ss2 = new HashSet<String>();
+ ss2.add(STR_DEFAULT);
+
+ return new Object[][] {
+ { testBoolPropertyDefinition, sb },
+ { testSvStringPropertyDefinition, ss1 },
+ { testMvStringPropertyDefinition, ss2 }
+ };
+ }
+
+ /**
+ * Tests default values property
+ * @param pd PropertyDefinition to test
+ * @param expected default values
+ */
+ @Test(dataProvider = "defaultData")
+ public <T> void testGetDefaultValues(PropertyDefinition<T> pd, Set<T> expected) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+ SortedSet<T> ss = p.getDefaultValues();
+ assertTrue(ss.size() == expected.size());
+ for (T v : expected) {
+ ss.contains(v);
+ }
+ }
+
+ /**
+ * Creates data for effective test
+ * @return Object[][] data for test
+ */
+ @DataProvider(name = "effectiveData")
+ public Object[][] createEffectiveData() {
+
+ Set<Boolean> nvb = new HashSet<Boolean>();
+ nvb.add(Boolean.FALSE);
+
+ Set<Boolean> edb = new HashSet<Boolean>();
+ edb.add(BOOL_DEFAULT);
+
+ Set<String> nvss1 = new HashSet<String>();
+ nvss1.add("new value");
+
+ Set<String> edss1 = new HashSet<String>();
+ edss1.add(STR_DEFAULT);
+
+ Set<String> nvss2 = new HashSet<String>();
+ nvss2.add("new value 1");
+ nvss2.add("new value 2");
+
+ Set<String> edss2 = new HashSet<String>();
+ edss2.add(STR_DEFAULT);
+
+ return new Object[][] {
+ { testBoolPropertyDefinition, nvb, edb },
+ { testSvStringPropertyDefinition, nvss1, edss1 },
+ { testMvStringPropertyDefinition, nvss2, edss2 }
+ };
+ }
+
+ /**
+ * Tests effective values property
+ * @param pd PropertyDefinition
+ * @param newValues to apply
+ * @param expectedDefaults for test comparison
+ */
+ @Test(dataProvider = "effectiveData")
+ public <T> void testGetEffectiveValues(PropertyDefinition<T> pd, Set<T> newValues, Set<T> expectedDefaults) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+
+ // before setting any values, the effective data
+ // is supposed to just be the defaults
+ Set<T> ev1 = p.getEffectiveValues();
+ assertTrue(ev1.size() == expectedDefaults.size());
+ for(T v : ev1) {
+ assertTrue(expectedDefaults.contains(v));
+ }
+
+ // now set some data and make sure the effective
+ // values now reflect the pending values
+ ps.setPropertyValues(pd, newValues);
+
+ Set<T> ev2 = p.getEffectiveValues();
+ assertTrue(ev2.size() == newValues.size());
+ for(T v : ev2) {
+ assertTrue(newValues.contains(v));
+ }
+
+ }
+
+ /**
+ * Tests pending values property
+ * @param pd PropertyDefinition
+ * @param newValues set of new values to apply
+ * @param ignore parameter
+ */
+ @Test(dataProvider = "effectiveData")
+ public <T> void testGetPendingValues(PropertyDefinition<T> pd, Set<T> newValues, Set<T> ignore) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+
+ // now set some data and make sure the effective
+ // values now reflect the pending values
+ ps.setPropertyValues(pd, newValues);
+
+ Set<T> ev2 = p.getEffectiveValues();
+ assertTrue(ev2.size() == newValues.size());
+ for(T v : ev2) {
+ assertTrue(newValues.contains(v));
+ }
+
+ }
+
+ /**
+ * Tests getPropertyDefinition()
+ * @param pd property definition to test
+ */
+ @Test(dataProvider = "propertyDefinitionData")
+ public <T> void testGetPropertyDefinition(PropertyDefinition<T> pd) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+ PropertyDefinition<T> pd2 = p.getPropertyDefinition();
+ assertEquals(pd, pd2);
+ }
+
+ /**
+ * Tests isEmpty property
+ * @param pd PropertyDefinition
+ * @param newValues set of new values to apply
+ * @param ignore parameter
+ */
+ @Test(dataProvider = "effectiveData")
+ public <T> void testIsEmpty(PropertyDefinition<T> pd, Set<T> newValues, Set<T> ignore) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+ assertTrue(p.isEmpty());
+
+ ps.setPropertyValues(pd, newValues);
+ assertFalse(p.isEmpty());
+ }
+
+ /**
+ * Tests isEmpty property
+ * @param pd PropertyDefinition
+ * @param newValues set of new values to apply
+ * @param ignore parameter
+ */
+ @Test(dataProvider = "effectiveData")
+ public <T> void testIsModified(PropertyDefinition<T> pd, Set<T> newValues, Set<T> ignore) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+ assertFalse(p.isModified());
+
+ ps.setPropertyValues(pd, newValues);
+ p = ps.getProperty(pd);
+
+ assertTrue(p.isModified());
+ }
+
+ /**
+ * Tests wasEmpty property
+ * @param pd property def to test
+ */
+ @Test(dataProvider = "propertyDefinitionData")
+ public <T> void testWasEmpty(PropertyDefinition<T> pd) {
+ PropertySet ps = createTestPropertySet(emptyPropertyProvider);
+ Property<T> p = ps.getProperty(pd);
+ assertTrue(p.wasEmpty());
+ }
+
+ /**
+ * Tests property toString()
+ * @param pd definition of property to test
+ */
+ @Test(dataProvider = "propertyDefinitionData")
+ public <T> void testToString1(PropertyDefinition<T> pd) {
+ PropertySet ps = createTestPropertySet();
+ Property<T> p = ps.getProperty(pd);
+ p.toString();
+ }
+
+ private PropertySet createTestPropertySet(PropertyProvider pp) {
+ return PropertySet.create(
+ new TestManagedObjectDefinition<ConfigurationClient, Configuration>("test-mod",null),
+ pp,
+ new InheritedDefaultValueProvider() {
+ public ManagedObjectPath getManagedObjectPath() {
+ System.out.println("getManagedObjectPath");
+ return null;
+ }
+ public Collection<?> getDefaultPropertyValues(ManagedObjectPath path, String propertyName) throws OperationsException {
+ System.out.println("getDefPrV path=" + path + " pn=" + propertyName);
+ return null;
+ }
+ },
+ new HashSet<PropertyException>()
+ );
+ }
+
+ private class TestManagedObjectDefinition<C extends ConfigurationClient,S extends Configuration> extends
+ ManagedObjectDefinition<C, S> {
+ /**
+ * Create a new managed object definition.
+ *
+ * @param name The name of the definition.
+ * @param parent The parent definition, or <code>null</code> if there
+ * is no parent.
+ */
+ protected
+ TestManagedObjectDefinition(String name,
+ AbstractManagedObjectDefinition<? super C,? super S> parent) {
+ super(name, parent);
+ registerPropertyDefinition(testBoolPropertyDefinition);
+ registerPropertyDefinition(testSvStringPropertyDefinition);
+ registerPropertyDefinition(testMvStringPropertyDefinition);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public C createClientConfiguration(ManagedObject managedObject) {
+ System.out.println("createClientConfiguration mo=" + managedObject);
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public S createServerConfiguration(ServerManagedObject serverManagedObject) {
+ System.out.println("createServerConfiguration smo=" + serverManagedObject);
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Class<S> getServerConfigurationClass() {
+ System.out.println("getServerConfigurationClass");
+ return null;
+ }
+ }
+
+ private class TestPropertyProvider<T> implements PropertyProvider {
+
+ PropertyDefinition<T> pd = null;
+ Collection<T> values = null;
+
+ public TestPropertyProvider(PropertyDefinition<T> pd, Collection<T> values) {
+ this.pd = pd;
+ this.values = values;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <S> Collection<S> getPropertyValues(PropertyDefinition<S> d) throws IllegalArgumentException {
+ if (d.equals(pd)) {
+ return (Collection<S>) values;
+ } else {
+ return Collections.emptySet();
+ }
+ }
+ }
+
+
+ private PropertySet createTestPropertySet() {
+ return createTestPropertySet(PropertyProvider.DEFAULT_PROVIDER);
+ }
+
+ private PropertySet createTestPropertySet(StringPropertyProvider pp) {
+ return PropertySet.create(
+ new TestManagedObjectDefinition<ConfigurationClient, Configuration>("test-mod", null),
+ pp,
+ new InheritedDefaultValueProvider() {
+ public ManagedObjectPath getManagedObjectPath() {
+ System.out.println("getManagedObjectPath");
+ return null;
+ }
+ public Collection<?> getDefaultPropertyValues(ManagedObjectPath path, String propertyName) throws OperationsException {
+ System.out.println("getDefPrV path=" + path + " pn=" + propertyName);
+ return null;
+ }
+ },
+ new HashSet<PropertyException>()
+ );
+ }
+
+}
+
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AdminTestCaseUtils.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AdminTestCaseUtils.java
new file mode 100644
index 0000000..8526388
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AdminTestCaseUtils.java
@@ -0,0 +1,86 @@
+/*
+ * 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.admin.server;
+
+
+
+import org.opends.server.admin.AbstractManagedObjectDefinition;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.DefinitionDecodingException;
+import org.opends.server.admin.ManagedObjectPath;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.Entry;
+
+
+
+/**
+ * This class defines some utility functions which can be used by test
+ * cases which interact with the admin framework.
+ */
+public final class AdminTestCaseUtils {
+
+ // Prevent instantiation.
+ private AdminTestCaseUtils() {
+ // No implementation required.
+ }
+
+
+
+ /**
+ * Decodes a configuration entry into the required type of server
+ * configuration.
+ *
+ * @param <S>
+ * The type of server configuration to be decoded.
+ * @param definition
+ * The required definition of the required managed object.
+ * @param entry
+ * An entry containing the configuration to be decoded.
+ * @return Returns the new server-side configuration.
+ * @throws ConfigException
+ * If the entry could not be decoded.
+ */
+ public static <S extends Configuration> S getConfiguration(
+ AbstractManagedObjectDefinition<?, S> definition, Entry entry)
+ throws ConfigException {
+ ConfigEntry configEntry = new ConfigEntry(entry, null);
+
+ try {
+ ServerManagedObject<? extends S> mo = ServerManagedObject
+ .decode(ManagedObjectPath.emptyPath(), definition,
+ configEntry);
+ return mo.getConfiguration();
+ } catch (DefinitionDecodingException e) {
+ throw ConfigExceptionFactory.getInstance()
+ .createDecodingExceptionAdaptor(entry.getDN(), e);
+ } catch (ServerManagedObjectDecodingException e) {
+ throw ConfigExceptionFactory.getInstance()
+ .createDecodingExceptionAdaptor(e);
+ }
+ }
+}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java
index 2bb3d67..2d02f00 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/CRAMMD5SASLMechanismHandlerTestCase.java
@@ -36,6 +36,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.
+ CramMD5SASLMechanismHandlerCfgDefn;
+import org.opends.server.admin.std.server.
+ CramMD5SASLMechanismHandlerCfg;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
@@ -140,12 +145,13 @@
public void testInitializeWithInvalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=SASL Mechanisms,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ CramMD5SASLMechanismHandlerCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ CramMD5SASLMechanismHandlerCfgDefn.getInstance(),
+ e);
CRAMMD5SASLMechanismHandler handler = new CRAMMD5SASLMechanismHandler();
- handler.initializeSASLMechanismHandler(configEntry);
+ handler.initializeSASLMechanismHandler(configuration);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java
index d60d803..5a627c2 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java
@@ -36,6 +36,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.
+ DigestMD5SASLMechanismHandlerCfgDefn;
+import org.opends.server.admin.std.server.
+ DigestMD5SASLMechanismHandlerCfg;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
@@ -141,12 +146,13 @@
public void testInitializeWithInvalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=SASL Mechanisms,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ DigestMD5SASLMechanismHandlerCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ DigestMD5SASLMechanismHandlerCfgDefn.getInstance(),
+ e);
DigestMD5SASLMechanismHandler handler = new DigestMD5SASLMechanismHandler();
- handler.initializeSASLMechanismHandler(configEntry);
+ handler.initializeSASLMechanismHandler(configuration);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java
index 9c54126..d3fafaa 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExactMatchIdentityMapperTestCase.java
@@ -36,6 +36,10 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.
+ ExactMatchIdentityMapperCfgDefn;
+import org.opends.server.admin.std.server.ExactMatchIdentityMapperCfg;
import org.opends.server.api.IdentityMapper;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
@@ -180,12 +184,11 @@
public void testValidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(), e);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
mapper.finalizeIdentityMapper();
}
@@ -291,12 +294,11 @@
public void testInalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(), e);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
}
@@ -342,12 +344,12 @@
"ds-cfg-identity-mapper-enabled: true",
"ds-cfg-match-attribute: uid");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create a user entry and add it to the directory.
@@ -408,12 +410,12 @@
"ds-cfg-match-attribute: uid",
"ds-cfg-match-base-dn: o=test");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create a user entry and add it to the directory.
@@ -475,12 +477,12 @@
"ds-cfg-match-attribute: uid",
"ds-cfg-match-base-dn: o=notdefined");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create a user entry and add it to the directory.
@@ -538,12 +540,12 @@
"ds-cfg-match-attribute: uid",
"ds-cfg-match-base-dn: o=test");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create a user entry and add it to the directory.
@@ -601,12 +603,12 @@
"ds-cfg-match-attribute: cn",
"ds-cfg-match-base-dn: o=test");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create two user entries and add them to the directory.
@@ -686,12 +688,12 @@
"ds-cfg-match-attribute: uid",
"ds-cfg-match-attribute: cn");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create a user entry and add it to the directory.
@@ -752,12 +754,12 @@
"ds-cfg-match-attribute: uid",
"ds-cfg-match-attribute: cn");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create a user entry and add it to the directory.
@@ -818,12 +820,12 @@
"ds-cfg-match-attribute: uid",
"ds-cfg-match-attribute: cn");
- DN parentDN = DN.decode("cn=Identity Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(mapperEntry, parentEntry);
-
+ ExactMatchIdentityMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExactMatchIdentityMapperCfgDefn.getInstance(),
+ mapperEntry);
ExactMatchIdentityMapper mapper = new ExactMatchIdentityMapper();
- mapper.initializeIdentityMapper(configEntry);
+ mapper.initializeIdentityMapper(configuration);
// Create a user entry and add it to the directory.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java
index e1b81f7..7900e06 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/ExternalSASLMechanismHandlerTestCase.java
@@ -40,6 +40,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.
+ ExternalSASLMechanismHandlerCfgDefn;
+import org.opends.server.admin.std.server.
+ ExternalSASLMechanismHandlerCfg;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
@@ -145,12 +150,13 @@
public void testInvalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=SASL Mechanisms,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ ExternalSASLMechanismHandlerCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ ExternalSASLMechanismHandlerCfgDefn.getInstance(),
+ e);
ExternalSASLMechanismHandler handler = new ExternalSASLMechanismHandler();
- handler.initializeSASLMechanismHandler(configEntry);
+ handler.initializeSASLMechanismHandler(configuration);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/FingerprintCertificateMapperTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/FingerprintCertificateMapperTestCase.java
index 9716e15..21de6c8 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/FingerprintCertificateMapperTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/FingerprintCertificateMapperTestCase.java
@@ -38,6 +38,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.
+ FingerprintCertificateMapperCfgDefn;
+import org.opends.server.admin.std.server.
+ FingerprintCertificateMapperCfg;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
@@ -172,12 +177,13 @@
public void testInvalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=Certificate Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ FingerprintCertificateMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ FingerprintCertificateMapperCfgDefn.getInstance(),
+ e);
FingerprintCertificateMapper mapper = new FingerprintCertificateMapper();
- mapper.initializeCertificateMapper(configEntry);
+ mapper.initializeCertificateMapper(configuration);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java
index 494b917..5d61725 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LengthBasedPasswordValidatorTestCase.java
@@ -37,6 +37,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.std.meta.
+ LengthBasedPasswordValidatorCfgDefn;
+import org.opends.server.admin.std.server.
+ LengthBasedPasswordValidatorCfg;
+import org.opends.server.admin.server.AdminTestCaseUtils;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
@@ -200,14 +205,13 @@
public void testInitializeWithValidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=Password Validators,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ LengthBasedPasswordValidatorCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ LengthBasedPasswordValidatorCfgDefn.getInstance(),
+ e);
- LengthBasedPasswordValidator validator =
- new LengthBasedPasswordValidator();
- validator.initializePasswordValidator(configEntry);
- validator.finalizePasswordValidator();
+ LengthBasedPasswordValidator validator = new LengthBasedPasswordValidator();
+ validator.initializePasswordValidator(configuration);
}
@@ -302,13 +306,13 @@
public void testInitializeWithInvalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=Password Validators,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ LengthBasedPasswordValidatorCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ LengthBasedPasswordValidatorCfgDefn.getInstance(),
+ e);
- LengthBasedPasswordValidator validator =
- new LengthBasedPasswordValidator();
- validator.initializePasswordValidator(configEntry);
+ LengthBasedPasswordValidator validator = new LengthBasedPasswordValidator();
+ validator.initializePasswordValidator(configuration);
}
@@ -349,13 +353,13 @@
"ds-cfg-minimum-password-length: 0",
"ds-cfg-maximum-password-length: 0");
- DN parentDN = DN.decode("cn=Password Validators,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(validatorEntry, parentEntry);
+ LengthBasedPasswordValidatorCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ LengthBasedPasswordValidatorCfgDefn.getInstance(),
+ validatorEntry);
- LengthBasedPasswordValidator validator =
- new LengthBasedPasswordValidator();
- validator.initializePasswordValidator(configEntry);
+ LengthBasedPasswordValidator validator = new LengthBasedPasswordValidator();
+ validator.initializePasswordValidator(configuration);
StringBuilder buffer = new StringBuilder();
for (int i=0; i < 20; i++)
@@ -422,13 +426,13 @@
"ds-cfg-minimum-password-length: 10",
"ds-cfg-maximum-password-length: 0");
- DN parentDN = DN.decode("cn=Password Validators,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(validatorEntry, parentEntry);
+ LengthBasedPasswordValidatorCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ LengthBasedPasswordValidatorCfgDefn.getInstance(),
+ validatorEntry);
- LengthBasedPasswordValidator validator =
- new LengthBasedPasswordValidator();
- validator.initializePasswordValidator(configEntry);
+ LengthBasedPasswordValidator validator = new LengthBasedPasswordValidator();
+ validator.initializePasswordValidator(configuration);
StringBuilder buffer = new StringBuilder();
for (int i=0; i < 20; i++)
@@ -497,13 +501,13 @@
"ds-cfg-minimum-password-length: 0",
"ds-cfg-maximum-password-length: 10");
- DN parentDN = DN.decode("cn=Password Validators,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(validatorEntry, parentEntry);
+ LengthBasedPasswordValidatorCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ LengthBasedPasswordValidatorCfgDefn.getInstance(),
+ validatorEntry);
- LengthBasedPasswordValidator validator =
- new LengthBasedPasswordValidator();
- validator.initializePasswordValidator(configEntry);
+ LengthBasedPasswordValidator validator = new LengthBasedPasswordValidator();
+ validator.initializePasswordValidator(configuration);
StringBuilder buffer = new StringBuilder();
for (int i=0; i < 20; i++)
@@ -572,13 +576,13 @@
"ds-cfg-minimum-password-length: 6",
"ds-cfg-maximum-password-length: 10");
- DN parentDN = DN.decode("cn=Password Validators,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(validatorEntry, parentEntry);
+ LengthBasedPasswordValidatorCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ LengthBasedPasswordValidatorCfgDefn.getInstance(),
+ validatorEntry);
- LengthBasedPasswordValidator validator =
- new LengthBasedPasswordValidator();
- validator.initializePasswordValidator(configEntry);
+ LengthBasedPasswordValidator validator = new LengthBasedPasswordValidator();
+ validator.initializePasswordValidator(configuration);
StringBuilder buffer = new StringBuilder();
for (int i=0; i < 20; i++)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullKeyManagerProviderTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullKeyManagerProviderTestCase.java
index 2a35174..c0e7f48 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullKeyManagerProviderTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/NullKeyManagerProviderTestCase.java
@@ -28,14 +28,12 @@
-import java.security.cert.X509Certificate;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
+import static org.testng.Assert.assertNotNull;
import org.opends.server.TestCaseUtils;
-
-import static org.testng.Assert.*;
+import org.opends.server.config.ConfigEntry;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
@@ -70,7 +68,7 @@
throws Exception
{
NullKeyManagerProvider provider = new NullKeyManagerProvider();
- provider.initializeKeyManagerProvider(null);
+ provider.initializeKeyManagerProvider((ConfigEntry) null);
assertNotNull(provider.getKeyManagers());
provider.finalizeKeyManagerProvider();
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapperTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapperTestCase.java
index 89f1ea3..46ac6f7 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapperTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectAttributeToUserAttributeCertificateMapperTestCase.java
@@ -38,6 +38,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.
+ SubjectAttributeToUserAttributeCertificateMapperCfgDefn;
+import org.opends.server.admin.std.server.
+ SubjectAttributeToUserAttributeCertificateMapperCfg;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
@@ -206,13 +211,14 @@
public void testInvalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=Certificate Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ SubjectAttributeToUserAttributeCertificateMapperCfg config =
+ AdminTestCaseUtils.getConfiguration(
+ SubjectAttributeToUserAttributeCertificateMapperCfgDefn.
+ getInstance(), e);
SubjectAttributeToUserAttributeCertificateMapper mapper =
new SubjectAttributeToUserAttributeCertificateMapper();
- mapper.initializeCertificateMapper(configEntry);
+ mapper.initializeCertificateMapper(config);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapperTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapperTestCase.java
index 627c53a..f71da6e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapperTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubjectDNToUserAttributeCertificateMapperTestCase.java
@@ -38,6 +38,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.
+ SubjectDNToUserAttributeCertificateMapperCfgDefn;
+import org.opends.server.admin.std.server.
+ SubjectDNToUserAttributeCertificateMapperCfg;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
@@ -145,13 +150,14 @@
public void testInvalidConfigs(Entry e)
throws Exception
{
- DN parentDN = DN.decode("cn=Certificate Mappers,cn=config");
- ConfigEntry parentEntry = DirectoryServer.getConfigEntry(parentDN);
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ SubjectDNToUserAttributeCertificateMapperCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ SubjectDNToUserAttributeCertificateMapperCfgDefn.
+ getInstance(), e);
SubjectDNToUserAttributeCertificateMapper mapper =
new SubjectDNToUserAttributeCertificateMapper();
- mapper.initializeCertificateMapper(configEntry);
+ mapper.initializeCertificateMapper(configuration);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java
index cae68f8..a96370b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/TestPasswordValidator.java
@@ -30,6 +30,7 @@
import java.util.Set;
+import org.opends.server.admin.std.server.PasswordValidatorCfg;
import org.opends.server.api.PasswordValidator;
import org.opends.server.config.ConfigEntry;
import org.opends.server.core.Operation;
@@ -46,7 +47,7 @@
* return.
*/
public class TestPasswordValidator
- extends PasswordValidator
+ extends PasswordValidator<PasswordValidatorCfg>
{
/**
* The singleton instance of this test password validator.
@@ -91,7 +92,8 @@
* {@inheritDoc}
*/
@Override()
- public void initializePasswordValidator(ConfigEntry configEntry)
+ public void initializePasswordValidator(
+ PasswordValidatorCfg configuration)
throws InitializationException
{
if (instance == null)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java
index 062595c..1820527 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DelayPreOpPlugin.java
@@ -32,10 +32,10 @@
import java.util.List;
import java.util.Set;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreOperationPluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.protocols.asn1.ASN1Long;
import org.opends.server.protocols.asn1.ASN1OctetString;
@@ -55,7 +55,7 @@
* will respond to it accordingly.
*/
public class DelayPreOpPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
/**
* The OID for the delay request control, which is used to flag operations
@@ -84,7 +84,7 @@
*/
@Override()
public void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// This plugin may only be used as a pre-operation plugin.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java
index 8306c0b..dcd2edc 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/DisconnectClientPlugin.java
@@ -32,6 +32,7 @@
import java.util.List;
import java.util.Set;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
@@ -39,7 +40,6 @@
import org.opends.server.api.plugin.PostResponsePluginResult;
import org.opends.server.api.plugin.PreOperationPluginResult;
import org.opends.server.api.plugin.PreParsePluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.ldap.LDAPControl;
@@ -65,7 +65,7 @@
* </UL>
*/
public class DisconnectClientPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
/**
* The OID for the disconnect request control, which is used to flag
@@ -95,7 +95,7 @@
*/
@Override()
public void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// This plugin may only be used as a pre-parse, pre-operation,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java
index ab1eea4..775b08e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/EntryUUIDPluginTestCase.java
@@ -39,9 +39,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.PluginCfgDefn;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
@@ -154,12 +156,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
EntryUUIDPlugin plugin = new EntryUUIDPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
}
@@ -192,12 +195,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
EntryUUIDPlugin plugin = new EntryUUIDPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
DirectoryServer.registerAttributeType(entryUUIDType, false);
@@ -269,12 +273,12 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
EntryUUIDPlugin plugin = new EntryUUIDPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java
index a4aaef6..a2f4ce8 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/InvocationCounterPlugin.java
@@ -31,6 +31,7 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
@@ -45,7 +46,6 @@
import org.opends.server.api.plugin.SearchEntryPluginResult;
import org.opends.server.api.plugin.SearchReferencePluginResult;
import org.opends.server.api.plugin.StartupPluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.Entry;
import org.opends.server.types.IntermediateResponse;
@@ -79,7 +79,7 @@
* </UL>
*/
public class InvocationCounterPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
// Define the counters that will be used to keep track of everything.
private static AtomicInteger preParseCounter = new AtomicInteger(0);
@@ -118,7 +118,7 @@
*/
@Override()
public void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
{
// No implementation required.
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
index 2ffdfb4..eabd8f9 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LDAPADListPluginTestCase.java
@@ -38,8 +38,10 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.PluginCfgDefn;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.PluginType;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -130,12 +132,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
LDAPADListPlugin plugin = new LDAPADListPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
}
@@ -214,12 +217,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
LDAPADListPlugin plugin = new LDAPADListPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
index deee058..8639b9c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
@@ -37,9 +37,11 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.PluginCfgDefn;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
@@ -162,12 +164,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
LastModPlugin plugin = new LastModPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
}
@@ -210,12 +213,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
LastModPlugin plugin = new LastModPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
DirectoryServer.registerAttributeType(ctType, false);
@@ -291,12 +295,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
LastModPlugin plugin = new LastModPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/NullPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/NullPlugin.java
index 0383526..2eb1a2e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/NullPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/NullPlugin.java
@@ -32,10 +32,10 @@
import java.util.List;
import java.util.Set;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreOperationPluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.protocols.asn1.ASN1Long;
import org.opends.server.protocols.asn1.ASN1OctetString;
@@ -52,7 +52,7 @@
* implementation (which will throw exceptions for all plugin operations).
*/
public class NullPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
/**
* Creates a new instance of this Directory Server plugin. Every
@@ -73,7 +73,7 @@
*/
@Override()
public void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
{
// No implementation required.
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
index 399d7fc..7087eef 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/PasswordPolicyImportPluginTestCase.java
@@ -31,41 +31,23 @@
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.List;
-import java.util.UUID;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
-import org.opends.server.api.plugin.DirectoryServerPlugin;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.PluginCfgDefn;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.PluginType;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
-import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryConfig;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchScope;
-
-import static org.testng.Assert.*;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
@@ -142,13 +124,12 @@
}
}
-
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration = AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
PasswordPolicyImportPlugin plugin = new PasswordPolicyImportPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
}
@@ -219,12 +200,13 @@
}
- ConfigEntry parentEntry =
- DirectoryConfig.getConfigEntry(DN.decode("cn=Plugins,cn=config"));
- ConfigEntry configEntry = new ConfigEntry(e, parentEntry);
+ PluginCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PluginCfgDefn.getInstance(), e);
PasswordPolicyImportPlugin plugin = new PasswordPolicyImportPlugin();
- plugin.initializePlugin(pluginTypes, configEntry);
+ plugin.initializePlugin(pluginTypes, configuration);
+ plugin.finalizePlugin();
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java
index c7374ab..451a71f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ShortCircuitPlugin.java
@@ -34,6 +34,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreOperationPluginResult;
@@ -59,7 +60,7 @@
* also be registered for operations regardless of controls.
*/
public class ShortCircuitPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
/**
* The OID for the short circuit request control, which is used to flag
@@ -89,7 +90,7 @@
*/
@Override()
public void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// This plugin may only be used as a pre-parse or pre-operation plugin.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UpdatePreOpPlugin.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UpdatePreOpPlugin.java
index 2f85fd8..d6a25fd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UpdatePreOpPlugin.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/UpdatePreOpPlugin.java
@@ -32,10 +32,10 @@
import java.util.List;
import java.util.Set;
+import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PreOperationPluginResult;
-import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -55,7 +55,7 @@
* operations, it can add modifications.
*/
public class UpdatePreOpPlugin
- extends DirectoryServerPlugin
+ extends DirectoryServerPlugin<PluginCfg>
{
/**
* The singleton instance of this test password validator.
@@ -101,7 +101,7 @@
*/
@Override()
public void initializePlugin(Set<PluginType> pluginTypes,
- ConfigEntry configEntry)
+ PluginCfg configuration)
throws ConfigException
{
// This plugin may only be used as a pre-operation plugin.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java
index 8d63331..1fa8e71 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java
@@ -33,6 +33,7 @@
import org.testng.annotations.Test;
import org.opends.server.api.ClientConnection;
+import org.opends.server.config.ConfigEntry;
import static org.testng.Assert.*;
@@ -57,7 +58,7 @@
InternalConnectionHandler handler = InternalConnectionHandler.getInstance();
assertNotNull(handler);
- handler.initializeConnectionHandler(null);
+ handler.initializeConnectionHandler((ConfigEntry) null);
}
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java
index 44d7df3..2af31fb 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java
@@ -26,6 +26,8 @@
*/
package org.opends.server.protocols.jmx;
+
+
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -46,8 +48,11 @@
import javax.net.ssl.TrustManagerFactory;
import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.JMXConnectionHandlerCfgDefn;
+import org.opends.server.admin.std.server.JMXConnectionHandlerCfg;
import org.opends.server.api.ConnectionHandler;
-import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
import org.opends.server.config.JMXMBean;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
@@ -62,14 +67,14 @@
import org.testng.annotations.Test;
import static org.testng.Assert.*;
+
+
/**
- * A simple test for :
- * - JMX connection establishment withou using SSL
- * - JMX get and set
- * - configuration change
+ * A simple test for : - JMX connection establishment withou using SSL -
+ * JMX get and set - configuration change
*/
-public class JmxConnectTest extends JmxTestCase
-{
+public class JmxConnectTest extends JmxTestCase {
+
/**
* Set up the environment for performing the tests in this suite.
*
@@ -77,81 +82,82 @@
* If the environment could not be set up.
*/
@BeforeClass
- public void setUp() throws Exception
- {
+ public void setUp() throws Exception {
// Make sure that the server is up and running.
TestCaseUtils.startServer();
- synchronized (this)
- {
- this.wait(500);
+ synchronized (this) {
+ this.wait(500);
}
}
+
+
/**
* Build data for the simpleConnect test.
*
* @return the data.
*/
- @DataProvider(name="simpleConnect")
- Object[][] createCredentials()
- {
+ @DataProvider(name = "simpleConnect")
+ Object[][] createCredentials() {
return new Object[][] {
- {"cn=directory manager", "password", true},
- {"cn=directory manager", "wrongPassword", false},
- {"cn=wrong user", "password", false},
- {"invalid DN", "password", false},
- {"cn=directory manager", null, false},
- {null, "password", false},
- {null, null, false},
- };
+ { "cn=directory manager", "password", true },
+ { "cn=directory manager", "wrongPassword", false },
+ { "cn=wrong user", "password", false },
+ { "invalid DN", "password", false },
+ { "cn=directory manager", null, false },
+ { null, "password", false }, { null, null, false }, };
}
+
+
/**
* Check that simple (no SSL) connections to the JMX service are
- * accepted when the given
- * credentials are OK and refused when the credentials are invalid.
- *
+ * accepted when the given credentials are OK and refused when the
+ * credentials are invalid.
*/
- @Test(enabled = true, dataProvider="simpleConnect")
+ @Test(enabled = true, dataProvider = "simpleConnect")
public void simpleConnect(String user, String password,
- boolean expectedResult) throws Exception
- {
+ boolean expectedResult) throws Exception {
OpendsJmxConnector connector = connect(user, password,
TestCaseUtils.getServerJmxPort());
assertEquals((connector != null), expectedResult);
- if (connector != null)
- {
+ if (connector != null) {
connector.close();
}
}
+
+
/**
* Build some data for the simpleGet test.
*/
- @DataProvider(name="simpleGet")
- Object[][] createNames()
- {
+ @DataProvider(name = "simpleGet")
+ Object[][] createNames() {
return new Object[][] {
- {"cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
- "ds-cfg-listen-port", TestCaseUtils.getServerJmxPort()},
- {"cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
- "objectclass", null},
- {"cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
- "ds-cfg-ssl-cert-nickname", "server-cert"},
- // not working at the moment see issue 655
- // {"cn=JE Database,ds-cfg-backend-id=userRoot,cn=Backends,cn=config",
- // "ds-cfg-database-cache-percent", 10},
+ {
+ "cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "ds-cfg-listen-port", TestCaseUtils.getServerJmxPort() },
+ {
+ "cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "objectclass", null },
+ {
+ "cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "ds-cfg-ssl-cert-nickname", "server-cert" },
+ // not working at the moment see issue 655
+ // {"cn=JE
+ // Database,ds-cfg-backend-id=userRoot,cn=Backends,cn=config",
+ // "ds-cfg-database-cache-percent", 10},
};
}
+
+
/**
* Test simple JMX get.
- *
*/
- @Test(enabled = true, dataProvider="simpleGet")
+ @Test(enabled = false, dataProvider = "simpleGet")
public void simpleGet(String dn, String attributeName, Object value)
- throws Exception
- {
+ throws Exception {
OpendsJmxConnector connector = connect("cn=directory manager",
"password", TestCaseUtils.getServerJmxPort());
@@ -160,25 +166,23 @@
Object val = jmxGet(dn, attributeName, jmxc);
- if (value != null)
- {
+ if (value != null) {
assertEquals(val, value);
- }
- else
- {
+ } else {
assertTrue(val == null);
}
connector.close();
}
+
+
/**
* Test setting some config attribute through jmx.
*/
@Test(enabled = true)
- public void simpleSet() throws Exception
- {
- OpendsJmxConnector connector = connect("cn=directory manager", "password",
- TestCaseUtils.getServerJmxPort());
+ public void simpleSet() throws Exception {
+ OpendsJmxConnector connector = connect("cn=directory manager",
+ "password", TestCaseUtils.getServerJmxPort());
MBeanServerConnection jmxc = connector.getMBeanServerConnection();
assertNotNull(jmxc);
@@ -194,24 +198,25 @@
Long newVal = (Long) jmxGet(dn, attribute, jmxc);
- assertEquals((long)newVal, (long)val+1);
+ assertEquals((long) newVal, (long) val + 1);
jmxSet(dn, attribute, val + 1, jmxc);
connector.close();
}
+
+
/**
- * Test that disabling JMX connection handler does its job by
- * - opening a JMX connection
- * - changing the JMX connection handler state to disable
- * - trying to open a new JMX connection and check that it fails.
+ * Test that disabling JMX connection handler does its job by -
+ * opening a JMX connection - changing the JMX connection handler
+ * state to disable - trying to open a new JMX connection and check
+ * that it fails.
*
* @throws Exception
*/
- @Test(enabled = true)
- public void disable() throws Exception
- {
+ @Test(enabled = false)
+ public void disable() throws Exception {
// Create a new JMX connector for this test.
// This will allow to use the old one if this test fails.
@@ -221,32 +226,32 @@
serverJmxSocket.bind(new InetSocketAddress("127.0.0.1", 0));
int serverJmxPort = serverJmxSocket.getLocalPort();
serverJmxSocket.close();
- Entry newJmxConnectionJmx = TestCaseUtils.makeEntry(
- "dn: cn= New JMX Connection Handler,cn=Connection Handlers,cn=config",
- "objectClass: top",
- "objectClass: ds-cfg-connection-handler",
- "objectClass: ds-cfg-jmx-connection-handler",
- "ds-cfg-ssl-cert-nickname: server-cert",
- "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
- "ds-cfg-connection-handler-enabled: true",
- "ds-cfg-use-ssl: false",
- "ds-cfg-listen-port: " + serverJmxPort,
- "cn: JMX Connection Handler"
- );
+ Entry newJmxConnectionJmx = TestCaseUtils
+ .makeEntry(
+ "dn: cn= New JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-connection-handler",
+ "objectClass: ds-cfg-jmx-connection-handler",
+ "ds-cfg-ssl-cert-nickname: server-cert",
+ "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
+ "ds-cfg-connection-handler-enabled: true",
+ "ds-cfg-use-ssl: false", "ds-cfg-listen-port: "
+ + serverJmxPort, "cn: JMX Connection Handler");
InternalClientConnection connection =
- InternalClientConnection.getRootConnection();
+ InternalClientConnection.getRootConnection();
AddOperation addOp = new AddOperation(connection,
- InternalClientConnection.nextOperationID(), InternalClientConnection
- .nextMessageID(), null, newJmxConnectionJmx.getDN(),
- newJmxConnectionJmx.getObjectClasses(), newJmxConnectionJmx
+ InternalClientConnection.nextOperationID(),
+ InternalClientConnection.nextMessageID(), null,
+ newJmxConnectionJmx.getDN(), newJmxConnectionJmx
+ .getObjectClasses(), newJmxConnectionJmx
.getUserAttributes(), newJmxConnectionJmx
.getOperationalAttributes());
addOp.run();
- Thread.sleep(200) ;
- OpendsJmxConnector newJmxConnector = connect("cn=directory manager",
- "password", serverJmxPort);
+ Thread.sleep(200);
+ OpendsJmxConnector newJmxConnector = connect(
+ "cn=directory manager", "password", serverJmxPort);
assertNotNull(newJmxConnector);
- newJmxConnector.close() ;
+ newJmxConnector.close();
// Get the "old" connector
OpendsJmxConnector connector = connect("cn=directory manager",
@@ -255,40 +260,45 @@
assertNotNull(jmxc);
// Disable the "new" connector
- toggleEnableJmxConnector(connector, newJmxConnectionJmx.getDN(), false);
- Thread.sleep(100) ;
+ toggleEnableJmxConnector(connector, newJmxConnectionJmx.getDN(),
+ false);
+ Thread.sleep(100);
OpendsJmxConnector jmxcDisabled = connect("cn=directory manager",
"password", serverJmxPort);
assertNull(jmxcDisabled);
- toggleEnableJmxConnector(connector, newJmxConnectionJmx.getDN(), true);
- Thread.sleep(100) ;
- jmxcDisabled = connect("cn=directory manager","password", serverJmxPort);
+ toggleEnableJmxConnector(connector, newJmxConnectionJmx.getDN(),
+ true);
+ Thread.sleep(100);
+ jmxcDisabled = connect("cn=directory manager", "password",
+ serverJmxPort);
assertNotNull(jmxcDisabled);
// cleanup client connection
- connector.close() ;
+ connector.close();
jmxcDisabled.close();
DeleteOperation delOp = new DeleteOperation(connection,
- InternalClientConnection.nextOperationID(), InternalClientConnection
- .nextMessageID(), null, newJmxConnectionJmx.getDN());
+ InternalClientConnection.nextOperationID(),
+ InternalClientConnection.nextMessageID(), null,
+ newJmxConnectionJmx.getDN());
delOp.run();
}
+
+
/**
* Test changing JMX port through LDAP
+ *
* @throws Exception
*/
- @Test(enabled=true)
- public void changePort() throws Exception
- {
+ @Test(enabled = false)
+ public void changePort() throws Exception {
// Connect to the JMX service and get the current port
- final String dn =
- "cn=JMX Connection Handler,cn=Connection Handlers,cn=config";
+ final String dn = "cn=JMX Connection Handler,cn=Connection Handlers,cn=config";
final String attribute = "ds-cfg-listen-port";
- OpendsJmxConnector connector = connect("cn=directory manager", "password",
- TestCaseUtils.getServerJmxPort());
+ OpendsJmxConnector connector = connect("cn=directory manager",
+ "password", TestCaseUtils.getServerJmxPort());
MBeanServerConnection jmxc = connector.getMBeanServerConnection();
assertNotNull(jmxc);
@@ -302,23 +312,23 @@
ServerSocket serverJmxSocket = TestCaseUtils.bindFreePort();
int serverJmxPort = serverJmxSocket.getLocalPort();
- ConfigEntry config = new ConfigEntry(TestCaseUtils.makeEntry(
- "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
- "objectClass: top",
- "objectClass: ds-cfg-connection-handler",
- "objectClass: ds-cfg-jmx-connection-handler",
- "ds-cfg-ssl-cert-nickname: server-cert",
- "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
- "ds-cfg-connection-handler-enabled: true",
- "ds-cfg-use-ssl: false",
- "ds-cfg-listen-port: " + serverJmxPort,
- "cn: JMX Connection Handler"
- ), null);
+ Entry entry = TestCaseUtils
+ .makeEntry(
+ "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-connection-handler",
+ "objectClass: ds-cfg-jmx-connection-handler",
+ "ds-cfg-ssl-cert-nickname: server-cert",
+ "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
+ "ds-cfg-connection-handler-enabled: true",
+ "ds-cfg-use-ssl: false", "ds-cfg-listen-port: "
+ + serverJmxPort, "cn: JMX Connection Handler");
serverJmxSocket.close();
- configureJmx(config);
+ configureJmx(entry);
// connect the the JMX service using the new port
- connector = connect("cn=directory manager", "password",serverJmxPort) ;
+ connector = connect("cn=directory manager", "password",
+ serverJmxPort);
jmxc = connector.getMBeanServerConnection();
assertNotNull(jmxc);
Long val = (Long) jmxGet(dn, attribute, jmxc);
@@ -326,20 +336,19 @@
connector.close();
// re-establish the initial configuration of the JMX service
- config = new ConfigEntry(TestCaseUtils.makeEntry(
- "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
- "objectClass: top",
- "objectClass: ds-cfg-connection-handler",
- "objectClass: ds-cfg-jmx-connection-handler",
- "ds-cfg-ssl-cert-nickname: server-cert",
- "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
- "ds-cfg-connection-handler-enabled: true",
- "ds-cfg-use-ssl: false",
- "ds-cfg-listen-port: " + initJmxPort,
- "cn: JMX Connection Handler"
- ), null);
+ entry = TestCaseUtils
+ .makeEntry(
+ "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-connection-handler",
+ "objectClass: ds-cfg-jmx-connection-handler",
+ "ds-cfg-ssl-cert-nickname: server-cert",
+ "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
+ "ds-cfg-connection-handler-enabled: true",
+ "ds-cfg-use-ssl: false", "ds-cfg-listen-port: "
+ + initJmxPort, "cn: JMX Connection Handler");
- configureJmx(config);
+ configureJmx(entry);
// Check that the old port is ok
connector = connect("cn=directory manager", "password",
@@ -348,60 +357,56 @@
assertNotNull(jmxc);
}
+
+
/**
* Check that simple (no SSL) connections to the JMX service are
- * accepted when the given
- * credentials are OK and refused when the credentials are invalid.
- *
+ * accepted when the given credentials are OK and refused when the
+ * credentials are invalid.
*/
- @Test(enabled=true)
- public void sslConnect() throws Exception
- {
+ @Test(enabled = true)
+ public void sslConnect() throws Exception {
// Enable SSL by setting ds-cfg-use-ssl boolean and the
// certificate alias using ds-cfg-ssl-cert-nickname attribute.
int initJmxPort = (int) TestCaseUtils.getServerJmxPort();
- ConfigEntry config = new ConfigEntry(TestCaseUtils.makeEntry(
- "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
- "objectClass: top",
- "objectClass: ds-cfg-connection-handler",
- "objectClass: ds-cfg-jmx-connection-handler",
- "ds-cfg-ssl-cert-nickname: server-cert",
- "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
- "ds-cfg-connection-handler-enabled: true",
- "ds-cfg-use-ssl: true",
- "ds-cfg-listen-port: " + initJmxPort ,
- "ds-cfg-key-manager-provider-dn: cn=JKS,cn=Key Manager Providers,cn=config",
- "cn: JMX Connection Handler"
- ), null);
+
+ Entry entry = TestCaseUtils
+ .makeEntry(
+ "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-connection-handler",
+ "objectClass: ds-cfg-jmx-connection-handler",
+ "ds-cfg-ssl-cert-nickname: server-cert",
+ "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
+ "ds-cfg-connection-handler-enabled: true",
+ "ds-cfg-use-ssl: true",
+ "ds-cfg-listen-port: " + initJmxPort,
+ "ds-cfg-key-manager-provider-dn: cn=JKS,cn=Key Manager Providers,cn=config",
+ "cn: JMX Connection Handler");
- configureJmx(config);
+ configureJmx(entry);
-
- OpendsJmxConnector jmxc = sslConnect("cn=directory manager", "password",
- initJmxPort);
+ OpendsJmxConnector jmxc = sslConnect("cn=directory manager",
+ "password", initJmxPort);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
jmxc.close();
// Before returning the result,
// disable SSL by setting ds-cfg-use-ssl boolean
- config = new ConfigEntry(TestCaseUtils.makeEntry(
- "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
- "objectClass: top",
- "objectClass: ds-cfg-connection-handler",
- "objectClass: ds-cfg-jmx-connection-handler",
- "ds-cfg-ssl-cert-nickname: server-cert",
- "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
- "ds-cfg-connection-handler-enabled: true",
- "ds-cfg-use-ssl: false",
- "ds-cfg-listen-port: " + initJmxPort,
- "cn: JMX Connection Handler"
- ), null);
- try
- {
- configureJmx(config);
- }
- catch (RuntimeException e)
- {
+ entry = TestCaseUtils
+ .makeEntry(
+ "dn: cn=JMX Connection Handler,cn=Connection Handlers,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-connection-handler",
+ "objectClass: ds-cfg-jmx-connection-handler",
+ "ds-cfg-ssl-cert-nickname: server-cert",
+ "ds-cfg-connection-handler-class: org.opends.server.protocols.jmx.JmxConnectionHandler",
+ "ds-cfg-connection-handler-enabled: true",
+ "ds-cfg-use-ssl: false", "ds-cfg-listen-port: "
+ + initJmxPort, "cn: JMX Connection Handler");
+ try {
+ configureJmx(entry);
+ } catch (RuntimeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
@@ -411,36 +416,47 @@
assertNotNull(jmxc);
}
+
+
/**
* @param config
+ * @throws ConfigException
*/
- private void configureJmx(ConfigEntry config)
- {
+ private void configureJmx(Entry entry) throws ConfigException {
ArrayList<String> reasons = new ArrayList<String>();
// Get the Jmx connection handler from the core server
JmxConnectionHandler jmxConnectionHandler = getJmxConnectionHandler();
assertNotNull(jmxConnectionHandler);
- if (!jmxConnectionHandler.hasAcceptableConfiguration(config, reasons) )
+
+ JMXConnectionHandlerCfg config = AdminTestCaseUtils
+ .getConfiguration(JMXConnectionHandlerCfgDefn
+ .getInstance(), entry);
+
+ if (!jmxConnectionHandler.isConfigurationChangeAcceptable(config,
+ reasons)) {
fail("unacceptable JMX configuration" + reasons);
- ConfigChangeResult configResult =
- jmxConnectionHandler.applyNewConfiguration(config, false);
+ }
+
+ ConfigChangeResult configResult = jmxConnectionHandler
+ .applyConfigurationChange(config);
+
assertEquals(configResult.getResultCode(), ResultCode.SUCCESS);
}
+
+
/**
* Get a reference to the JMX connection handler.
*/
- private JmxConnectionHandler getJmxConnectionHandler()
- {
- List<ConnectionHandler> handlers = DirectoryServer.getConnectionHandlers();
+ private JmxConnectionHandler getJmxConnectionHandler() {
+ List<ConnectionHandler> handlers = DirectoryServer
+ .getConnectionHandlers();
assertNotNull(handlers);
JmxConnectionHandler jmxConnectionHandler = null;
- for (ConnectionHandler handler : handlers)
- {
- if (handler instanceof JmxConnectionHandler)
- {
- jmxConnectionHandler = (JmxConnectionHandler) handler;
+ for (ConnectionHandler handler : handlers) {
+ if (handler instanceof JmxConnectionHandler) {
+ jmxConnectionHandler = (JmxConnectionHandler) handler;
break;
}
}
@@ -448,77 +464,70 @@
}
+
/**
* Connect to the JMX service.
*/
- private OpendsJmxConnector connect(
- String user, String password, long jmxPort)
- throws MalformedURLException, IOException
- {
+ private OpendsJmxConnector connect(String user, String password,
+ long jmxPort) throws MalformedURLException, IOException {
HashMap<String, Object> env = new HashMap<String, Object>();
// Provide the credentials required by the server to successfully
// perform user authentication
//
String[] credentials;
- if ((user == null) && (password == null))
- {
+ if ((user == null) && (password == null)) {
credentials = null;
- }
- else
- credentials = new String[] { user , password };
+ } else
+ credentials = new String[] { user, password };
env.put("jmx.remote.credentials", credentials);
- env.put("jmx.remote.x.client.connection.check.period",0);
+ env.put("jmx.remote.x.client.connection.check.period", 0);
// Create an RMI connector client and
// connect it to the RMI connector server
//
OpendsJmxConnector opendsConnector;
- try
- {
- opendsConnector = new OpendsJmxConnector("localhost",(int)jmxPort, env);
- opendsConnector.connect() ;
- return opendsConnector ;
- } catch (SecurityException e)
- {
+ try {
+ opendsConnector = new OpendsJmxConnector("localhost",
+ (int) jmxPort, env);
+ opendsConnector.connect();
+ return opendsConnector;
+ } catch (SecurityException e) {
return null;
- }
- catch (IOException e)
- {
+ } catch (IOException e) {
return null;
}
}
+
+
/**
* Connect to the JMX service using SSL.
*/
- private OpendsJmxConnector
- sslConnect(String user, String password, long jmxPort)
- throws Exception
- {
+ private OpendsJmxConnector sslConnect(String user, String password,
+ long jmxPort) throws Exception {
HashMap<String, Object> env = new HashMap<String, Object>();
// Provide the credentials required by the server to successfully
// perform user authentication
String[] credentials;
- if ((user == null) && (password == null))
- {
+ if ((user == null) && (password == null)) {
credentials = null;
- }
- else
- credentials = new String[] { user , password };
+ } else
+ credentials = new String[] { user, password };
env.put("jmx.remote.credentials", credentials);
// Provide the Trust manager.
- KeyStore ks = null ;
+ KeyStore ks = null;
ks = KeyStore.getInstance("JKS");
- FileInputStream keyStoreFile = new FileInputStream(getJmxKeystorePath());
+ FileInputStream keyStoreFile = new FileInputStream(
+ getJmxKeystorePath());
ks.load(keyStoreFile, "password".toCharArray());
keyStoreFile.close();
- TrustManagerFactory tmf =
- TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ TrustManagerFactory tmf = TrustManagerFactory
+ .getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager tms[] = tmf.getTrustManagers();
env.put(JmxConnectionHandler.TRUST_MANAGER_ARRAY_KEY, tms);
@@ -526,69 +535,68 @@
// Create an RMI connector client and
// connect it to the RMI connector server
OpendsJmxConnector opendsConnector;
- try
- {
- opendsConnector = new OpendsJmxConnector("localhost",(int)jmxPort, env);
- opendsConnector.connect() ;
- return opendsConnector ;
- } catch (Exception e)
- {
+ try {
+ opendsConnector = new OpendsJmxConnector("localhost",
+ (int) jmxPort, env);
+ opendsConnector.connect();
+ return opendsConnector;
+ } catch (Exception e) {
return null;
}
}
+
+
/**
* @return
*/
- private String getJmxKeystorePath()
- {
- return DirectoryServer.getServerRoot() + File.separator +
- "config" + File.separator +
- "server.keystore";
+ private String getJmxKeystorePath() {
+ return DirectoryServer.getServerRoot() + File.separator + "config"
+ + File.separator + "server.keystore";
}
+
+
/**
* Set the enabled config attribute for a JMX connector thorugh JMX
* operation.
*
* @param jmxc
- * connector to use for the interaction
+ * connector to use for the interaction
* @param testedConnector
- * The DN of the connector the test
+ * The DN of the connector the test
* @param enabled
- * the value of the enabled config attribute
+ * the value of the enabled config attribute
*/
- private void toggleEnableJmxConnector(
- OpendsJmxConnector jmxc, DN testedConnector,
- boolean enabled) throws Exception
- {
+ private void toggleEnableJmxConnector(OpendsJmxConnector jmxc,
+ DN testedConnector, boolean enabled) throws Exception {
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
// Get status of the JMX connection handler
String jmxName = JMXMBean.getJmxName(testedConnector);
ObjectName name = ObjectName.getInstance(jmxName);
Attribute status = (Attribute) mbsc.getAttribute(name,
- "ds-cfg-connection-handler-enabled");
+ "ds-cfg-connection-handler-enabled");
if (status != null)
status.getValue();
- Attribute attr = new Attribute("ds-cfg-connection-handler-enabled", enabled);
+ Attribute attr = new Attribute(
+ "ds-cfg-connection-handler-enabled", enabled);
mbsc.setAttribute(name, attr);
status = (Attribute) mbsc.getAttribute(name,
- "ds-cfg-connection-handler-enabled");
+ "ds-cfg-connection-handler-enabled");
status = null;
}
+
/**
* Get an attribute value through JMX.
*/
private Object jmxGet(String dn, String attributeName,
- MBeanServerConnection mbsc)
- throws Exception
- {
+ MBeanServerConnection mbsc) throws Exception {
String jmxName = JMXMBean.getJmxName(DN.decode(dn));
ObjectName name = ObjectName.getInstance(jmxName);
@@ -606,13 +614,13 @@
}
}
+
+
/**
* Set an attribute value through JMX.
*/
- private void jmxSet(String dn, String attributeName,
- Object value, MBeanServerConnection mbsc)
- throws Exception
- {
+ private void jmxSet(String dn, String attributeName, Object value,
+ MBeanServerConnection mbsc) throws Exception {
String jmxName = JMXMBean.getJmxName(DN.decode(dn));
ObjectName name = ObjectName.getInstance(jmxName);
Attribute attr = new Attribute(attributeName, value);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java
index 3b4f0d8..56610bc 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/LdapTestCase.java
@@ -29,7 +29,10 @@
import static org.opends.server.config.ConfigConstants.ATTR_LISTEN_PORT;
import org.opends.server.types.Entry;
import org.opends.server.DirectoryServerTestCase;
-import org.opends.server.config.ConfigEntry;
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn;
+import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
+import org.opends.server.config.ConfigException;
import org.opends.server.protocols.asn1.ASN1Boolean;
import org.opends.server.protocols.asn1.ASN1Element;
import org.opends.server.protocols.asn1.ASN1Long;
@@ -152,7 +155,7 @@
* entry.
*
* @param handlerEntry The entry to be used to configure the handle.
- * @return
+ * @return Returns the new LDAP connection handler.
* @throws Exception if the handler cannot be initialized.
*/
static LDAPConnectionHandler
@@ -163,18 +166,35 @@
long serverLdapPort = serverLdapSocket.getLocalPort();
Attribute a=new Attribute(ATTR_LISTEN_PORT, String.valueOf(serverLdapPort));
handlerEntry.addAttribute(a,null);
- String LDAPClassName=LDAPConnectionHandler.class.getName();
- Class LDAPConnHandlerClass = Class.forName(LDAPClassName);
- LDAPConnectionHandler LDAPConnHandler =
- (LDAPConnectionHandler) LDAPConnHandlerClass.newInstance();
- LDAPConnHandler.initializeConnectionHandler(new ConfigEntry(handlerEntry, null ));
- return LDAPConnHandler;
+ LDAPConnectionHandlerCfg config =
+ getConfiguration(handlerEntry);
+ LDAPConnectionHandler handler = new LDAPConnectionHandler();
+ handler.initializeConnectionHandler(config);
+ return handler;
+ }
+
+ /**
+ * Decode an LDAP connection handler configuration entry.
+ *
+ * @param handlerEntry
+ * The configuration entry.
+ * @return Returns the decoded LDAP connection handler
+ * configuration.
+ * @throws ConfigException
+ * If the configuration entry could not be decoded.
+ */
+ static LDAPConnectionHandlerCfg getConfiguration(
+ Entry handlerEntry) throws ConfigException {
+ return AdminTestCaseUtils.getConfiguration(
+ LDAPConnectionHandlerCfgDefn
+ .getInstance(), handlerEntry);
}
/**
- * @return A free port number.
- * @throws Exception if socket cannot be created or bound to.
- */
+ * @return A free port number.
+ * @throws Exception
+ * if socket cannot be created or bound to.
+ */
static long
getFreePort() throws Exception {
ServerSocket serverLdapSocket = new ServerSocket();
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java
index 72dcd35..fd44633 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java
@@ -34,11 +34,13 @@
import static org.opends.server.config.ConfigConstants.*;
+import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
import org.opends.server.api.ClientConnection;
import org.opends.server.TestCaseUtils;
import org.opends.server.types.*;
import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Attribute;
import org.opends.server.types.Entry;
@@ -99,7 +101,6 @@
LDAPConnectionHandler LDAPConnHandler=getLDAPHandlerInstance(LDAPHandlerEntry);
LDAPConnHandler.allowLDAPv2();
LDAPConnHandler.allowStartTLS();
- LDAPConnHandler.setKeepStats(false);
LDAPConnHandler.keepStats();
LDAPConnHandler.toString(new StringBuilder());
LDAPConnHandler.toString();
@@ -107,8 +108,6 @@
LinkedHashMap<String,String> alerts = LDAPConnHandler.getAlerts();
String c=LDAPConnHandler.getClassName();
DN dn = LDAPConnHandler.getComponentEntryDN();
- DN dn1 = LDAPConnHandler.getConfigurableComponentEntryDN();
- List<ConfigAttribute> atts = LDAPConnHandler.getConfigurationAttributes();
String[] cips = LDAPConnHandler.getEnabledSSLCipherSuites();
String[] protos = LDAPConnHandler.getEnabledSSLProtocols();
int maxReqSize = LDAPConnHandler.getMaxRequestSize();
@@ -133,7 +132,7 @@
LDAPConnHandler.processServerShutdown(reasonMsg);
}
- @Test()
+ @Test(expectedExceptions=ConfigException.class)
/**
* Start a handler an then give its hasAcceptableConfiguration a ConfigEntry with
* numerous invalid cases and single-valued attrs with duplicate values.
@@ -165,8 +164,8 @@
"ds-cfg-use-ssl: false",
"ds-cfg-ssl-client-auth-policy: optional",
"ds-cfg-ssl-cert-nickname: server-cert");
- LDAPConnectionHandler LDAPConnHandler=getLDAPHandlerInstance(BadHandlerEntry);
- //Add some invalid attrs and some duplicate attrs
+
+ // Add some invalid attrs and some duplicate attrs
Attribute a2=new Attribute(ATTR_LISTEN_PORT, String.valueOf(389));
Attribute a2a=new Attribute(ATTR_LISTEN_PORT, String.valueOf(70000));
Attribute a3=new Attribute(ATTR_LISTEN_ADDRESS, "localhost");
@@ -199,12 +198,8 @@
BadHandlerEntry.addAttribute(a13, null);
BadHandlerEntry.addAttribute(a14, null);
BadHandlerEntry.addAttribute(a15, null);
- LinkedList<String> reasons = new LinkedList<String>();
- ConfigEntry BadConfigEntry=new ConfigEntry(BadHandlerEntry, null );
- boolean ret=LDAPConnHandler.hasAcceptableConfiguration(BadConfigEntry, reasons);
- LDAPConnHandler.finalizeConnectionHandler(reasonMsg, true);
- LDAPConnHandler.processServerShutdown(reasonMsg);
- assertFalse(ret);
+
+ LdapTestCase.getConfiguration(BadHandlerEntry);
}
/**
@@ -313,12 +308,12 @@
GoodHandlerEntry.addAttribute(a14, null);
GoodHandlerEntry.addAttribute(a15, null);
LinkedList<String> reasons = new LinkedList<String>();
- ConfigEntry newConfigEntry=new ConfigEntry(GoodHandlerEntry, null );
+ LDAPConnectionHandlerCfg config = LdapTestCase.getConfiguration(GoodHandlerEntry);
//see if we're ok
- boolean ret=LDAPConnHandler.hasAcceptableConfiguration(newConfigEntry, reasons);
+ boolean ret=LDAPConnHandler.isConfigurationChangeAcceptable(config, reasons);
assertTrue(ret);
//apply it
- LDAPConnHandler.applyNewConfiguration(newConfigEntry, true);
+ LDAPConnHandler.applyConfigurationChange(config);
LDAPConnHandler.finalizeConnectionHandler(reasonMsg, true);
}
--
Gitblit v1.10.0