From be1a80c1ea26cb12c7cdc6ef0e1534199a027f9d Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 11 Feb 2011 23:00:49 +0000
Subject: [PATCH] Copy source files from trunk sdk keeping revision history

---
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnection.java                                            |  494 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequest.java                                |  133 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleTest.java                 |  163 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/FutureResultTransformer.java                              |  243 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StringPrepProfile.java                                    |  587 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteStringBuilder.java                                             | 1118 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java  |  133 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OrderingMatchingRuleTest.java                               |  135 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListenerOptions.java                                           |  229 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordSyntaxImpl.java                                 |  200 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1WriterTestCase.java                                       |  742 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyResponseControl.java                        |  418 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Reader.java                                       |  210 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResultImpl.java                           |  169 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequest.java                                        |   66 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ReaderTestCase.java                                       |  922 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java              |  217 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryWriterTestCase.java                                  |   96 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberEqualityMatchingRuleImpl.java                |   67 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleSyntaxTest.java                                 |   73 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SyntaxImpl.java                                             |  142 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequenceReader.java                                            |  505 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java                            |  784 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FacsimileNumberSyntaxImpl.java                              |  238 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestTestCase.java                                      |  136 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeFactory.java                                              |   54 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaElement.java                                          |  189 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListener.java                                                  |  383 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResult.java                               |  212 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractRequestImpl.java                                  |  145 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Predicate.java                                            |   57 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attribute.java                                                     |  484 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/RegexSyntaxTestCase.java                                    |   95 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java                 |  114 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Result.java                                              |  239 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAttribute.java                                             |  497 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificatePairSyntaxImpl.java                              |  106 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PrintableStringSyntaxImpl.java                              |  248 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BinarySyntaxImpl.java                                       |   98 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationType.java               |  323 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancingAlgorithm.java                                        |   49 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControl.java                   |  191 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericExtendedResultImpl.java               |   54 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableResultImpl.java                              |   39 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SynchronousConnection.java                                         |  388 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeUsage.java                                         |  110 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractLoadBalancingAlgorithm.java                                |  446 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AbandonRequestTestCase.java                               |   67 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractBindRequest.java                                  |   86 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Writer.java                                               |  391 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedAttribute.java                                               | 1045 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DigestMD5SASLBindRequestTestCase.java                     |  116 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPPasswordModify.java                         |  497 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java              |   53 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1.java                                                     |  226 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GetEffectiveRightsRequestControl.java                     |  427 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ja.properties                           |  531 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleImpl.java                   |   97 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractExtendedRequest.java                              |  141 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultReferenceImpl.java               |   53 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractMatchingRuleImpl.java                               |  133 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SubstringReader.java                                      |  184 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java                    |  200 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessageBuilder.java                                     |  435 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResultDecoder.java                       |  137 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/OpenDSTestCase.java                                                |  181 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeType.java                                          |  900 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/package-info.java                                                  |   35 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PostalAddressSyntaxImpl.java                                |  101 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AddRequestTestCase.java                                   |   71 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerformanceRunner.java                          | 1283 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ko.properties                           |  531 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableExtendedResultImpl.java              |   60 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPServerFilter.java                                     | 1163 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/DNTestCase.java                                                    |  980 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryReader.java                                              |   89 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractOrderingMatchingRuleImpl.java                       |   97 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/FileBasedArgument.java                          |  278 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFTestCase.java                                             |   44 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SortKey.java                                                       |  704 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/BindRequestTestCase.java                                  |   71 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/BooleanArgument.java                            |  126 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequestImpl.java                                    |  219 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DeleteRequestTestCase.java                                |   70 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Request.java                                              |   97 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnsupportedMessageException.java                          |   81 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultIOException.java                                        |   76 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousConnectionDecorator.java                      |  508 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/EntryChangeNotificationResponseControl.java               |  399 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiringResponseControl.java                      |  229 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPClientContext.java                                             |  171 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GenerateCoreSchema.java                                     |  407 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPServer.java                                                    |  789 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestListener.java                                                  | 1429 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DN.java                                                            |  813 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionException.java                                           |   47 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewResponseControl.java                       |  338 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleTest.java                     |  149 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubtreeDeleteRequestControl.java                          |  192 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TypesTestCase.java                                                 |  156 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ManageDsaITRequestControl.java                            |  194 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPMessageHandler.java                           |  236 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResponseImpl.java                                |  144 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java                  |   97 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortResponseControl.java                        |  376 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/package-info.java                                         |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierEqualityMatchingRuleImpl.java               |  179 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_CN.properties                        |  531 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeTest.java                                      |  648 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancer.java                                                  |  100 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityResponseControl.java                 |  226 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequest.java                                    |  181 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Response.java                                            |   99 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPExtendedFutureResultImpl.java                         |  113 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClass.java                                            |  797 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/package-info.java                                        |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java             | 1105 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FaxSyntaxImpl.java                                          |   99 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaTestCase.java                                         |   42 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSubstringMatchingRuleImpl.java               |   67 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleTest.java                  |   79 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControl.java                  |  570 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RDN.java                                                           |  420 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1ByteSequenceReader.java                                   |  562 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ByteSequenceOutputStream.java                             |  144 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FailoverLoadBalancingAlgorithm.java                                |  153 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleImpl.java                  |  116 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedResponseException.java                          |   72 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumOrderingMatchingRule.java                               |   73 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntryImpl.java                               |  360 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPCompare.java                                |  660 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeDescription.java                                          | 1478 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UUIDSyntaxTest.java                                         |   73 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java                |  175 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SyntaxTestCase.java                                         |   99 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/IntermediateResponseHandler.java                                   |   69 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyDNRequestTestCase.java                              |   69 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnectionFactory.java                                       |   68 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringEqualityMatchingRuleImpl.java                    |   49 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFReader.java                                       |  891 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/RecursiveFutureResult.java                                |  274 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/RDNTestCase.java                                                   |  475 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TeletexTerminalIdentifierSyntaxImpl.java                    |  268 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleUseSyntaxTest.java                              |   71 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaUtilsTest.java                                        |  114 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/TelexSyntaxTest.java                                        |   65 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/StringArgument.java                             |  147 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleImpl.java                        |   63 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ApplicationKeyManager.java                      |  335 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDOrderingMatchingRuleImpl.java                           |  131 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/messages/MessagesTestCase.java                                 |   39 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationContainer.java          |   53 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResult.java                                      |  192 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/EnumSyntaxTestCase.java                                     |  132 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRuleSyntaxImpl.java                             |  206 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedHashMapEntry.java                                            |  188 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactory.java             |  171 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequestImpl.java                                    |  153 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/Base64TestCase.java                                       |  238 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnection.java                                       | 1033 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleImpl.java                      |   82 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OtherMailboxSyntaxTest.java                                 |   63 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferReaderTestCase.java                             |   58 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java                      |  103 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attributes.java                                                    |  627 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyRequestControl.java                         |  195 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordReader.java                                       |   91 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequestImpl.java                           |  256 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringSyntaxImpl.java                                    |  125 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryWriter.java                                          |  362 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnectionFactory.java                                     |   90 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequest.java                                       |  222 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntriesTestCase.java                                               |  229 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/PlainSASLBindRequestTestCase.java                         |   69 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FilterVisitor.java                                                 |  234 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java               |   71 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/CompletedFutureResult.java                                |  196 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java                        |   40 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DeliveryMethodSyntaxImpl.java                               |  169 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/LDAPSyntaxTest.java                                         |  114 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV1RequestControl.java                          |  294 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SdkTestCase.java                                                   |   43 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_de.properties                           |  531 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/RealAttributesOnlyRequestControl.java                 |  192 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TreeMapEntry.java                                                  |  188 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstitutionSyntaxTestCase.java                             |  153 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GuideSyntaxImpl.java                                        |  427 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryReader.java                                    |  429 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentGroup.java                              |  208 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessage.java                                            |  527 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GenericControl.java                                       |  219 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousFutureResult.java                             |  483 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPWriter.java                                           |  677 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordExactEqualityMatchingRuleImpl.java              |   61 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterables.java                                            |  393 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_fr.properties                           |  531 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSubstringMatchingRuleImpl.java                 |   59 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AbstractSchemaElementTestCase.java                          |  197 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticatedConnectionFactory.java                                |  240 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortRequestControl.java                         |  393 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/IntegerArgument.java                            |  536 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ASCIICharProp.java                                        |  397 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractSASLBindRequest.java                              |   74 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/package-info.java                                         |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Matcher.java                                                       |  845 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSyntaxImpl.java                              |  200 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java                  |   68 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateSyntaxImpl.java                                  |  106 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaUtils.java                                            |  898 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AnonymousSASLBindRequestTestCase.java                     |   68 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResult.java                                          |  215 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/VirtualAttributesOnlyRequestControl.java              |  192 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/SimpleBindRequestTestCase.java                            |   68 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entries.java                                                       |  515 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java              |  213 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java |  102 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClient.java                                           |   99 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanSyntaxImpl.java                                      |  105 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequest.java                              |  202 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResultImpl.java                                  |  246 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Syntax.java                                                 |  430 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java                           |  201 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchRequestControl.java                       |  414 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthorizationException.java                                        |   62 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequence.java                                                  |  326 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthenticatedConnectionFactory.java             |  473 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StringPrepProfileTestCase.java                            |  119 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeSyntaxImpl.java                              | 1411 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java                    |  435 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.java                   |   61 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequest.java                                           |  243 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordSyntaxImpl.java                                 |  340 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryFactory.java                                                  |   53 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Filter.java                                                        | 2123 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SimplePagedResultsControl.java                            |  344 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequest.java                                        |  185 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/HeartBeatConnectionFactory.java                                    |  405 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequest.java                                      |  263 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFWriter.java                                       |  544 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitor.java                                      |  109 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassSyntaxImpl.java                                  |  217 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryWriter.java                                              |  104 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.java                    |   61 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java                    |  173 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/DataSource.java                                 |  589 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiChoiceArgument.java                        |  271 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ReferralException.java                                             |   49 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizedIllegalArgumentException.java                             |   95 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FutureResult.java                                                  |  139 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResult.java                                       |  174 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Responses.java                                           |  665 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/LDAPSyntaxDescriptionSyntaxImpl.java                        |  228 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindRequest.java                                          |  114 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPListenerImpl.java                                     |  182 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadResponseControl.java                              |  259 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequest.java                                        |  131 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUse.java                                        |  372 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerFirstComponentEqualityMatchingRuleImpl.java          |  123 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResultDecoder.java                               |  134 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableBindResultImpl.java                          |   57 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSyntaxImpl.java                                |  135 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/controls/ControlsTestCase.java                                     |   60 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableCompareResultImpl.java                       |   45 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiablePasswordModifyExtendedResultImpl.java        |   61 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1OutputStreamWriter.java                                   |  562 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Requests.java                                             | 1710 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleTest.java                      |   76 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordReader.java                                   |  751 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Modification.java                                                  |  125 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListSubstringMatchingRuleImpl.java                |  141 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringOrderingMatchingRuleImpl.java                    |   49 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPMessageHandler.java                                   |  159 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResultImpl.java                                      |  145 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferWriter.java                                     |  741 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ToolConstants.java                              |  619 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryReaderTestCase.java                                  |  152 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubentriesRequestControl.java                             |  195 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedRequest.java             | 1140 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDEqualityMatchingRuleImpl.java                           |  130 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleImpl.java                      |   83 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPSearchFutureResultImpl.java                           |  141 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionEventListener.java                                       |   89 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/Control.java                                              |   96 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperation.java                   |   56 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_TW.properties                        |  531 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControlTestCase.java           |   74 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionFactory.java                                             |   86 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleImpl.java                     |   82 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeException.java                                               |  150 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1OutputStreamWriterTestCase.java                           |   69 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java                        |  132 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Writer.java                                       |  156 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringSyntaxTest.java                                    |   64 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyRequestTestCase.java                                |   75 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaBuilder.java                                          | 3134 +
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/package-info.java                                   |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java                            |  209 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java                   |  196 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerEqualityMatchingRuleImpl.java                        |   66 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringSyntaxImpl.java                              |  126 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLFilter.java                                           |   51 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExternalSASLBindRequestTestCase.java                      |   67 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequest.java                                        |  356 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchema.java                                             | 2675 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRuleSyntaxImpl.java                               |  204 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiColumnPrinter.java                         |  547 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java                            |  352 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Collections2.java                                         |  507 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ConflictingSchemaElementException.java                      |   57 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleImpl.java                     |   83 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRule.java                                       |  344 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSubstringMatchingRuleImpl.java                   |   49 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleSyntaxImpl.java                                 |  215 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ByteSequenceReaderTestCase.java                           |   48 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequest.java                                   |  163 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindRequest.java                                      |  108 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/ASCIICharPropTestCase.java                                |  183 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequestImpl.java                            |  249 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiredResponseControl.java                       |  194 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConstants.java                                        |  332 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedRequestException.java                           |   71 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java              |  171 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Functions.java                                            |  395 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequest.java                             |  546 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/RegexSyntaxImpl.java                                        |  127 
 opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/ToolsTestCase.java                              |   45 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java                          |  280 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleImpl.java                      |   86 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateListSyntaxImpl.java                              |  107 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java                |   53 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransportTestCase.java                   |   71 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractEntry.java                                                 |  387 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UnknownSchemaElementException.java                          |   55 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransport.java                           |   80 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TrustManagers.java                                                 |  551 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameSyntaxImpl.java                            |   95 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/KeywordEqualityMatchingRuleImpl.java                        |  179 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaConstants.java                                        | 1535 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResult.java                        |  230 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleTest.java                   |   85 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/responses/ResponsesTestCase.java                                   |   46 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityRequestControl.java                  |  199 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java                        |  105 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUseSyntaxImpl.java                              |  218 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionSecurityLayer.java                                       |   83 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CompareRequestTestCase.java                               |   71 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelexNumberSyntaxImpl.java                                  |  226 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionChangeRecordWriter.java                             |  322 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Constants.java                                            |  169 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPModify.java                                 |  798 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultException.java                                          |  219 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetSymmetricKeyExtendedRequest.java                 |  335 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExtendedRequestTestCase.java                              |   50 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SupportedAlgorithmSyntaxImpl.java                           |  108 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleTest.java                  |  149 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequest.java                             |  155 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleImpl.java                     |  100 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntryTestCase.java                                                 |  119 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GuideSyntaxTest.java                                        |   69 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java                  |   50 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListEqualityMatchingRuleImpl.java                 |   96 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordExactEqualityMatchingRuleImpl.java              |   78 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequest.java                        |  276 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecord.java                                             |   72 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GenericBindRequestTestCase.java                           |   77 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GSSAPISASLBindRequestTestCase.java                        |  111 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterators.java                                            |  547 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchChangeType.java                           |   99 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleTest.java                    |  161 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AssertionRequestControl.java                              |  242 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ModificationType.java                                              |  208 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyErrorType.java                              |  129 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SchemaResolver.java                                                |   63 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaException.java                                        |   87 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Argument.java                                   |  789 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultReferenceIOException.java                              |   81 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Assertion.java                                                     |   48 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/WordEqualityMatchingRuleImpl.java                           |  179 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java                       |   95 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionPool.java                                                |  881 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableBindRequest.java                      |   58 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericIntermediateResponseImpl.java         |   55 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IA5StringSyntaxImpl.java                                    |  130 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RootDSE.java                                                       |  510 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java             |   51 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Base64.java                                               |  383 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordWriter.java                                   |  471 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequestImpl.java                                |  187 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_es.properties                           |  531 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPBindFutureResultImpl.java                             |  101 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestsTestCase.java                                     |   46 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableIntermediateResponseImpl.java        |   61 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringTestCase.java                                            |  195 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPUrlTestCase.java                                               |  232 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressSyntaxImpl.java                          |  112 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/package-info.java                                         |   34 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPListenerTestCase.java                                          | 1062 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPConnectionFactory.java                                         |  244 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AsynchronousConnection.java                                        |  850 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultHandler.java                                           |   81 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPTestCase.java                                         |   45 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CoreSchemaTest.java                                         |   47 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSyntaxImpl.java                                  |   98 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/InternalConnection.java                                   |  361 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequest.java                                |  517 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequest.java                                       |   92 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConsoleApplication.java                         |  586 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPSearch.java                                 | 1298 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java             |  165 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringEqualityMatchingRuleImpl.java                  |   60 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/InternalConnectionFactory.java                                     |  116 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StaticUtilsTestCase.java                                  |  227 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StaticUtils.java                                          | 2271 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractIntermediateResponse.java                        |  129 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequestImpl.java                                       |  371 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequest.java                                 |  229 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UTCTimeSyntaxTest.java                                      |  112 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java        |   88 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultCode.java                                                    |  747 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringBuilderTestCase.java                                     |  296 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/package-info.java                               |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLDecoderTransformer.java                               |  101 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleTest.java                     |   90 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LinkedAttributeTestCase.java                                       |  486 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequest.java                               |  147 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PermissiveModifyRequestControl.java                       |  201 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLEncoderTransformer.java                               |  101 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRule.java                                         |  616 
 opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages.properties                              | 5870 ++
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteString.java                                                    |  717 
 opendj3/opendj-modules/opendj-sdk/src/main/javadoc/overview.html                                                                  |  103 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestTestCase.java                       |   69 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeSyntaxTest.java                                |  101 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleTest.java                      |   83 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaCompatOptions.java                                    |  162 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReference.java                               |   97 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connections.java                                                   |  342 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerOrderingMatchingRuleImpl.java                        |   67 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadRequestControl.java                               |  354 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Function.java                                             |   58 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameForm.java                                               |  452 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableWhoAmIExtendedResultImpl.java                |   53 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentException.java                          |   86 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResultImpl.java                      |  149 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/FilterTestCase.java                                                |  219 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleTest.java                      |   78 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClientImpl.java                                       |  151 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequest.java                                |  143 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConditionResult.java                                               |  298 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequestImpl.java                                   |  251 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleTest.java                        |   85 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPOptions.java                                                   |  350 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordWriter.java                                       |  183 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponseImpl.java                     |  170 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.java                 |   83 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPClientFilter.java                                     |  644 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeOrderingMatchingRuleImpl.java                |   50 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPUrl.java                                                       |  978 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AssertionFailureException.java                                     |   49 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSyntaxImpl.java                                     |   77 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UTCTimeSyntaxImpl.java                                      |  734 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestCaseUtils.java                                                 |  175 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/TimeoutChecker.java                                       |  157 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AVA.java                                                           |  977 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java                            |  170 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassType.java                                        |   81 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControlTestCase.java          |   95 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPReader.java                                           | 1817 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractMapEntry.java                                              |  200 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ControlDecoder.java                                       |   69 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerSyntaxImpl.java                                      |  227 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferWriterTestCase.java                             |   87 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CountryStringSyntaxImpl.java                                |  133 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferReader.java                                     |  821 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entry.java                                                         |  550 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameAndOptionalUIDSyntaxImpl.java                           |  151 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeEqualityMatchingRuleImpl.java                |   50 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/JPEGSyntaxImpl.java                                         |   98 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java                      |  539 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SuiteRunner.java                                                   |   54 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleTest.java                                       |  136 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumSyntaxImpl.java                                         |  192 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Validator.java                                            |  213 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/IA5StringSyntaxTest.java                                    |   63 
 opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/UtilTestCase.java                                         |   44 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequestImpl.java                                    |  371 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SizeLimitInputStream.java                                 |  219 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchScope.java                                                   |  205 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPCompareFutureResultImpl.java                          |   92 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java                         |  147 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticationException.java                                       |   60 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractFilterVisitor.java                                         |  220 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ModRate.java                                    |  429 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RequestHandler.java                                                |  245 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponse.java                         |  123 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationSyntaxImpl.java                          |  113 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConstraintViolationException.java                                  |   80 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeTypeSyntaxImpl.java                                |  280 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnhancedGuideSyntaxImpl.java                                |  181 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResultImpl.java                                   |  115 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/package-info.java                                             |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TimeoutResultException.java                                        |   47 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OtherMailboxSyntaxImpl.java                                 |  173 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java                           |  287 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java                          |  214 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequest.java                                      |  120 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SubstringAssertionSyntaxImpl.java                           |  148 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthRate.java                                   |  774 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequestImpl.java                                    |   87 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PromptingTrustManager.java                      |  482 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedRequest.java                 |  249 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPFutureResultImpl.java                                 |   93 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connection.java                                                    | 1260 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java               |   54 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequest.java                              |  163 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequestDecoder.java                               |   67 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentParser.java                             | 1919 
 opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactoryTestCase.java     |   73 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequestImpl.java                                  |  267 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.java              |   71 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/MatchedValuesRequestControl.java                          |  463 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GeneralizedTimeSyntaxTest.java                              |   74 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OIDSyntaxImpl.java                                          |  108 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/package-info.java                                         |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequestImpl.java                                   |  115 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1InputStreamReaderTestCase.java                            |   46 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ConnectionFactoryTestCase.java                                     |  308 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SSLContextBuilder.java                                             |  255 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequestImpl.java                             |  275 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFStream.java                                       |  172 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAsynchronousConnection.java                                |  430 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadResponseControl.java                               |  260 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java                         |  656 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindClientImpl.java                                   |  275 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstringMatchingRuleTest.java                              |  263 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitorWriter.java                                |  132 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationEqualityMatchingRuleImpl.java            |   85 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/LocalizableMessageDescriptor.java                         | 1091 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/AttributeDescriptionTestCase.java                                  |  373 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/UnbindRequestTestCase.java                                |   66 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequestImpl.java                               |  211 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/CLIException.java                               |  102 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressEqualityMatchingRuleImpl.java            |   85 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultHandler.java                                                 |   71 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchemaImpl.java                                         | 1090 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Reader.java                                               |  431 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnection.java                                              |  109 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadRequestControl.java                                |  354 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReferenceImpl.java                           |  132 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDSyntaxImpl.java                                         |  150 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DITContentRuleSyntaxTest.java                               |   92 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRule.java                                           |  475 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryWriter.java                                    |  158 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResult.java                                |  223 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResult.java                              |  143 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPUtils.java                                            |  727 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java                               |  201 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java                  |  911 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/package-info.java                                           |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableRequest.java                          |  173 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/CancelledResultException.java                                      |   54 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleImpl.java                    |  102 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Utils.java                                      |  733 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java                |   43 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java                       |   55 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyWarningType.java                            |   92 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UniqueMemberEqualityMatchingRuleImpl.java                   |   50 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV2RequestControl.java                          |  283 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java                        |   63 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/package-info.java                                     |   34 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPFutureResultImpl.java                         |  174 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EqualLengthApproximateMatchingRuleImpl.java                 |   67 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/ApproximateMatchingRuleTest.java                            |  163 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/package-info.java                                             |   39 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteSequenceTestCase.java                                          |  247 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ResultImpl.java                                          |  101 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DereferenceAliasesPolicy.java                                      |  218 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/KeyManagers.java                                                   |  398 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryReader.java                                          |  468 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleImpl.java                                       |  157 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SynchronousConnectionTestCase.java                                 |  182 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Schema.java                                                 | 2617 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringOrderingMatchingRuleImpl.java                  |   59 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/MultipleEntriesFoundException.java                                 |   51 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableException.java                                          |   44 
 opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java                  |  183 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/IntermediateResponse.java                                |  112 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1InputStreamReader.java                                    |  786 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewRequestControl.java                        |  525 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RoundRobinLoadBalancingAlgorithm.java                              |  178 
 opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/SearchRate.java                                 |  525 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeOptions.java                                                 |  241 
 opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleTest.java                     |   88 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryNotFoundException.java                                        |   60 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameFormSyntaxImpl.java                                     |  222 
 opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntry.java                                   |  240 
 596 files changed, 172,163 insertions(+), 0 deletions(-)

diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ApplicationKeyManager.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ApplicationKeyManager.java
new file mode 100755
index 0000000..b58578e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ApplicationKeyManager.java
@@ -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
+ *
+ *
+ *      Copyright 2008-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2009 Parametric Technology Corporation (PTC)
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import java.net.Socket;
+import java.security.*;
+import java.security.cert.X509Certificate;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+
+
+
+/**
+ * This class is in charge of checking whether the certificates that are
+ * presented are trusted or not. This implementation tries to check also that
+ * the subject DN of the certificate corresponds to the host passed using the
+ * setHostName method.
+ *<p>
+ * The constructor tries to use a default TrustManager from the system and if it
+ * cannot be retrieved this class will only accept the certificates explicitly
+ * accepted by the user (and specified by calling acceptCertificate).
+ *<p>
+ * NOTE: this class is not aimed to be used when we have connections in
+ * parallel.
+ */
+final class ApplicationKeyManager implements X509KeyManager
+{
+  static private final Logger LOG = Logger
+      .getLogger(ApplicationKeyManager.class.getName());
+
+  /**
+   * The default keyManager.
+   */
+  private X509KeyManager keyManager = null;
+
+
+
+  /**
+   * The default constructor.
+   *
+   * @param keystore
+   *          The keystore to use for this keymanager.
+   * @param password
+   *          The keystore password to use for this keymanager.
+   */
+  ApplicationKeyManager(final KeyStore keystore, final char[] password)
+  {
+    KeyManagerFactory kmf = null;
+    String userSpecifiedAlgo = System
+        .getProperty("org.opends.admin.keymanageralgo");
+    String userSpecifiedProvider = System
+        .getProperty("org.opends.admin.keymanagerprovider");
+
+    // Handle IBM specific cases if the user did not specify a algorithm
+    // and/or provider.
+    final String vendor = System.getProperty("java.vendor");
+    if (vendor.startsWith("IBM"))
+    {
+      if (userSpecifiedAlgo == null)
+      {
+        userSpecifiedAlgo = "IbmX509";
+      }
+      if (userSpecifiedProvider == null)
+      {
+        userSpecifiedProvider = "IBMJSSE2";
+      }
+    }
+
+    // Have some fallbacks to choose the provider and algorith of the
+    // key manager. First see if the user wanted to use something
+    // specific, then try with the SunJSSE provider and SunX509
+    // algorithm. Finally, fallback to the default algorithm of the JVM.
+    final String[] preferredProvider = { userSpecifiedProvider, "SunJSSE",
+        null, null };
+    final String[] preferredAlgo = { userSpecifiedAlgo, "SunX509", "SunX509",
+        TrustManagerFactory.getDefaultAlgorithm() };
+    for (int i = 0; i < preferredProvider.length && keyManager == null; i++)
+    {
+      final String provider = preferredProvider[i];
+      final String algo = preferredAlgo[i];
+      if (algo == null)
+      {
+        continue;
+      }
+      try
+      {
+        if (provider != null)
+        {
+          kmf = KeyManagerFactory.getInstance(algo, provider);
+        }
+        else
+        {
+          kmf = KeyManagerFactory.getInstance(algo);
+        }
+        kmf.init(keystore, password);
+        final KeyManager kms[] = kmf.getKeyManagers();
+        /*
+         * Iterate over the returned keymanagers, look for an instance of
+         * X509KeyManager. If found, use that as our "default" key manager.
+         */
+        for (final KeyManager km : kms)
+        {
+          if (kms[i] instanceof X509KeyManager)
+          {
+            keyManager = (X509KeyManager) km;
+            break;
+          }
+        }
+      }
+      catch (final NoSuchAlgorithmException e)
+      {
+        // Nothing to do. Maybe we should avoid this and be strict, but
+        // we are in a best effor mode.
+        LOG.log(Level.WARNING, "Error with the algorithm", e);
+      }
+      catch (final KeyStoreException e)
+      {
+        // Nothing to do. Maybe we should avoid this and be strict, but
+        // we are in a best effor mode..
+        LOG.log(Level.WARNING, "Error with the keystore", e);
+      }
+      catch (final UnrecoverableKeyException e)
+      {
+        // Nothing to do. Maybe we should avoid this and be strict, but
+        // we are in a best effor mode.
+        LOG.log(Level.WARNING, "Error with the key", e);
+      }
+      catch (final NoSuchProviderException e)
+      {
+        // Nothing to do. Maybe we should avoid this and be strict, but
+        // we are in a best effor mode.
+        LOG.log(Level.WARNING, "Error with the provider", e);
+      }
+    }
+  }
+
+
+
+  /**
+   * Choose an alias to authenticate the client side of a secure socket given
+   * the public key type and the list of certificate issuer authorities
+   * recognized by the peer (if any).
+   *
+   * @param keyType
+   *          the key algorithm type name(s), ordered with the most-preferred
+   *          key type first.
+   * @param issuers
+   *          the list of acceptable CA issuer subject names or null if it does
+   *          not matter which issuers are used.
+   * @param socket
+   *          the socket to be used for this connection. This parameter can be
+   *          null, in which case this method will return the most generic alias
+   *          to use.
+   * @return the alias name for the desired key, or null if there are no
+   *         matches.
+   */
+  public String chooseClientAlias(final String[] keyType,
+      final Principal[] issuers, final Socket socket)
+  {
+    if (keyManager != null)
+    {
+      return keyManager.chooseClientAlias(keyType, issuers, socket);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Choose an alias to authenticate the client side of a secure socket given
+   * the public key type and the list of certificate issuer authorities
+   * recognized by the peer (if any).
+   *
+   * @param keyType
+   *          the key algorithm type name(s), ordered with the most-preferred
+   *          key type first.
+   * @param issuers
+   *          the list of acceptable CA issuer subject names or null if it does
+   *          not matter which issuers are used.
+   * @param socket
+   *          the socket to be used for this connection. This parameter can be
+   *          null, in which case this method will return the most generic alias
+   *          to use.
+   * @return the alias name for the desired key, or null if there are no
+   *         matches.
+   */
+  public String chooseServerAlias(final String keyType,
+      final Principal[] issuers, final Socket socket)
+  {
+    if (keyManager != null)
+    {
+      return keyManager.chooseServerAlias(keyType, issuers, socket);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Returns the certificate chain associated with the given alias.
+   *
+   * @param alias
+   *          the alias name
+   * @return the certificate chain (ordered with the user's certificate first
+   *         and the root certificate authority last), or null if the alias
+   *         can't be found.
+   */
+  public X509Certificate[] getCertificateChain(final String alias)
+  {
+    if (keyManager != null)
+    {
+      return keyManager.getCertificateChain(alias);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Get the matching aliases for authenticating the server side of a secure
+   * socket given the public key type and the list of certificate issuer
+   * authorities recognized by the peer (if any).
+   *
+   * @param keyType
+   *          the key algorithm type name
+   * @param issuers
+   *          the list of acceptable CA issuer subject names or null if it does
+   *          not matter which issuers are used.
+   * @return an array of the matching alias names, or null if there were no
+   *         matches.
+   */
+  public String[] getClientAliases(final String keyType,
+      final Principal[] issuers)
+  {
+    if (keyManager != null)
+    {
+      return keyManager.getClientAliases(keyType, issuers);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Returns the key associated with the given alias.
+   *
+   * @param alias
+   *          the alias name
+   * @return the requested key, or null if the alias can't be found.
+   */
+  public PrivateKey getPrivateKey(final String alias)
+  {
+    if (keyManager != null)
+    {
+      return keyManager.getPrivateKey(alias);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Get the matching aliases for authenticating the server side of a secure
+   * socket given the public key type and the list of certificate issuer
+   * authorities recognized by the peer (if any).
+   *
+   * @param keyType
+   *          the key algorithm type name
+   * @param issuers
+   *          the list of acceptable CA issuer subject names or null if it does
+   *          not matter which issuers are used.
+   * @return an array of the matching alias names, or null if there were no
+   *         matches.
+   */
+  public String[] getServerAliases(final String keyType,
+      final Principal[] issuers)
+  {
+    if (keyManager != null)
+    {
+      return keyManager.getServerAliases(keyType, issuers);
+    }
+    else
+    {
+      return null;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Argument.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Argument.java
new file mode 100644
index 0000000..a87c623
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Argument.java
@@ -0,0 +1,789 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines a generic argument that may be used in the argument list
+ * for an application. This is an abstract class that must be subclassed in
+ * order to provide specific functionality.
+ */
+abstract class Argument
+{
+  // Indicates whether this argument should be hidden in the usage
+  // information.
+  private boolean isHidden;
+
+  // Indicates whether this argument may be specified more than once for
+  // multiple values.
+  private boolean isMultiValued;
+
+  // Indicates whether this argument was provided in the set of
+  // command-line
+  // arguments.
+  private boolean isPresent;
+
+  // Indicates whether this argument is required to have a value.
+  private boolean isRequired;
+
+  // Indicates whether this argument requires a value.
+  private boolean needsValue;
+
+  // The single-character identifier for this argument.
+  private final Character shortIdentifier;
+
+  // The unique ID of the description for this argument.
+  private final LocalizableMessage description;
+
+  // The set of values for this argument.
+  private final LinkedList<String> values;
+
+  // The default value for the argument if none other is provided.
+  private String defaultValue;
+
+  // The long identifier for this argument.
+  private final String longIdentifier;
+
+  // The generic name that will be used to refer to this argument.
+  private final String name;
+
+  // The name of the property that can be used to set the default value.
+  private String propertyName;
+
+  // The value placeholder for this argument, which will be used in
+  // usage
+  // information.
+  private LocalizableMessage valuePlaceholder;
+
+  // Indicates whether this argument was provided in the set of
+  // properties
+  // found is a properties file.
+  private boolean isValueSetByProperty;
+
+
+
+  /**
+   * Creates a new argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  protected Argument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean isMultiValued, final boolean needsValue,
+      final LocalizableMessage valuePlaceholder, final String defaultValue,
+      final String propertyName, final LocalizableMessage description)
+      throws ArgumentException
+  {
+    this.name = name;
+    this.shortIdentifier = shortIdentifier;
+    this.longIdentifier = longIdentifier;
+    this.isRequired = isRequired;
+    this.isMultiValued = isMultiValued;
+    this.needsValue = needsValue;
+    this.valuePlaceholder = valuePlaceholder;
+    this.defaultValue = defaultValue;
+    this.propertyName = propertyName;
+    this.description = description;
+    this.isValueSetByProperty = false;
+
+    if ((shortIdentifier == null) && (longIdentifier == null))
+    {
+      final LocalizableMessage message = ERR_ARG_NO_IDENTIFIER.get(name);
+      throw new ArgumentException(message);
+    }
+
+    if (needsValue && (valuePlaceholder == null))
+    {
+      final LocalizableMessage message = ERR_ARG_NO_VALUE_PLACEHOLDER.get(name);
+      throw new ArgumentException(message);
+    }
+
+    values = new LinkedList<String>();
+    isPresent = false;
+    isHidden = false;
+  }
+
+
+
+  /**
+   * Adds a value to the set of values for this argument. This should only be
+   * called if the value is allowed by the <CODE>valueIsAcceptable</CODE>
+   * method.
+   *
+   * @param valueString
+   *          The string representation of the value to add to this argument.
+   */
+  public void addValue(final String valueString)
+  {
+    values.add(valueString);
+  }
+
+
+
+  /**
+   * Clears the set of values assigned to this argument.
+   */
+  public void clearValues()
+  {
+    values.clear();
+  }
+
+
+
+  /**
+   * Retrieves the value of this argument as a <CODE>Boolean</CODE>.
+   *
+   * @return The value of this argument as a <CODE>Boolean</CODE>.
+   * @throws ArgumentException
+   *           If this argument cannot be interpreted as a Boolean value.
+   */
+  public boolean getBooleanValue() throws ArgumentException
+  {
+    if (values.isEmpty())
+    {
+      final LocalizableMessage message = ERR_ARG_NO_BOOLEAN_VALUE.get(name);
+      throw new ArgumentException(message);
+    }
+
+    final Iterator<String> iterator = values.iterator();
+    final String valueString = toLowerCase(iterator.next());
+
+    boolean booleanValue;
+    if (valueString.equals("true") || valueString.equals("yes")
+        || valueString.equals("on") || valueString.equals("1"))
+    {
+      booleanValue = true;
+    }
+    else if (valueString.equals("false") || valueString.equals("no")
+        || valueString.equals("off") || valueString.equals("0"))
+    {
+      booleanValue = false;
+    }
+    else
+    {
+      final LocalizableMessage message = ERR_ARG_CANNOT_DECODE_AS_BOOLEAN.get(
+          valueString, name);
+      throw new ArgumentException(message);
+    }
+
+    if (iterator.hasNext())
+    {
+      final LocalizableMessage message = ERR_ARG_BOOLEAN_MULTIPLE_VALUES
+          .get(name);
+      throw new ArgumentException(message);
+    }
+    else
+    {
+      return booleanValue;
+    }
+  }
+
+
+
+  /**
+   * Retrieves the default value that will be used for this argument if it is
+   * not specified on the command line and it is not set from a properties file.
+   *
+   * @return The default value that will be used for this argument if it is not
+   *         specified on the command line and it is not set from a properties
+   *         file, or <CODE>null</CODE> if there is no default value.
+   */
+  public String getDefaultValue()
+  {
+    return defaultValue;
+  }
+
+
+
+  /**
+   * Retrieves the human-readable description for this argument.
+   *
+   * @return The human-readable description for this argument.
+   */
+  public LocalizableMessage getDescription()
+  {
+    return description != null ? description : LocalizableMessage.EMPTY;
+  }
+
+
+
+  /**
+   * Retrieves the value of this argument as an integer.
+   *
+   * @return The value of this argument as an integer.
+   * @throws ArgumentException
+   *           If there are multiple values, or the value cannot be parsed as an
+   *           integer.
+   */
+  public double getDoubleValue() throws ArgumentException
+  {
+    if (values.isEmpty())
+    {
+      final LocalizableMessage message = ERR_ARG_NO_INT_VALUE.get(name);
+      throw new ArgumentException(message);
+    }
+
+    final Iterator<String> iterator = values.iterator();
+    final String valueString = iterator.next();
+
+    double intValue;
+    try
+    {
+      intValue = Double.parseDouble(valueString);
+    }
+    catch (final Exception e)
+    {
+      final LocalizableMessage message = ERR_ARG_CANNOT_DECODE_AS_INT.get(
+          valueString, name);
+      throw new ArgumentException(message, e);
+    }
+
+    if (iterator.hasNext())
+    {
+      final LocalizableMessage message = ERR_ARG_INT_MULTIPLE_VALUES.get(name);
+      throw new ArgumentException(message);
+    }
+    else
+    {
+      return intValue;
+    }
+  }
+
+
+
+  /**
+   * Retrieves the set of values for this argument as a list of integers.
+   *
+   * @return A list of the integer representations of the values for this
+   *         argument.
+   * @throws ArgumentException
+   *           If any of the values cannot be parsed as an integer.
+   */
+  public LinkedList<Double> getDoubleValues() throws ArgumentException
+  {
+    final LinkedList<Double> intList = new LinkedList<Double>();
+
+    final Iterator<String> iterator = values.iterator();
+    while (iterator.hasNext())
+    {
+      final String valueString = iterator.next();
+
+      try
+      {
+        intList.add(Double.valueOf(valueString));
+      }
+      catch (final Exception e)
+      {
+        final LocalizableMessage message = ERR_ARG_CANNOT_DECODE_AS_INT.get(
+            valueString, name);
+        throw new ArgumentException(message, e);
+      }
+    }
+
+    return intList;
+  }
+
+
+
+  /**
+   * Retrieves the value of this argument as an integer.
+   *
+   * @return The value of this argument as an integer.
+   * @throws ArgumentException
+   *           If there are multiple values, or the value cannot be parsed as an
+   *           integer.
+   */
+  public int getIntValue() throws ArgumentException
+  {
+    if (values.isEmpty())
+    {
+      final LocalizableMessage message = ERR_ARG_NO_INT_VALUE.get(name);
+      throw new ArgumentException(message);
+    }
+
+    final Iterator<String> iterator = values.iterator();
+    final String valueString = iterator.next();
+
+    int intValue;
+    try
+    {
+      intValue = Integer.parseInt(valueString);
+    }
+    catch (final Exception e)
+    {
+      final LocalizableMessage message = ERR_ARG_CANNOT_DECODE_AS_INT.get(
+          valueString, name);
+      throw new ArgumentException(message, e);
+    }
+
+    if (iterator.hasNext())
+    {
+      final LocalizableMessage message = ERR_ARG_INT_MULTIPLE_VALUES.get(name);
+      throw new ArgumentException(message);
+    }
+    else
+    {
+      return intValue;
+    }
+  }
+
+
+
+  /**
+   * Retrieves the set of values for this argument as a list of integers.
+   *
+   * @return A list of the integer representations of the values for this
+   *         argument.
+   * @throws ArgumentException
+   *           If any of the values cannot be parsed as an integer.
+   */
+  public LinkedList<Integer> getIntValues() throws ArgumentException
+  {
+    final LinkedList<Integer> intList = new LinkedList<Integer>();
+
+    final Iterator<String> iterator = values.iterator();
+    while (iterator.hasNext())
+    {
+      final String valueString = iterator.next();
+
+      try
+      {
+        intList.add(Integer.valueOf(valueString));
+      }
+      catch (final Exception e)
+      {
+        final LocalizableMessage message = ERR_ARG_CANNOT_DECODE_AS_INT.get(
+            valueString, name);
+        throw new ArgumentException(message, e);
+      }
+    }
+
+    return intList;
+  }
+
+
+
+  /**
+   * Retrieves the long (multi-character) identifier that may be used to specify
+   * the value of this argument.
+   *
+   * @return The long (multi-character) identifier that may be used to specify
+   *         the value of this argument.
+   */
+  public String getLongIdentifier()
+  {
+    return longIdentifier;
+  }
+
+
+
+  /**
+   * Retrieves the generic name that will be used to refer to this argument.
+   *
+   * @return The generic name that will be used to refer to this argument.
+   */
+  public String getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * Retrieves the name of a property in a properties file that may be used to
+   * set the default value for this argument if it is present. A value read from
+   * a properties file will override the default value returned from the
+   * <CODE>getDefaultValue</CODE>, but the properties file value will be
+   * overridden by a value supplied on the command line.
+   *
+   * @return The name of a property in a properties file that may be used to set
+   *         the default value for this argument if it is present.
+   */
+  public String getPropertyName()
+  {
+    return propertyName;
+  }
+
+
+
+  /**
+   * Retrieves the single-character identifier that may be used to specify the
+   * value of this argument.
+   *
+   * @return The single-character identifier that may be used to specify the
+   *         value of this argument, or <CODE>null</CODE> if there is none.
+   */
+  public Character getShortIdentifier()
+  {
+    return shortIdentifier;
+  }
+
+
+
+  /**
+   * Retrieves the string vale for this argument. If it has multiple values,
+   * then the first will be returned. If it does not have any values, then the
+   * default value will be returned.
+   *
+   * @return The string value for this argument, or <CODE>null</CODE> if there
+   *         are no values and no default value has been given.
+   */
+  public String getValue()
+  {
+    if (values.isEmpty())
+    {
+      return defaultValue;
+    }
+
+    return values.getFirst();
+  }
+
+
+
+  /**
+   * Retrieves the value placeholder that will be displayed for this argument in
+   * the generated usage information.
+   *
+   * @return The value placeholder that will be displayed for this argument in
+   *         the generated usage information, or <CODE>null</CODE> if there is
+   *         none.
+   */
+  public LocalizableMessage getValuePlaceholder()
+  {
+    return valuePlaceholder;
+  }
+
+
+
+  /**
+   * Retrieves the set of string values for this argument.
+   *
+   * @return The set of string values for this argument.
+   */
+  public LinkedList<String> getValues()
+  {
+    return values;
+  }
+
+
+
+  /**
+   * Indicates whether this argument has at least one value.
+   *
+   * @return <CODE>true</CODE> if this argument has at least one value, or
+   *         <CODE>false</CODE> if it does not have any values.
+   */
+  public boolean hasValue()
+  {
+    return (!values.isEmpty());
+  }
+
+
+
+  /**
+   * Indicates whether this argument should be hidden from the usage
+   * information.
+   *
+   * @return <CODE>true</CODE> if this argument should be hidden from the usage
+   *         information, or <CODE>false</CODE> if not.
+   */
+  public boolean isHidden()
+  {
+    return isHidden;
+  }
+
+
+
+  /**
+   * Indicates whether this argument may be provided more than once on the
+   * command line to specify multiple values.
+   *
+   * @return <CODE>true</CODE> if this argument may be provided more than once
+   *         on the command line to specify multiple values, or
+   *         <CODE>false</CODE> if it may have at most one value.
+   */
+  public boolean isMultiValued()
+  {
+    return isMultiValued;
+  }
+
+
+
+  /**
+   * Indicates whether this argument is present in the parsed set of
+   * command-line arguments.
+   *
+   * @return <CODE>true</CODE> if this argument is present in the parsed set of
+   *         command-line arguments, or <CODE>false</CODE> if not.
+   */
+  public boolean isPresent()
+  {
+    return isPresent;
+  }
+
+
+
+  /**
+   * Indicates whether this argument is required to have at least one value.
+   *
+   * @return <CODE>true</CODE> if this argument is required to have at least one
+   *         value, or <CODE>false</CODE> if it does not need to have a value.
+   */
+  public boolean isRequired()
+  {
+    return isRequired;
+  }
+
+
+
+  /**
+   * Indicates whether this argument was provided in the set of properties found
+   * is a properties file.
+   *
+   * @return <CODE>true</CODE> if this argument was provided in the set of
+   *         properties found is a properties file, or <CODE>false</CODE> if
+   *         not.
+   */
+  public boolean isValueSetByProperty()
+  {
+    return isValueSetByProperty;
+  }
+
+
+
+  /**
+   * Indicates whether a value must be provided with this argument if it is
+   * present.
+   *
+   * @return <CODE>true</CODE> if a value must be provided with the argument if
+   *         it is present, or <CODE>false</CODE> if the argument does not take
+   *         a value and the presence of the argument identifier itself is
+   *         sufficient to convey the necessary information.
+   */
+  public boolean needsValue()
+  {
+    return needsValue;
+  }
+
+
+
+  /**
+   * Specifies the default value that will be used for this argument if it is
+   * not specified on the command line and it is not set from a properties file.
+   *
+   * @param defaultValue
+   *          The default value that will be used for this argument if it is not
+   *          specified on the command line and it is not set from a properties
+   *          file.
+   */
+  public void setDefaultValue(final String defaultValue)
+  {
+    this.defaultValue = defaultValue;
+  }
+
+
+
+  /**
+   * Specifies whether this argument should be hidden from the usage
+   * information.
+   *
+   * @param isHidden
+   *          Indicates whether this argument should be hidden from the usage
+   *          information.
+   */
+  public void setHidden(final boolean isHidden)
+  {
+    this.isHidden = isHidden;
+  }
+
+
+
+  /**
+   * Specifies whether this argument may be provided more than once on the
+   * command line to specify multiple values.
+   *
+   * @param isMultiValued
+   *          Indicates whether this argument may be provided more than once on
+   *          the command line to specify multiple values.
+   */
+  public void setMultiValued(final boolean isMultiValued)
+  {
+    this.isMultiValued = isMultiValued;
+  }
+
+
+
+  /**
+   * Specifies whether a value must be provided with this argument if it is
+   * present. If this is changed from <CODE>false</CODE> to <CODE>true</CODE>,
+   * then a value placeholder must also be provided.
+   *
+   * @param needsValue
+   *          Indicates whether a value must be provided with this argument if
+   *          it is present.
+   */
+  public void setNeedsValue(final boolean needsValue)
+  {
+    this.needsValue = needsValue;
+  }
+
+
+
+  /**
+   * Specifies whether this argument is present in the parsed set of
+   * command-line arguments.
+   *
+   * @param isPresent
+   *          Indicates whether this argument is present in the set of
+   *          command-line arguments.
+   */
+  public void setPresent(final boolean isPresent)
+  {
+    this.isPresent = isPresent;
+  }
+
+
+
+  /**
+   * Specifies the name of a property in a properties file that may be used to
+   * set the default value for this argument if it is present.
+   *
+   * @param propertyName
+   *          The name of a property in a properties file that may be used to
+   *          set the default value for this argument if it is present.
+   */
+  public void setPropertyName(final String propertyName)
+  {
+    this.propertyName = propertyName;
+  }
+
+
+
+  /**
+   * Specifies whether this argument is required to have at least one value.
+   *
+   * @param isRequired
+   *          Indicates whether this argument is required to have at least one
+   *          value.
+   */
+  public void setRequired(final boolean isRequired)
+  {
+    this.isRequired = isRequired;
+  }
+
+
+
+  /**
+   * Specifies the value placeholder that will be displayed for this argument in
+   * the generated usage information. It may be <CODE>null</CODE> only if
+   * <CODE>needsValue()</CODE> returns <CODE>false</CODE>.
+   *
+   * @param valuePlaceholder
+   *          The value placeholder that will be displayed for this argument in
+   *          the generated usage information.
+   */
+  public void setValuePlaceholder(final LocalizableMessage valuePlaceholder)
+  {
+    this.valuePlaceholder = valuePlaceholder;
+  }
+
+
+
+  /**
+   * Specifies whether this argument was provided in the set of properties found
+   * is a properties file.
+   *
+   * @param isValueSetByProperty
+   *          Specify whether this argument was provided in the set of
+   *          properties found is a properties file.
+   */
+  public void setValueSetByProperty(final boolean isValueSetByProperty)
+  {
+    this.isValueSetByProperty = isValueSetByProperty;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in this
+   * argument.
+   *
+   * @param valueString
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          A buffer into which the invalid reason may be written if the value
+   *          is not acceptable.
+   * @return <CODE>true</CODE> if the value is acceptable, or <CODE>false</CODE>
+   *         if it is not.
+   */
+  public abstract boolean valueIsAcceptable(String valueString,
+      LocalizableMessageBuilder invalidReason);
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentException.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentException.java
new file mode 100644
index 0000000..4c9ba59
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentException.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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import org.opends.sdk.LocalizableException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class defines an exception that may be thrown if there is a problem with
+ * an argument definition.
+ */
+@SuppressWarnings("serial")
+final class ArgumentException extends Exception implements LocalizableException
+{
+  // The I18N message associated with this exception.
+  private final LocalizableMessage message;
+
+
+
+  /**
+   * Creates a new argument exception with the provided message.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   */
+  ArgumentException(final LocalizableMessage message)
+  {
+    super(String.valueOf(message));
+    this.message = message;
+  }
+
+
+
+  /**
+   * Creates a new argument exception with the provided message and root cause.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   * @param cause
+   *          The exception that was caught to trigger this exception.
+   */
+  ArgumentException(final LocalizableMessage message, final Throwable cause)
+  {
+    super(String.valueOf(message), cause);
+    this.message = message;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LocalizableMessage getMessageObject()
+  {
+    return this.message;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentGroup.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentGroup.java
new file mode 100644
index 0000000..a4466ec
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentGroup.java
@@ -0,0 +1,208 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * Class for organizing options into logical groups when arguement usage is
+ * printed. To use an argument group, create an instance and use
+ * {@link org.opends.server.util.args.ArgumentParser #addArgument(Argument, ArgumentGroup)}
+ * when adding arguments for to the parser.
+ */
+final class ArgumentGroup implements Comparable<ArgumentGroup>
+{
+
+  // Description for this group of arguments
+  private LocalizableMessage description = null;
+
+  // List of arguments belonging to this group
+  private List<Argument> args = null;
+
+  // Governs groups position within usage statement
+  private final Integer priority;
+
+
+
+  /**
+   * Creates a parameterized instance.
+   *
+   * @param description
+   *          for options in this group that is printed before argument
+   *          descriptions in usage output
+   * @param priority
+   *          number governing the position of this group within the usage
+   *          statement. Groups with higher priority values appear before groups
+   *          with lower priority.
+   */
+  ArgumentGroup(final LocalizableMessage description, final int priority)
+  {
+    this.description = description;
+    this.priority = priority;
+    this.args = new LinkedList<Argument>();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final ArgumentGroup o)
+  {
+    // Groups with higher priority numbers appear before
+    // those with lower priority in the usage output
+    return -1 * priority.compareTo(o.priority);
+  }
+
+
+
+  /**
+   * Adds an argument to this group.
+   *
+   * @param arg
+   *          to add
+   * @return boolean where true indicates the add was successful
+   */
+  boolean addArgument(final Argument arg)
+  {
+    boolean success = false;
+    if (arg != null)
+    {
+      final Character newShort = arg.getShortIdentifier();
+      final String newLong = arg.getLongIdentifier();
+
+      // See if there is already an argument in this group that the
+      // new argument should replace
+      for (final Iterator<Argument> it = this.args.iterator(); it.hasNext();)
+      {
+        final Argument a = it.next();
+        if (newShort != null && newShort.equals(a.getShortIdentifier())
+            || newLong != null && newLong.equals(a.getLongIdentifier()))
+        {
+          it.remove();
+          break;
+        }
+      }
+
+      success = this.args.add(arg);
+    }
+    return success;
+  }
+
+
+
+  /**
+   * Indicates whether this group contains any members.
+   *
+   * @return boolean where true means this group contains members
+   */
+  boolean containsArguments()
+  {
+    return this.args.size() > 0;
+  }
+
+
+
+  /**
+   * Indicates whether this group contains any non-hidden members.
+   *
+   * @return boolean where true means this group contains non-hidden members
+   */
+  boolean containsNonHiddenArguments()
+  {
+    for (final Argument arg : args)
+    {
+      if (!arg.isHidden())
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Gets the list of arguments associated with this group.
+   *
+   * @return list of associated arguments
+   */
+  List<Argument> getArguments()
+  {
+    return Collections.unmodifiableList(args);
+  }
+
+
+
+  /**
+   * Gets the description for this group of arguments.
+   *
+   * @return description for this argument group
+   */
+  LocalizableMessage getDescription()
+  {
+    return this.description;
+  }
+
+
+
+  /**
+   * Removes an argument from this group.
+   *
+   * @param arg
+   *          to remove
+   * @return boolean where true indicates the remove was successful
+   */
+  boolean removeArgument(final Argument arg)
+  {
+    return this.args.remove(arg);
+  }
+
+
+
+  /**
+   * Sets the description for this group of arguments.
+   *
+   * @param description
+   *          for this argument group
+   */
+  void setDescription(final LocalizableMessage description)
+  {
+    this.description = description;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentParser.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentParser.java
new file mode 100644
index 0000000..4dfc520
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ArgumentParser.java
@@ -0,0 +1,1919 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.PROPERTY_SCRIPT_NAME;
+import static com.sun.opends.sdk.tools.Utils.wrapText;
+import static com.sun.opends.sdk.util.StaticUtils.EOL;
+import static com.sun.opends.sdk.util.StaticUtils.getBytes;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.*;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines a utility that can be used to deal with command-line
+ * arguments for applications in a CLIP-compliant manner using either short
+ * one-character or longer word-based arguments. It is also integrated with the
+ * Directory Server message catalog so that it can display messages in an
+ * internationalizeable format, can automatically generate usage information,
+ * can detect conflicts between arguments, and can interact with a properties
+ * file to obtain default values for arguments there if they are not specified
+ * on the command-line.
+ */
+final class ArgumentParser
+{
+  /**
+   * The argument that will be used to indicate the file properties.
+   */
+  private StringArgument filePropertiesPathArgument;
+
+  /**
+   * The argument that will be used to indicate that we'll not look for default
+   * properties file.
+   */
+  private BooleanArgument noPropertiesFileArgument;
+
+  // The argument that will be used to trigger the display of usage
+  // information.
+  private Argument usageArgument;
+
+  // The argument that will be used to trigger the display of the OpenDS
+  // version.
+  private Argument versionArgument;
+
+  // The set of unnamed trailing arguments that were provided for this
+  // parser.
+  private final ArrayList<String> trailingArguments;
+
+  // Indicates whether this parser will allow additional unnamed
+  // arguments at the end of the list.
+  private final boolean allowsTrailingArguments;
+
+  // Indicates whether long arguments should be treated in a
+  // case-sensitive manner.
+  private final boolean longArgumentsCaseSensitive;
+
+  // Indicates whether the usage or version information has been
+  // displayed.
+  private boolean usageOrVersionDisplayed;
+
+  // Indicates whether the version argument was provided.
+  private boolean versionPresent;
+
+  // The set of arguments defined for this parser, referenced by short
+  // ID.
+  private final HashMap<Character, Argument> shortIDMap;
+
+  // The set of arguments defined for this parser, referenced by
+  // argument name.
+  private final HashMap<String, Argument> argumentMap;
+
+  // The set of arguments defined for this parser, referenced by long
+  // ID.
+  private final HashMap<String, Argument> longIDMap;
+
+  // The maximum number of unnamed trailing arguments that may be
+  // provided.
+  private final int maxTrailingArguments;
+
+  // The minimum number of unnamed trailing arguments that may be
+  // provided.
+  private final int minTrailingArguments;
+
+  // The total set of arguments defined for this parser.
+  private final LinkedList<Argument> argumentList;
+
+  // The output stream to which usage information should be printed.
+  private OutputStream usageOutputStream;
+
+  // The fully-qualified name of the Java class that should be invoked
+  // to launch the program with which this argument parser is associated.
+  private final String mainClassName;
+
+  // A human-readable description for the tool, which will be included
+  // when displaying usage information.
+  private final LocalizableMessage toolDescription;
+
+  // The display name that will be used for the trailing arguments in
+  // the usage information.
+  private final String trailingArgsDisplayName;
+
+  // The raw set of command-line arguments that were provided.
+  private String[] rawArguments;
+
+  /** Set of argument groups. */
+  private Set<ArgumentGroup> argumentGroups;
+
+  /**
+   * Group for arguments that have not been explicitly grouped. These will
+   * appear at the top of the usage statement without a header.
+   */
+  private final ArgumentGroup defaultArgGroup = new ArgumentGroup(
+      LocalizableMessage.EMPTY, Integer.MAX_VALUE);
+
+  /**
+   * Group for arguments that are related to connection through LDAP. This
+   * includes options like the bind DN, the port, etc.
+   */
+  private final ArgumentGroup ldapArgGroup = new ArgumentGroup(
+      INFO_DESCRIPTION_LDAP_CONNECTION_ARGS.get(), Integer.MIN_VALUE + 2);
+
+  /**
+   * Group for arguments that are related to utility input/output like
+   * properties file, no-prompt etc. These will appear toward the bottom of the
+   * usage statement.
+   */
+  private final ArgumentGroup ioArgGroup = new ArgumentGroup(
+      INFO_DESCRIPTION_IO_ARGS.get(), Integer.MIN_VALUE + 1);
+
+  /**
+   * Group for arguments that are general like help, version etc. These will
+   * appear at the end of the usage statement.
+   */
+  private final ArgumentGroup generalArgGroup = new ArgumentGroup(
+      INFO_DESCRIPTION_GENERAL_ARGS.get(), Integer.MIN_VALUE);
+
+  private final static String INDENT = "    ";
+
+  private final static int MAX_LENGTH = 80;
+
+
+
+  /**
+   * Creates a new instance of this argument parser with no arguments. Unnamed
+   * trailing arguments will not be allowed.
+   *
+   * @param mainClassName
+   *          The fully-qualified name of the Java class that should be invoked
+   *          to launch the program with which this argument parser is
+   *          associated.
+   * @param toolDescription
+   *          A human-readable description for the tool, which will be included
+   *          when displaying usage information.
+   * @param longArgumentsCaseSensitive
+   *          Indicates whether long arguments should be treated in a
+   *          case-sensitive manner.
+   */
+  ArgumentParser(final String mainClassName,
+      final LocalizableMessage toolDescription,
+      final boolean longArgumentsCaseSensitive)
+  {
+    this.mainClassName = mainClassName;
+    this.toolDescription = toolDescription;
+    this.longArgumentsCaseSensitive = longArgumentsCaseSensitive;
+
+    argumentList = new LinkedList<Argument>();
+    argumentMap = new HashMap<String, Argument>();
+    shortIDMap = new HashMap<Character, Argument>();
+    longIDMap = new HashMap<String, Argument>();
+    allowsTrailingArguments = false;
+    usageOrVersionDisplayed = false;
+    versionPresent = false;
+    trailingArgsDisplayName = null;
+    maxTrailingArguments = 0;
+    minTrailingArguments = 0;
+    trailingArguments = new ArrayList<String>();
+    rawArguments = null;
+    usageArgument = null;
+    filePropertiesPathArgument = null;
+    noPropertiesFileArgument = null;
+    usageOutputStream = System.out;
+    initGroups();
+  }
+
+
+
+  /**
+   * Creates a new instance of this argument parser with no arguments that may
+   * or may not be allowed to have unnamed trailing arguments.
+   *
+   * @param mainClassName
+   *          The fully-qualified name of the Java class that should be invoked
+   *          to launch the program with which this argument parser is
+   *          associated.
+   * @param toolDescription
+   *          A human-readable description for the tool, which will be included
+   *          when displaying usage information.
+   * @param longArgumentsCaseSensitive
+   *          Indicates whether long arguments should be treated in a
+   *          case-sensitive manner.
+   * @param allowsTrailingArguments
+   *          Indicates whether this parser allows unnamed trailing arguments to
+   *          be provided.
+   * @param minTrailingArguments
+   *          The minimum number of unnamed trailing arguments that must be
+   *          provided. A value less than or equal to zero indicates that no
+   *          minimum will be enforced.
+   * @param maxTrailingArguments
+   *          The maximum number of unnamed trailing arguments that may be
+   *          provided. A value less than or equal to zero indicates that no
+   *          maximum will be enforced.
+   * @param trailingArgsDisplayName
+   *          The display name that should be used as a placeholder for unnamed
+   *          trailing arguments in the generated usage information.
+   */
+  ArgumentParser(final String mainClassName,
+      final LocalizableMessage toolDescription,
+      final boolean longArgumentsCaseSensitive,
+      final boolean allowsTrailingArguments, final int minTrailingArguments,
+      final int maxTrailingArguments, final String trailingArgsDisplayName)
+  {
+    this.mainClassName = mainClassName;
+    this.toolDescription = toolDescription;
+    this.longArgumentsCaseSensitive = longArgumentsCaseSensitive;
+    this.allowsTrailingArguments = allowsTrailingArguments;
+    this.minTrailingArguments = minTrailingArguments;
+    this.maxTrailingArguments = maxTrailingArguments;
+    this.trailingArgsDisplayName = trailingArgsDisplayName;
+
+    argumentList = new LinkedList<Argument>();
+    argumentMap = new HashMap<String, Argument>();
+    shortIDMap = new HashMap<Character, Argument>();
+    longIDMap = new HashMap<String, Argument>();
+    trailingArguments = new ArrayList<String>();
+    usageOrVersionDisplayed = false;
+    versionPresent = false;
+    rawArguments = null;
+    usageArgument = null;
+    usageOutputStream = System.out;
+    initGroups();
+  }
+
+
+
+  /**
+   * Adds the provided argument to the set of arguments handled by this parser.
+   *
+   * @param argument
+   *          The argument to be added.
+   * @throws ArgumentException
+   *           If the provided argument conflicts with another argument that has
+   *           already been defined.
+   */
+  void addArgument(final Argument argument) throws ArgumentException
+  {
+    addArgument(argument, null);
+  }
+
+
+
+  /**
+   * Adds the provided argument to the set of arguments handled by this parser.
+   *
+   * @param argument
+   *          The argument to be added.
+   * @param group
+   *          The argument group to which the argument belongs.
+   * @throws ArgumentException
+   *           If the provided argument conflicts with another argument that has
+   *           already been defined.
+   */
+  void addArgument(final Argument argument, ArgumentGroup group)
+      throws ArgumentException
+  {
+
+    final Character shortID = argument.getShortIdentifier();
+    if ((shortID != null) && shortIDMap.containsKey(shortID))
+    {
+      final String conflictingName = shortIDMap.get(shortID).getName();
+
+      final LocalizableMessage message = ERR_ARGPARSER_DUPLICATE_SHORT_ID.get(
+          argument.getName(), String.valueOf(shortID), conflictingName);
+      throw new ArgumentException(message);
+    }
+
+    if (versionArgument != null)
+    {
+      if (shortID != null &&
+          shortID.equals(versionArgument.getShortIdentifier()))
+      {
+        // Update the version argument to not display its short
+        // identifier.
+        try
+        {
+          versionArgument = new BooleanArgument(OPTION_LONG_PRODUCT_VERSION,
+              null, OPTION_LONG_PRODUCT_VERSION,
+              INFO_DESCRIPTION_PRODUCT_VERSION.get());
+          this.generalArgGroup.addArgument(versionArgument);
+        }
+        catch (final ArgumentException e)
+        {
+          // ignore
+        }
+      }
+    }
+
+    String longID = argument.getLongIdentifier();
+    if (longID != null)
+    {
+      if (!longArgumentsCaseSensitive)
+      {
+        longID = toLowerCase(longID);
+      }
+      if (longIDMap.containsKey(longID))
+      {
+        final String conflictingName = longIDMap.get(longID).getName();
+
+        final LocalizableMessage message = ERR_ARGPARSER_DUPLICATE_LONG_ID.get(
+            argument.getName(), argument.getLongIdentifier(), conflictingName);
+        throw new ArgumentException(message);
+      }
+    }
+
+    if (shortID != null)
+    {
+      shortIDMap.put(shortID, argument);
+    }
+
+    if (longID != null)
+    {
+      longIDMap.put(longID, argument);
+    }
+
+    argumentList.add(argument);
+
+    if (group == null)
+    {
+      group = getStandardGroup(argument);
+    }
+    group.addArgument(argument);
+    argumentGroups.add(group);
+  }
+
+
+
+  /**
+   * Adds the provided argument to the set of arguments handled by this parser
+   * and puts the arguement in the default group.
+   *
+   * @param argument
+   *          The argument to be added.
+   * @throws ArgumentException
+   *           If the provided argument conflicts with another argument that has
+   *           already been defined.
+   */
+  void addDefaultArgument(final Argument argument) throws ArgumentException
+  {
+    addArgument(argument, defaultArgGroup);
+  }
+
+
+
+  /**
+   * Adds the provided argument to the set of arguments handled by this parser
+   * and puts the arguement in the general group.
+   *
+   * @param argument
+   *          The argument to be added.
+   * @throws ArgumentException
+   *           If the provided argument conflicts with another argument that has
+   *           already been defined.
+   */
+  void addGeneralArgument(final Argument argument) throws ArgumentException
+  {
+    addArgument(argument, generalArgGroup);
+  }
+
+
+
+  /**
+   * Adds the provided argument to the set of arguments handled by this parser
+   * and puts the argument in the input/output group.
+   *
+   * @param argument
+   *          The argument to be added.
+   * @throws ArgumentException
+   *           If the provided argument conflicts with another argument that has
+   *           already been defined.
+   */
+  void addInputOutputArgument(final Argument argument) throws ArgumentException
+  {
+    addArgument(argument, ioArgGroup);
+  }
+
+
+
+  /**
+   * Adds the provided argument to the set of arguments handled by this parser
+   * and puts the argument in the LDAP connection group.
+   *
+   * @param argument
+   *          The argument to be added.
+   * @throws ArgumentException
+   *           If the provided argument conflicts with another argument that has
+   *           already been defined.
+   */
+  void addLdapConnectionArgument(final Argument argument)
+      throws ArgumentException
+  {
+    addArgument(argument, ldapArgGroup);
+  }
+
+
+
+  /**
+   * Indicates whether this parser will allow unnamed trailing arguments. These
+   * will be arguments at the end of the list that are not preceded by either a
+   * long or short identifier and will need to be manually parsed by the
+   * application using this parser. Note that once an unnamed trailing argument
+   * has been identified, all remaining arguments will be classified as such.
+   *
+   * @return <CODE>true</CODE> if this parser allows unnamed trailing arguments,
+   *         or <CODE>false</CODE> if it does not.
+   */
+  boolean allowsTrailingArguments()
+  {
+    return allowsTrailingArguments;
+  }
+
+
+
+  /**
+   * Check if we have a properties file.
+   *
+   * @return The properties found in the properties file or null.
+   * @throws ArgumentException
+   *           If a problem was encountered while parsing the provided
+   *           arguments.
+   */
+  Properties checkExternalProperties() throws ArgumentException
+  {
+    // We don't look for properties file.
+    if ((noPropertiesFileArgument != null)
+        && (noPropertiesFileArgument.isPresent()))
+    {
+      return null;
+    }
+
+    // Check if we have a properties file argument
+    if (filePropertiesPathArgument == null)
+    {
+      return null;
+    }
+
+    // check if the properties file argument has been set. If not
+    // look for default location.
+    String propertiesFilePath = null;
+    if (filePropertiesPathArgument.isPresent())
+    {
+      propertiesFilePath = filePropertiesPathArgument.getValue();
+    }
+    else
+    {
+      // Check in "user home"/.opends directory
+      final String userDir = System.getProperty("user.home");
+      propertiesFilePath = findPropertiesFile(userDir + File.separator
+          + DEFAULT_OPENDS_CONFIG_DIR);
+
+      // TODO
+      /*
+       * if (propertiesFilePath == null) { // check "Opends instance"/config
+       * directory String instanceDir = DirectoryServer.getInstanceRoot();
+       * propertiesFilePath = findPropertiesFile(instanceDir+ File.separator +
+       * "config"); }
+       */
+    }
+
+    // We don't have a properties file location
+    if (propertiesFilePath == null)
+    {
+      return null;
+    }
+
+    // We have a location for the properties file.
+    final Properties argumentProperties = new Properties();
+    final String scriptName = System.getProperty(Utils.PROPERTY_SCRIPT_NAME);
+    try
+    {
+      final Properties p = new Properties();
+      final FileInputStream fis = new FileInputStream(propertiesFilePath);
+      p.load(fis);
+      fis.close();
+
+      for (final Enumeration<?> e = p.propertyNames(); e.hasMoreElements();)
+      {
+        final String currentPropertyName = (String) e.nextElement();
+        String propertyName = currentPropertyName;
+
+        // Property name form <script name>.<property name> has the
+        // precedence to <property name>
+        if (scriptName != null)
+        {
+          if (currentPropertyName.startsWith(scriptName))
+          {
+            propertyName = currentPropertyName
+                .substring(scriptName.length() + 1);
+          }
+          else
+          {
+            if (p.containsKey(scriptName + "." + currentPropertyName))
+            {
+              continue;
+            }
+          }
+        }
+        argumentProperties.setProperty(propertyName.toLowerCase(), p
+            .getProperty(currentPropertyName));
+      }
+    }
+    catch (final Exception e)
+    {
+      final LocalizableMessage message = ERR_ARGPARSER_CANNOT_READ_PROPERTIES_FILE
+          .get(String.valueOf(propertiesFilePath), getExceptionMessage(e));
+      throw new ArgumentException(message, e);
+    }
+    return argumentProperties;
+  }
+
+
+
+  /**
+   * Retrieves the argument with the specified name.
+   *
+   * @param name
+   *          The name of the argument to retrieve.
+   * @return The argument with the specified name, or <CODE>null</CODE> if there
+   *         is no such argument.
+   */
+  Argument getArgument(final String name)
+  {
+    return argumentMap.get(name);
+  }
+
+
+
+  /**
+   * Retrieves the argument with the specified long identifier.
+   *
+   * @param longID
+   *          The long identifier of the argument to retrieve.
+   * @return The argument with the specified long identifier, or
+   *         <CODE>null</CODE> if there is no such argument.
+   */
+  Argument getArgumentForLongID(final String longID)
+  {
+    return longIDMap.get(longID);
+  }
+
+
+
+  /**
+   * Retrieves the argument with the specified short identifier.
+   *
+   * @param shortID
+   *          The short ID for the argument to retrieve.
+   * @return The argument with the specified short identifier, or
+   *         <CODE>null</CODE> if there is no such argument.
+   */
+  Argument getArgumentForShortID(final Character shortID)
+  {
+    return shortIDMap.get(shortID);
+  }
+
+
+
+  /**
+   * Retrieves the list of all arguments that have been defined for this
+   * argument parser.
+   *
+   * @return The list of all arguments that have been defined for this argument
+   *         parser.
+   */
+  LinkedList<Argument> getArgumentList()
+  {
+    return argumentList;
+  }
+
+
+
+  /**
+   * Retrieves the set of arguments mapped by the long identifier that may be
+   * used to reference them. Note that arguments that do not have a long
+   * identifier will not be present in this list.
+   *
+   * @return The set of arguments mapped by the long identifier that may be used
+   *         to reference them.
+   */
+  HashMap<String, Argument> getArgumentsByLongID()
+  {
+    return longIDMap;
+  }
+
+
+
+  /**
+   * Retrieves the set of arguments mapped by the short identifier that may be
+   * used to reference them. Note that arguments that do not have a short
+   * identifier will not be present in this list.
+   *
+   * @return The set of arguments mapped by the short identifier that may be
+   *         used to reference them.
+   */
+  HashMap<Character, Argument> getArgumentsByShortID()
+  {
+    return shortIDMap;
+  }
+
+
+
+  /**
+   * Retrieves the fully-qualified name of the Java class that should be invoked
+   * to launch the program with which this argument parser is associated.
+   *
+   * @return The fully-qualified name of the Java class that should be invoked
+   *         to launch the program with which this argument parser is
+   *         associated.
+   */
+  String getMainClassName()
+  {
+    return mainClassName;
+  }
+
+
+
+  /**
+   * Retrieves the maximum number of unnamed trailing arguments that may be
+   * provided.
+   *
+   * @return The maximum number of unnamed trailing arguments that may be
+   *         provided, or a value less than or equal to zero if no maximum will
+   *         be enforced.
+   */
+  int getMaxTrailingArguments()
+  {
+    return maxTrailingArguments;
+  }
+
+
+
+  /**
+   * Retrieves the minimum number of unnamed trailing arguments that must be
+   * provided.
+   *
+   * @return The minimum number of unnamed trailing arguments that must be
+   *         provided, or a value less than or equal to zero if no minimum will
+   *         be enforced.
+   */
+  int getMinTrailingArguments()
+  {
+    return minTrailingArguments;
+  }
+
+
+
+  /**
+   * Retrieves the raw set of arguments that were provided.
+   *
+   * @return The raw set of arguments that were provided, or <CODE>null</CODE>
+   *         if the argument list has not yet been parsed.
+   */
+  String[] getRawArguments()
+  {
+    return rawArguments;
+  }
+
+
+
+  /**
+   * Given an argument, returns an appropriate group. Arguments may be part of
+   * one of the special groups or the default group.
+   *
+   * @param argument
+   *          for which a group is requested
+   * @return argument group appropriate for <code>argument</code>
+   */
+  ArgumentGroup getStandardGroup(final Argument argument)
+  {
+    ArgumentGroup group;
+    if (isInputOutputArgument(argument))
+    {
+      group = ioArgGroup;
+    }
+    else if (isGeneralArgument(argument))
+    {
+      group = generalArgGroup;
+    }
+    else if (isLdapConnectionArgument(argument))
+    {
+      group = ldapArgGroup;
+    }
+    else
+    {
+      group = defaultArgGroup;
+    }
+    return group;
+  }
+
+
+
+  /**
+   * Retrieves a human-readable description for this tool, which should be
+   * included at the top of the command-line usage information.
+   *
+   * @return A human-readable description for this tool, or {@code null} if none
+   *         is available.
+   */
+  LocalizableMessage getToolDescription()
+  {
+    return toolDescription;
+  }
+
+
+
+  /**
+   * Retrieves the set of unnamed trailing arguments that were provided on the
+   * command line.
+   *
+   * @return The set of unnamed trailing arguments that were provided on the
+   *         command line.
+   */
+  ArrayList<String> getTrailingArguments()
+  {
+    return trailingArguments;
+  }
+
+
+
+  /**
+   * Retrieves a string containing usage information based on the defined
+   * arguments.
+   *
+   * @return A string containing usage information based on the defined
+   *         arguments.
+   */
+  String getUsage()
+  {
+    final StringBuilder buffer = new StringBuilder();
+    getUsage(buffer);
+
+    return buffer.toString();
+  }
+
+
+
+  /**
+   * Writes usage information based on the defined arguments to the provided
+   * output stream.
+   *
+   * @param outputStream
+   *          The output stream to which the usage information should be
+   *          written.
+   * @throws IOException
+   *           If a problem occurs while attempting to write the usage
+   *           information to the provided output stream.
+   */
+  void getUsage(final OutputStream outputStream) throws IOException
+  {
+    final StringBuilder buffer = new StringBuilder();
+    getUsage(buffer);
+
+    outputStream.write(getBytes(buffer.toString()));
+  }
+
+
+
+  /**
+   * Appends usage information based on the defined arguments to the provided
+   * buffer.
+   *
+   * @param buffer
+   *          The buffer to which the usage information should be appended.
+   */
+  void getUsage(final StringBuilder buffer)
+  {
+    usageOrVersionDisplayed = true;
+    if ((toolDescription != null) && (toolDescription.length() > 0))
+    {
+      buffer.append(wrapText(toolDescription.toString(), MAX_LENGTH - 1));
+      buffer.append(EOL);
+      buffer.append(EOL);
+    }
+
+    final String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
+    if ((scriptName == null) || (scriptName.length() == 0))
+    {
+      buffer.append(INFO_ARGPARSER_USAGE_JAVA_CLASSNAME.get(mainClassName));
+    }
+    else
+    {
+      buffer.append(INFO_ARGPARSER_USAGE_JAVA_SCRIPTNAME.get(scriptName));
+    }
+
+    if (allowsTrailingArguments)
+    {
+      if (trailingArgsDisplayName == null)
+      {
+        buffer.append(" " + INFO_ARGPARSER_USAGE_TRAILINGARGS.get());
+      }
+      else
+      {
+        buffer.append(" ");
+        buffer.append(trailingArgsDisplayName);
+      }
+    }
+    buffer.append(EOL);
+    buffer.append(EOL);
+    buffer.append(INFO_SUBCMDPARSER_WHERE_OPTIONS_INCLUDE.get());
+    buffer.append(EOL);
+    buffer.append(EOL);
+
+    Argument helpArgument = null;
+
+    final boolean printHeaders = printUsageGroupHeaders();
+    for (final ArgumentGroup argGroup : argumentGroups)
+    {
+      if (argGroup.containsArguments() && printHeaders)
+      {
+        // Print the groups description if any
+        final LocalizableMessage groupDesc = argGroup.getDescription();
+        if (groupDesc != null && !LocalizableMessage.EMPTY.equals(groupDesc))
+        {
+          buffer.append(EOL);
+          buffer.append(wrapText(groupDesc.toString(), MAX_LENGTH - 1));
+          buffer.append(EOL);
+          buffer.append(EOL);
+        }
+      }
+
+      final SortedSet<Argument> args = new TreeSet<Argument>(
+          new Comparator<Argument>()
+          {
+
+            /**
+             * {@inheritDoc}
+             */
+            public int compare(final Argument o1, final Argument o2)
+            {
+              final String s1;
+              final String s2;
+
+              if (o1.getShortIdentifier() != null)
+              {
+                s1 = o1.getShortIdentifier().toString();
+              }
+              else
+              {
+                s1 = o1.getLongIdentifier();
+              }
+
+              if (o2.getShortIdentifier() != null)
+              {
+                s2 = o2.getShortIdentifier().toString();
+              }
+              else
+              {
+                s2 = o2.getLongIdentifier();
+              }
+
+              final int res = s1.compareToIgnoreCase(s2);
+              if (res != 0)
+              {
+                return res;
+              }
+              else
+              {
+                // Lowercase options first then uppercase.
+                return -s1.compareTo(s2);
+              }
+            }
+
+          });
+      args.addAll(argGroup.getArguments());
+
+      for (final Argument a : args)
+      {
+        // If this argument is hidden, then skip it.
+        if (a.isHidden())
+        {
+          continue;
+        }
+
+        // Help argument should be printed at the end
+        if ((usageArgument != null)
+            && usageArgument.getName().equals(a.getName()))
+        {
+          helpArgument = a;
+          continue;
+        }
+        printArgumentUsage(a, buffer);
+      }
+    }
+    if (helpArgument != null)
+    {
+      printArgumentUsage(helpArgument, buffer);
+    }
+    else
+    {
+      buffer.append(EOL);
+      buffer.append("-?");
+      buffer.append(EOL);
+    }
+  }
+
+
+
+  /**
+   * Retrieves a message containing usage information based on the defined
+   * arguments.
+   *
+   * @return A string containing usage information based on the defined
+   *         arguments.
+   */
+  LocalizableMessage getUsageMessage()
+  {
+    final StringBuilder buffer = new StringBuilder();
+    getUsage(buffer);
+
+    // TODO: rework getUsage(OutputStream) to work with messages
+    // framework
+    return LocalizableMessage.raw(buffer.toString());
+  }
+
+
+
+  /**
+   * Returns whether the usage argument was provided or not. This method should
+   * be called after a call to parseArguments.
+   *
+   * @return <CODE>true</CODE> if the usage argument was provided and
+   *         <CODE>false</CODE> otherwise.
+   */
+  boolean isUsageArgumentPresent()
+  {
+    boolean isUsageArgumentPresent = false;
+    if (usageArgument != null)
+    {
+      isUsageArgumentPresent = usageArgument.isPresent();
+    }
+    return isUsageArgumentPresent;
+  }
+
+
+
+  /**
+   * Returns whether the version argument was provided or not. This method
+   * should be called after a call to parseArguments.
+   *
+   * @return <CODE>true</CODE> if the version argument was provided and
+   *         <CODE>false</CODE> otherwise.
+   */
+  boolean isVersionArgumentPresent()
+  {
+    return versionPresent;
+  }
+
+
+
+  /**
+   * Parses the provided set of arguments and updates the information associated
+   * with this parser accordingly.
+   *
+   * @param rawArguments
+   *          The raw set of arguments to parse.
+   * @throws ArgumentException
+   *           If a problem was encountered while parsing the provided
+   *           arguments.
+   */
+  void parseArguments(final String[] rawArguments) throws ArgumentException
+  {
+    parseArguments(rawArguments, null);
+  }
+
+
+
+  /**
+   * Parses the provided set of arguments and updates the information associated
+   * with this parser accordingly. Default values for unspecified arguments may
+   * be read from the specified properties if any are provided.
+   *
+   * @param rawArguments
+   *          The set of raw arguments to parse.
+   * @param argumentProperties
+   *          A set of properties that may be used to provide default values for
+   *          arguments not included in the given raw arguments.
+   * @throws ArgumentException
+   *           If a problem was encountered while parsing the provided
+   *           arguments.
+   */
+  void parseArguments(final String[] rawArguments, Properties argumentProperties)
+      throws ArgumentException
+  {
+    this.rawArguments = rawArguments;
+
+    boolean inTrailingArgs = false;
+
+    final int numArguments = rawArguments.length;
+    for (int i = 0; i < numArguments; i++)
+    {
+      final String arg = rawArguments[i];
+
+      if (inTrailingArgs)
+      {
+        trailingArguments.add(arg);
+        if ((maxTrailingArguments > 0)
+            && (trailingArguments.size() > maxTrailingArguments))
+        {
+          final LocalizableMessage message = ERR_ARGPARSER_TOO_MANY_TRAILING_ARGS
+              .get(maxTrailingArguments);
+          throw new ArgumentException(message);
+        }
+
+        continue;
+      }
+
+      if (arg.equals("--"))
+      {
+        // This is a special indicator that we have reached the end of
+        // the named arguments and that everything that follows after this
+        // should be considered trailing arguments.
+        inTrailingArgs = true;
+      }
+      else if (arg.startsWith("--"))
+      {
+        // This indicates that we are using the long name to reference
+        // the argument. It may be in any of the following forms:
+        // --name
+        // --name value
+        // --name=value
+
+        String argName = arg.substring(2);
+        String argValue = null;
+        final int equalPos = argName.indexOf('=');
+        if (equalPos < 0)
+        {
+          // This is fine. The value is not part of the argument name
+          // token.
+        }
+        else if (equalPos == 0)
+        {
+          // The argument starts with "--=", which is not acceptable.
+          final LocalizableMessage message = ERR_ARGPARSER_LONG_ARG_WITHOUT_NAME
+              .get(arg);
+          throw new ArgumentException(message);
+        }
+        else
+        {
+          // The argument is in the form --name=value, so parse them
+          // both out.
+          argValue = argName.substring(equalPos + 1);
+          argName = argName.substring(0, equalPos);
+        }
+
+        // If we're not case-sensitive, then convert the name to
+        // lowercase.
+        final String origArgName = argName;
+        if (!longArgumentsCaseSensitive)
+        {
+          argName = toLowerCase(argName);
+        }
+
+        // Get the argument with the specified name.
+        final Argument a = longIDMap.get(argName);
+        if (a == null)
+        {
+          if (argName.equals(OPTION_LONG_HELP))
+          {
+            // "--help" will always be interpreted as requesting usage
+            // information.
+            try
+            {
+              getUsage(usageOutputStream);
+            }
+            catch (final Exception e)
+            {
+            }
+
+            return;
+          }
+          else if (argName.equals(OPTION_LONG_PRODUCT_VERSION))
+          {
+            // "--version" will always be interpreted as requesting
+            // version information.
+            usageOrVersionDisplayed = true;
+            versionPresent = true;
+            try
+            {
+              // TODO
+              // DirectoryServer.printVersion(usageOutputStream);
+            }
+            catch (final Exception e)
+            {
+            }
+
+            return;
+          }
+          else
+          {
+            // There is no such argument registered.
+            final LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_LONG_ID
+                .get(origArgName);
+            throw new ArgumentException(message);
+          }
+        }
+        else
+        {
+          a.setPresent(true);
+
+          // If this is the usage argument, then immediately stop and
+          // print usage information.
+          if ((usageArgument != null)
+              && usageArgument.getName().equals(a.getName()))
+          {
+            try
+            {
+              getUsage(usageOutputStream);
+            }
+            catch (final Exception e)
+            {
+            }
+
+            return;
+          }
+        }
+
+        // See if the argument takes a value. If so, then make sure one
+        // was provided. If not, then make sure none was provided.
+        if (a.needsValue())
+        {
+          if (argValue == null)
+          {
+            if ((i + 1) == numArguments)
+            {
+              final LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_LONG_ID
+                  .get(origArgName);
+              throw new ArgumentException(message);
+            }
+
+            argValue = rawArguments[++i];
+          }
+
+          final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
+          if (!a.valueIsAcceptable(argValue, invalidReason))
+          {
+            final LocalizableMessage message = ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_LONG_ID
+                .get(argValue, origArgName, invalidReason.toString());
+            throw new ArgumentException(message);
+          }
+
+          // If the argument already has a value, then make sure it is
+          // acceptable to have more than one.
+          if (a.hasValue() && (!a.isMultiValued()))
+          {
+            final LocalizableMessage message = ERR_ARGPARSER_NOT_MULTIVALUED_FOR_LONG_ID
+                .get(origArgName);
+            throw new ArgumentException(message);
+          }
+
+          a.addValue(argValue);
+        }
+        else
+        {
+          if (argValue != null)
+          {
+            final LocalizableMessage message = ERR_ARGPARSER_ARG_FOR_LONG_ID_DOESNT_TAKE_VALUE
+                .get(origArgName);
+            throw new ArgumentException(message);
+          }
+        }
+      }
+      else if (arg.startsWith("-"))
+      {
+        // This indicates that we are using the 1-character name to
+        // reference the argument. It may be in any of the following forms:
+        // -n
+        // -nvalue
+        // -n value
+        if (arg.equals("-"))
+        {
+          final LocalizableMessage message = ERR_ARGPARSER_INVALID_DASH_AS_ARGUMENT
+              .get();
+          throw new ArgumentException(message);
+        }
+
+        final char argCharacter = arg.charAt(1);
+        String argValue;
+        if (arg.length() > 2)
+        {
+          argValue = arg.substring(2);
+        }
+        else
+        {
+          argValue = null;
+        }
+
+        // Get the argument with the specified short ID.
+        final Argument a = shortIDMap.get(argCharacter);
+        if (a == null)
+        {
+          if (argCharacter == '?')
+          {
+            // "-?" will always be interpreted as requesting usage
+            // information.
+            try
+            {
+              getUsage(usageOutputStream);
+            }
+            catch (final Exception e)
+            {
+            }
+
+            return;
+          }
+          else if ((argCharacter == OPTION_SHORT_PRODUCT_VERSION)
+              && (!shortIDMap.containsKey(OPTION_SHORT_PRODUCT_VERSION)))
+          {
+            // "-V" will always be interpreted as requesting
+            // version information except if it's already defined (e.g
+            // in ldap tools).
+            usageOrVersionDisplayed = true;
+            versionPresent = true;
+            try
+            {
+              // TODO
+              // DirectoryServer.printVersion(usageOutputStream);
+            }
+            catch (final Exception e)
+            {
+            }
+            return;
+          }
+          else
+          {
+            // There is no such argument registered.
+            final LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_SHORT_ID
+                .get(String.valueOf(argCharacter));
+            throw new ArgumentException(message);
+          }
+        }
+        else
+        {
+          a.setPresent(true);
+
+          // If this is the usage argument, then immediately stop and
+          // print usage information.
+          if ((usageArgument != null)
+              && usageArgument.getName().equals(a.getName()))
+          {
+            try
+            {
+              getUsage(usageOutputStream);
+            }
+            catch (final Exception e)
+            {
+            }
+
+            return;
+          }
+        }
+
+        // See if the argument takes a value. If so, then make sure one
+        // was provided. If not, then make sure none was provided.
+        if (a.needsValue())
+        {
+          if (argValue == null)
+          {
+            if ((i + 1) == numArguments)
+            {
+              final LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_SHORT_ID
+                  .get(String.valueOf(argCharacter));
+              throw new ArgumentException(message);
+            }
+
+            argValue = rawArguments[++i];
+          }
+
+          final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
+          if (!a.valueIsAcceptable(argValue, invalidReason))
+          {
+            final LocalizableMessage message = ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_SHORT_ID
+                .get(argValue, String.valueOf(argCharacter), invalidReason
+                    .toString());
+            throw new ArgumentException(message);
+          }
+
+          // If the argument already has a value, then make sure it is
+          // acceptable to have more than one.
+          if (a.hasValue() && (!a.isMultiValued()))
+          {
+            final LocalizableMessage message = ERR_ARGPARSER_NOT_MULTIVALUED_FOR_SHORT_ID
+                .get(String.valueOf(argCharacter));
+            throw new ArgumentException(message);
+          }
+
+          a.addValue(argValue);
+        }
+        else
+        {
+          if (argValue != null)
+          {
+            // If we've gotten here, then it means that we're in a scenario like
+            // "-abc" where "a" is a valid argument that doesn't take a
+            // value. However, this could still be valid if all remaining
+            // characters in the value are also valid argument characters that
+            // don't take values.
+            final int valueLength = argValue.length();
+            for (int j = 0; j < valueLength; j++)
+            {
+              final char c = argValue.charAt(j);
+              final Argument b = shortIDMap.get(c);
+              if (b == null)
+              {
+                // There is no such argument registered.
+                final LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_SHORT_ID
+                    .get(String.valueOf(argCharacter));
+                throw new ArgumentException(message);
+              }
+              else if (b.needsValue())
+              {
+                // This means we're in a scenario like "-abc" where b is
+                // a valid argument that takes a value. We don't support
+                // that.
+                final LocalizableMessage message = ERR_ARGPARSER_CANT_MIX_ARGS_WITH_VALUES
+                    .get(String.valueOf(argCharacter), argValue, String
+                        .valueOf(c));
+                throw new ArgumentException(message);
+              }
+              else
+              {
+                b.setPresent(true);
+
+                // If this is the usage argument, then immediately stop
+                // and print usage information.
+                if ((usageArgument != null)
+                    && usageArgument.getName().equals(b.getName()))
+                {
+                  try
+                  {
+                    getUsage(usageOutputStream);
+                  }
+                  catch (final Exception e)
+                  {
+                  }
+
+                  return;
+                }
+              }
+            }
+          }
+        }
+      }
+      else if (allowsTrailingArguments)
+      {
+        // It doesn't start with a dash, so it must be a trailing
+        // argument if that is acceptable.
+        inTrailingArgs = true;
+        trailingArguments.add(arg);
+      }
+      else
+      {
+        // It doesn't start with a dash and we don't allow trailing
+        // arguments, so this is illegal.
+        final LocalizableMessage message = ERR_ARGPARSER_DISALLOWED_TRAILING_ARGUMENT
+            .get(arg);
+        throw new ArgumentException(message);
+      }
+    }
+
+    // If we allow trailing arguments and there is a minimum number,
+    // then make sure at least that many were provided.
+    if (allowsTrailingArguments && (minTrailingArguments > 0))
+    {
+      if (trailingArguments.size() < minTrailingArguments)
+      {
+        final LocalizableMessage message = ERR_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS
+            .get(minTrailingArguments);
+        throw new ArgumentException(message);
+      }
+    }
+
+    // If we don't have the argumentProperties, try to load a properties
+    // file.
+    if (argumentProperties == null)
+    {
+      argumentProperties = checkExternalProperties();
+    }
+
+    // Iterate through all of the arguments. For any that were not
+    // provided on the command line, see if there is an alternate default that
+    // can be used. For cases where there is not, see that argument is required.
+    for (final Argument a : argumentList)
+    {
+      if (!a.isPresent())
+      {
+        // See if there is a value in the properties that can be used
+        if ((argumentProperties != null) && (a.getPropertyName() != null))
+        {
+          final String value = argumentProperties.getProperty(a
+              .getPropertyName().toLowerCase());
+          final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
+          if (value != null)
+          {
+            Boolean addValue = true;
+            if (!(a instanceof BooleanArgument))
+            {
+              addValue = a.valueIsAcceptable(value, invalidReason);
+            }
+            if (addValue)
+            {
+              a.addValue(value);
+              if (a.needsValue())
+              {
+                a.setPresent(true);
+              }
+              a.setValueSetByProperty(true);
+            }
+          }
+        }
+      }
+
+      if ((!a.isPresent()) && a.needsValue())
+      {
+        // See if the argument defines a default.
+        if (a.getDefaultValue() != null)
+        {
+          a.addValue(a.getDefaultValue());
+        }
+
+        // If there is still no value and the argument is required, then
+        // that's a problem.
+        if ((!a.hasValue()) && a.isRequired())
+        {
+          final LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_REQUIRED_ARG
+              .get(a.getName());
+          throw new ArgumentException(message);
+        }
+      }
+    }
+  }
+
+
+
+  /**
+   * Parses the provided set of arguments and updates the information associated
+   * with this parser accordingly. Default values for unspecified arguments may
+   * be read from the specified properties file.
+   *
+   * @param rawArguments
+   *          The set of raw arguments to parse.
+   * @param propertiesFile
+   *          The path to the properties file to use to obtain default values
+   *          for unspecified properties.
+   * @param requirePropertiesFile
+   *          Indicates whether the parsing should fail if the provided
+   *          properties file does not exist or is not accessible.
+   * @throws ArgumentException
+   *           If a problem was encountered while parsing the provided arguments
+   *           or interacting with the properties file.
+   */
+  void parseArguments(final String[] rawArguments, final String propertiesFile,
+      final boolean requirePropertiesFile) throws ArgumentException
+  {
+    this.rawArguments = rawArguments;
+
+    Properties argumentProperties = null;
+
+    try
+    {
+      final Properties p = new Properties();
+      final FileInputStream fis = new FileInputStream(propertiesFile);
+      p.load(fis);
+      fis.close();
+      argumentProperties = p;
+    }
+    catch (final Exception e)
+    {
+      if (requirePropertiesFile)
+      {
+        final LocalizableMessage message = ERR_ARGPARSER_CANNOT_READ_PROPERTIES_FILE
+            .get(String.valueOf(propertiesFile), getExceptionMessage(e));
+        throw new ArgumentException(message, e);
+      }
+    }
+
+    parseArguments(rawArguments, argumentProperties);
+  }
+
+
+
+  /**
+   * Indicates whether or not argument group description headers should be
+   * printed.
+   *
+   * @return boolean where true means print the descriptions
+   */
+  boolean printUsageGroupHeaders()
+  {
+    // If there is only a single group then we won't print them.
+    int groupsContainingArgs = 0;
+    for (final ArgumentGroup argGroup : argumentGroups)
+    {
+      if (argGroup.containsNonHiddenArguments())
+      {
+        groupsContainingArgs++;
+      }
+    }
+    return groupsContainingArgs > 1;
+  }
+
+
+
+  /**
+   * Sets the usage group description for the default argument group.
+   *
+   * @param description
+   *          for the default group
+   */
+  void setDefaultArgumentGroupDescription(final LocalizableMessage description)
+  {
+    this.defaultArgGroup.setDescription(description);
+  }
+
+
+
+  /**
+   * Sets the provided argument which will be used to identify the file
+   * properties.
+   *
+   * @param argument
+   *          The argument which will be used to identify the file properties.
+   */
+  void setFilePropertiesArgument(final StringArgument argument)
+  {
+    filePropertiesPathArgument = argument;
+  }
+
+
+
+  /**
+   * Sets the usage group description for the general argument group.
+   *
+   * @param description
+   *          for the general group
+   */
+  void setGeneralArgumentGroupDescription(final LocalizableMessage description)
+  {
+    this.generalArgGroup.setDescription(description);
+  }
+
+
+
+  /**
+   * Sets the usage group description for the input/output argument group.
+   *
+   * @param description
+   *          for the input/output group
+   */
+  void setInputOutputArgumentGroupDescription(
+      final LocalizableMessage description)
+  {
+    this.ioArgGroup.setDescription(description);
+  }
+
+
+
+  /**
+   * Sets the usage group description for the LDAP argument group.
+   *
+   * @param description
+   *          for the LDAP group
+   */
+  void setLdapArgumentGroupDescription(final LocalizableMessage description)
+  {
+    this.ldapArgGroup.setDescription(description);
+  }
+
+
+
+  /**
+   * Sets the provided argument which will be used to identify the file
+   * properties.
+   *
+   * @param argument
+   *          The argument which will be used to indicate if we have to look for
+   *          properties file.
+   */
+  void setNoPropertiesFileArgument(final BooleanArgument argument)
+  {
+    noPropertiesFileArgument = argument;
+  }
+
+
+
+  /**
+   * Sets the provided argument as one which will automatically trigger the
+   * output of usage information if it is provided on the command line and no
+   * further argument validation will be performed. Note that the caller will
+   * still need to add this argument to the parser with the
+   * <CODE>addArgument</CODE> method, and the argument should not be required
+   * and should not take a value. Also, the caller will still need to check for
+   * the presence of the usage argument after calling
+   * <CODE>parseArguments</CODE> to know that no further processing will be
+   * required.
+   *
+   * @param argument
+   *          The argument whose presence should automatically trigger the
+   *          display of usage information.
+   */
+  void setUsageArgument(final Argument argument)
+  {
+    usageArgument = argument;
+    usageOutputStream = System.out;
+  }
+
+
+
+  /**
+   * Sets the provided argument as one which will automatically trigger the
+   * output of usage information if it is provided on the command line and no
+   * further argument validation will be performed. Note that the caller will
+   * still need to add this argument to the parser with the
+   * <CODE>addArgument</CODE> method, and the argument should not be required
+   * and should not take a value. Also, the caller will still need to check for
+   * the presence of the usage argument after calling
+   * <CODE>parseArguments</CODE> to know that no further processing will be
+   * required.
+   *
+   * @param argument
+   *          The argument whose presence should automatically trigger the
+   *          display of usage information.
+   * @param outputStream
+   *          The output stream to which the usage information should be
+   *          written.
+   */
+  void setUsageArgument(final Argument argument, final OutputStream outputStream)
+  {
+    usageArgument = argument;
+    usageOutputStream = outputStream;
+  }
+
+
+
+  /**
+   * Indicates whether the version or the usage information has been displayed
+   * to the end user either by an explicit argument like "-H" or "--help", or by
+   * a built-in argument like "-?".
+   *
+   * @return {@code true} if the usage information has been displayed, or
+   *         {@code false} if not.
+   */
+  boolean usageOrVersionDisplayed()
+  {
+    return usageOrVersionDisplayed;
+  }
+
+
+
+  /**
+   * Get the absolute path of the properties file.
+   *
+   * @param directory
+   *          The location in which we should look for properties file
+   * @return The absolute path of the properties file or null
+   */
+  private String findPropertiesFile(final String directory)
+  {
+    // Look for the tools properties file
+    final File f = new File(directory, DEFAULT_OPENDS_PROPERTIES_FILE_NAME
+        + DEFAULT_OPENDS_PROPERTIES_FILE_EXTENSION);
+    if (f.exists() && f.canRead())
+    {
+      return f.getAbsolutePath();
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  private void initGroups()
+  {
+    this.argumentGroups = new TreeSet<ArgumentGroup>();
+    this.argumentGroups.add(defaultArgGroup);
+    this.argumentGroups.add(ldapArgGroup);
+    this.argumentGroups.add(generalArgGroup);
+    this.argumentGroups.add(ioArgGroup);
+
+    try
+    {
+      versionArgument = new BooleanArgument(OPTION_LONG_PRODUCT_VERSION,
+          OPTION_SHORT_PRODUCT_VERSION, OPTION_LONG_PRODUCT_VERSION,
+          INFO_DESCRIPTION_PRODUCT_VERSION.get());
+      this.generalArgGroup.addArgument(versionArgument);
+    }
+    catch (final ArgumentException e)
+    {
+      // ignore
+    }
+  }
+
+
+
+  private boolean isGeneralArgument(final Argument arg)
+  {
+    boolean general = false;
+    if (arg != null)
+    {
+      final String longId = arg.getLongIdentifier();
+      general = OPTION_LONG_HELP.equals(longId)
+          || OPTION_LONG_PRODUCT_VERSION.equals(longId);
+    }
+    return general;
+  }
+
+
+
+  private boolean isInputOutputArgument(final Argument arg)
+  {
+    boolean io = false;
+    if (arg != null)
+    {
+      final String longId = arg.getLongIdentifier();
+      io = OPTION_LONG_VERBOSE.equals(longId)
+          || OPTION_LONG_QUIET.equals(longId)
+          || OPTION_LONG_NO_PROMPT.equals(longId)
+          || OPTION_LONG_PROP_FILE_PATH.equals(longId)
+          || OPTION_LONG_NO_PROP_FILE.equals(longId)
+          || OPTION_LONG_SCRIPT_FRIENDLY.equals(longId)
+          || OPTION_LONG_DONT_WRAP.equals(longId)
+          || OPTION_LONG_ENCODING.equals(longId)
+          || OPTION_LONG_BATCH_FILE_PATH.equals(longId);
+    }
+    return io;
+  }
+
+
+
+  private boolean isLdapConnectionArgument(final Argument arg)
+  {
+    boolean ldap = false;
+    if (arg != null)
+    {
+      final String longId = arg.getLongIdentifier();
+      ldap = OPTION_LONG_USE_SSL.equals(longId)
+          || OPTION_LONG_START_TLS.equals(longId)
+          || OPTION_LONG_HOST.equals(longId) || OPTION_LONG_PORT.equals(longId)
+          || OPTION_LONG_BINDDN.equals(longId)
+          || OPTION_LONG_BINDPWD.equals(longId)
+          || OPTION_LONG_BINDPWD_FILE.equals(longId)
+          || OPTION_LONG_SASLOPTION.equals(longId)
+          || OPTION_LONG_TRUSTALL.equals(longId)
+          || OPTION_LONG_TRUSTSTOREPATH.equals(longId)
+          || OPTION_LONG_TRUSTSTORE_PWD.equals(longId)
+          || OPTION_LONG_TRUSTSTORE_PWD_FILE.equals(longId)
+          || OPTION_LONG_KEYSTOREPATH.equals(longId)
+          || OPTION_LONG_KEYSTORE_PWD.equals(longId)
+          || OPTION_LONG_KEYSTORE_PWD_FILE.equals(longId)
+          || OPTION_LONG_CERT_NICKNAME.equals(longId)
+          || OPTION_LONG_REFERENCED_HOST_NAME.equals(longId)
+          || OPTION_LONG_ADMIN_UID.equals(longId)
+          || OPTION_LONG_REPORT_AUTHZ_ID.equals(longId)
+          || OPTION_LONG_USE_PW_POLICY_CTL.equals(longId)
+          || OPTION_LONG_USE_SASL_EXTERNAL.equals(longId)
+          || OPTION_LONG_PROTOCOL_VERSION.equals(longId);
+    }
+    return ldap;
+  }
+
+
+
+  /**
+   * Appends argument usage information to the provided buffer.
+   *
+   * @param a
+   *          The argument to handle.
+   * @param buffer
+   *          The buffer to which the usage information should be appended.
+   */
+  private void printArgumentUsage(final Argument a, final StringBuilder buffer)
+  {
+    // Write a line with the short and/or long identifiers that may be
+    // used
+    // for the argument.
+    final int indentLength = INDENT.length();
+    final Character shortID = a.getShortIdentifier();
+    final String longID = a.getLongIdentifier();
+    if (shortID != null)
+    {
+      final int currentLength = buffer.length();
+
+      if (usageArgument.getName().equals(a.getName()))
+      {
+        buffer.append("-?, ");
+      }
+
+      buffer.append("-");
+      buffer.append(shortID.charValue());
+
+      if (a.needsValue() && longID == null)
+      {
+        buffer.append(" ");
+        buffer.append(a.getValuePlaceholder());
+      }
+
+      if (longID != null)
+      {
+        final StringBuilder newBuffer = new StringBuilder();
+        newBuffer.append(", --");
+        newBuffer.append(longID);
+
+        if (a.needsValue())
+        {
+          newBuffer.append(" ");
+          newBuffer.append(a.getValuePlaceholder());
+        }
+
+        final int lineLength = (buffer.length() - currentLength)
+            + newBuffer.length();
+        if (lineLength > MAX_LENGTH)
+        {
+          buffer.append(EOL);
+          buffer.append(newBuffer.toString());
+        }
+        else
+        {
+          buffer.append(newBuffer.toString());
+        }
+      }
+
+      buffer.append(EOL);
+    }
+    else
+    {
+      if (longID != null)
+      {
+        if (usageArgument.getName().equals(a.getName()))
+        {
+          buffer.append("-?, ");
+        }
+        buffer.append("--");
+        buffer.append(longID);
+
+        if (a.needsValue())
+        {
+          buffer.append(" ");
+          buffer.append(a.getValuePlaceholder());
+        }
+
+        buffer.append(EOL);
+      }
+    }
+
+    // Write one or more lines with the description of the argument.
+    // We will
+    // indent the description five characters and try our best to wrap
+    // at or
+    // before column 79 so it will be friendly to 80-column displays.
+    buffer.append(
+        Utils.wrapText(a.getDescription(), MAX_LENGTH, indentLength));
+    buffer.append(EOL);
+
+    if (a.needsValue() && (a.getDefaultValue() != null)
+        && (a.getDefaultValue().length() > 0))
+    {
+      buffer.append(INDENT);
+      buffer.append(INFO_ARGPARSER_USAGE_DEFAULT_VALUE.get(a.getDefaultValue())
+          .toString());
+      buffer.append(EOL);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthRate.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthRate.java
new file mode 100644
index 0000000..fa50545
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthRate.java
@@ -0,0 +1,774 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.glassfish.grizzly.TransportFactory;
+import org.opends.sdk.*;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.SearchResultEntry;
+
+import com.sun.opends.sdk.util.RecursiveFutureResult;
+
+
+
+/**
+ * A load generation tool that can be used to load a Directory Server with Bind
+ * requests using one or more LDAP connections.
+ */
+public final class AuthRate extends ConsoleApplication
+{
+  private final class BindPerformanceRunner extends PerformanceRunner
+  {
+    private final class BindStatsThread extends StatsThread
+    {
+      private final String[] extraColumn;
+
+
+
+      private BindStatsThread(final boolean extraFieldRequired)
+      {
+        super(extraFieldRequired ? new String[] { "bind time %" }
+            : new String[0]);
+        extraColumn = new String[extraFieldRequired ? 1 : 0];
+      }
+
+
+
+      @Override
+      String[] getAdditionalColumns()
+      {
+        invalidCredRecentCount.set(0);
+        if (extraColumn.length != 0)
+        {
+          final long searchWaitTime = searchWaitRecentTime.getAndSet(0);
+          extraColumn[0] = String.format("%.1f",
+              ((float) (waitTime - searchWaitTime) / waitTime) * 100.0);
+        }
+        return extraColumn;
+      }
+    }
+
+
+
+    private final class BindUpdateStatsResultHandler extends
+        UpdateStatsResultHandler<BindResult>
+    {
+      private BindUpdateStatsResultHandler(final long startTime,
+          final AsynchronousConnection connection, final ConnectionWorker worker)
+      {
+        super(startTime, connection, worker);
+      }
+
+
+
+      @Override
+      public void handleErrorResult(final ErrorResultException error)
+      {
+        super.handleErrorResult(error);
+
+        if (error.getResult().getResultCode() == ResultCode.INVALID_CREDENTIALS)
+        {
+          invalidCredRecentCount.getAndIncrement();
+        }
+      }
+    }
+
+
+
+    private final class BindWorkerThread extends ConnectionWorker
+    {
+      private SearchRequest sr;
+      private BindRequest br;
+      private Object[] data;
+      private final char[] invalidPassword = "invalid-password".toCharArray();
+
+      private final ThreadLocal<Random> rng = new ThreadLocal<Random>()
+      {
+
+        @Override
+        protected Random initialValue()
+        {
+          return new Random();
+        }
+
+      };
+
+
+
+      private BindWorkerThread(final AsynchronousConnection connection,
+          final ConnectionFactory connectionFactory)
+      {
+        super(connection, connectionFactory);
+      }
+
+
+
+      @Override
+      public FutureResult<?> performOperation(
+          final AsynchronousConnection connection,
+          final DataSource[] dataSources, final long startTime)
+      {
+        if (dataSources != null)
+        {
+          data = DataSource.generateData(dataSources, data);
+          if (data.length == dataSources.length)
+          {
+            final Object[] newData = new Object[data.length + 1];
+            System.arraycopy(data, 0, newData, 0, data.length);
+            data = newData;
+          }
+        }
+        if (filter != null && baseDN != null)
+        {
+          if (sr == null)
+          {
+            if (dataSources == null)
+            {
+              sr = Requests.newSearchRequest(baseDN, scope, filter, attributes);
+            }
+            else
+            {
+              sr = Requests.newSearchRequest(String.format(baseDN, data),
+                  scope, String.format(filter, data), attributes);
+            }
+            sr.setDereferenceAliasesPolicy(dereferencesAliasesPolicy);
+          }
+          else if (dataSources != null)
+          {
+            sr.setFilter(String.format(filter, data));
+            sr.setName(String.format(baseDN, data));
+          }
+
+          final RecursiveFutureResult<SearchResultEntry, BindResult> future =
+            new RecursiveFutureResult<SearchResultEntry, BindResult>(
+              new BindUpdateStatsResultHandler(startTime, connection, this))
+          {
+            @Override
+            protected FutureResult<? extends BindResult> chainResult(
+                final SearchResultEntry innerResult,
+                final ResultHandler<? super BindResult> resultHandler)
+                throws ErrorResultException
+            {
+              searchWaitRecentTime.getAndAdd(System.nanoTime() - startTime);
+              if (data == null)
+              {
+                data = new Object[1];
+              }
+              data[data.length - 1] = innerResult.getName().toString();
+              return performBind(connection, data, resultHandler);
+            }
+          };
+          connection.searchSingleEntry(sr, future);
+          return future;
+        }
+        else
+        {
+          return performBind(connection, data,
+              new BindUpdateStatsResultHandler(startTime, connection, this));
+        }
+      }
+
+
+
+      private FutureResult<BindResult> performBind(
+          final AsynchronousConnection connection, final Object[] data,
+          final ResultHandler<? super BindResult> handler)
+      {
+        final boolean useInvalidPassword;
+
+        // Avoid rng if possible.
+        switch (invalidCredPercent)
+        {
+        case 0:
+          useInvalidPassword = false;
+          break;
+        case 100:
+          useInvalidPassword = true;
+          break;
+        default:
+          final Random r = rng.get();
+          final int p = r.nextInt(100);
+          useInvalidPassword = (p < invalidCredPercent);
+          break;
+        }
+
+        if (bindRequest instanceof SimpleBindRequest)
+        {
+          final SimpleBindRequest o = (SimpleBindRequest) bindRequest;
+          if (br == null)
+          {
+            br = Requests.copyOfSimpleBindRequest(o);
+          }
+
+          final SimpleBindRequest sbr = (SimpleBindRequest) br;
+          if (data != null && o.getName() != null)
+          {
+            sbr.setName(String.format(o.getName(), data));
+          }
+          if (useInvalidPassword)
+          {
+            sbr.setPassword(invalidPassword);
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if (bindRequest instanceof DigestMD5SASLBindRequest)
+        {
+          final DigestMD5SASLBindRequest o = (DigestMD5SASLBindRequest) bindRequest;
+          if (br == null)
+          {
+            br = Requests.copyOfDigestMD5SASLBindRequest(o);
+          }
+
+          final DigestMD5SASLBindRequest sbr = (DigestMD5SASLBindRequest) br;
+          if (data != null)
+          {
+            if (o.getAuthenticationID() != null)
+            {
+              sbr.setAuthenticationID(String.format(o.getAuthenticationID(),
+                  data));
+            }
+            if (o.getAuthorizationID() != null)
+            {
+              sbr.setAuthorizationID(String.format(o.getAuthorizationID(), data));
+            }
+          }
+          if (useInvalidPassword)
+          {
+            sbr.setPassword(invalidPassword);
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if (bindRequest instanceof CRAMMD5SASLBindRequest)
+        {
+          final CRAMMD5SASLBindRequest o = (CRAMMD5SASLBindRequest) bindRequest;
+          if (br == null)
+          {
+            br = Requests.copyOfCRAMMD5SASLBindRequest(o);
+          }
+
+          final CRAMMD5SASLBindRequest sbr = (CRAMMD5SASLBindRequest) br;
+          if (data != null && o.getAuthenticationID() != null)
+          {
+            sbr.setAuthenticationID(String.format(o.getAuthenticationID(), data));
+          }
+          if (useInvalidPassword)
+          {
+            sbr.setPassword(invalidPassword);
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if (bindRequest instanceof GSSAPISASLBindRequest)
+        {
+          final GSSAPISASLBindRequest o = (GSSAPISASLBindRequest) bindRequest;
+          if (br == null)
+          {
+            br = Requests.copyOfGSSAPISASLBindRequest(o);
+          }
+
+          final GSSAPISASLBindRequest sbr = (GSSAPISASLBindRequest) br;
+          if (data != null)
+          {
+            if (o.getAuthenticationID() != null)
+            {
+              sbr.setAuthenticationID(String.format(o.getAuthenticationID(),
+                  data));
+            }
+            if (o.getAuthorizationID() != null)
+            {
+              sbr.setAuthorizationID(String.format(o.getAuthorizationID(), data));
+            }
+          }
+          if (useInvalidPassword)
+          {
+            sbr.setPassword(invalidPassword);
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+        else if (bindRequest instanceof ExternalSASLBindRequest)
+        {
+          final ExternalSASLBindRequest o = (ExternalSASLBindRequest) bindRequest;
+          if (br == null)
+          {
+            br = Requests.copyOfExternalSASLBindRequest(o);
+          }
+
+          final ExternalSASLBindRequest sbr = (ExternalSASLBindRequest) br;
+          if (data != null && o.getAuthorizationID() != null)
+          {
+            sbr.setAuthorizationID(String.format(o.getAuthorizationID(), data));
+          }
+        }
+        else if (bindRequest instanceof PlainSASLBindRequest)
+        {
+          final PlainSASLBindRequest o = (PlainSASLBindRequest) bindRequest;
+          if (br == null)
+          {
+            br = Requests.copyOfPlainSASLBindRequest(o);
+          }
+
+          final PlainSASLBindRequest sbr = (PlainSASLBindRequest) br;
+          if (data != null)
+          {
+            if (o.getAuthenticationID() != null)
+            {
+              sbr.setAuthenticationID(String.format(o.getAuthenticationID(),
+                  data));
+            }
+            if (o.getAuthorizationID() != null)
+            {
+              sbr.setAuthorizationID(String.format(o.getAuthorizationID(), data));
+            }
+          }
+          if (useInvalidPassword)
+          {
+            sbr.setPassword(invalidPassword);
+          }
+          else
+          {
+            sbr.setPassword(o.getPassword());
+          }
+        }
+
+        return connection.bind(br, handler);
+      }
+    }
+
+
+
+    private final AtomicLong searchWaitRecentTime = new AtomicLong();
+
+    private final AtomicInteger invalidCredRecentCount = new AtomicInteger();
+
+    private String filter;
+
+    private String baseDN;
+
+    private SearchScope scope;
+
+    private DereferenceAliasesPolicy dereferencesAliasesPolicy;
+
+    private String[] attributes;
+
+    private BindRequest bindRequest;
+
+    private int invalidCredPercent;
+
+
+
+    private BindPerformanceRunner(final ArgumentParser argParser,
+        final ConsoleApplication app) throws ArgumentException
+    {
+      super(argParser, app, true, true, true);
+    }
+
+
+
+    @Override
+    ConnectionWorker newConnectionWorker(
+        final AsynchronousConnection connection,
+        final ConnectionFactory connectionFactory)
+    {
+      return new BindWorkerThread(connection, connectionFactory);
+    }
+
+
+
+    @Override
+    StatsThread newStatsThread()
+    {
+      return new BindStatsThread(filter != null && baseDN != null);
+    }
+  }
+
+
+
+  /**
+   * The main method for AuthRate tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = mainAuthRate(args, System.in, System.out, System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return The error code.
+   */
+
+  static int mainAuthRate(final String[] args)
+  {
+    return mainAuthRate(args, System.in, System.out, System.err);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+
+  static int mainAuthRate(final String[] args, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+
+  {
+    return new AuthRate(inStream, outStream, errStream).run(args);
+  }
+
+
+
+  private BooleanArgument verbose;
+
+  private BooleanArgument scriptFriendly;
+
+
+
+  private AuthRate(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return scriptFriendly.isPresent();
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription = INFO_AUTHRATE_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(
+        AuthRate.class.getName(), toolDescription, false, true, 0, 0,
+        "[filter format string] [attributes ...]");
+
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+    BindPerformanceRunner runner;
+
+    StringArgument baseDN;
+    MultiChoiceArgument<SearchScope> searchScope;
+    MultiChoiceArgument<DereferenceAliasesPolicy> dereferencePolicy;
+    BooleanArgument showUsage;
+    StringArgument propertiesFileArgument;
+    BooleanArgument noPropertiesFileArgument;
+    IntegerArgument invalidCredPercent;
+
+    try
+    {
+      TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
+      connectionFactoryProvider = new ConnectionFactoryProvider(argParser, this);
+      runner = new BindPerformanceRunner(argParser, this);
+
+      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
+          OPTION_LONG_PROP_FILE_PATH, false, false, true,
+          INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+
+      baseDN = new StringArgument("baseDN", OPTION_SHORT_BASEDN,
+          OPTION_LONG_BASEDN, false, false, true,
+          INFO_BASEDN_PLACEHOLDER.get(), null, null,
+          INFO_SEARCHRATE_TOOL_DESCRIPTION_BASEDN.get());
+      baseDN.setPropertyName(OPTION_LONG_BASEDN);
+      argParser.addArgument(baseDN);
+
+      searchScope = new MultiChoiceArgument<SearchScope>("searchScope", 's',
+          "searchScope", false, true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(),
+          SearchScope.values(), false,
+          INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE.get());
+      searchScope.setPropertyName("searchScope");
+      searchScope.setDefaultValue(SearchScope.WHOLE_SUBTREE);
+      argParser.addArgument(searchScope);
+
+      dereferencePolicy = new MultiChoiceArgument<DereferenceAliasesPolicy>(
+          "derefpolicy", 'a', "dereferencePolicy", false, true,
+          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(),
+          DereferenceAliasesPolicy.values(), false,
+          INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY.get());
+      dereferencePolicy.setPropertyName("dereferencePolicy");
+      dereferencePolicy.setDefaultValue(DereferenceAliasesPolicy.NEVER);
+      argParser.addArgument(dereferencePolicy);
+
+      invalidCredPercent = new IntegerArgument("invalidPassword", 'I',
+          "invalidPassword", false, false, true,
+          LocalizableMessage.raw("{invalidPassword}"), 0, null, true, 0, true,
+          100,
+          LocalizableMessage.raw("Percent of bind operations with simulated "
+              + "invalid password"));
+      invalidCredPercent.setPropertyName("invalidPassword");
+      argParser.addArgument(invalidCredPercent);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+
+      scriptFriendly = new BooleanArgument("scriptFriendly", 'S',
+          "scriptFriendly", INFO_DESCRIPTION_SCRIPT_FRIENDLY.get());
+      scriptFriendly.setPropertyName("scriptFriendly");
+      argParser.addArgument(scriptFriendly);
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+
+      connectionFactory = connectionFactoryProvider.getConnectionFactory();
+      runner.validate();
+
+      runner.bindRequest = connectionFactoryProvider.getBindRequest();
+      if (runner.bindRequest == null)
+      {
+        throw new ArgumentException(
+            LocalizableMessage
+                .raw("Authentication information must be provided to use this tool"));
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    final List<String> attributes = new LinkedList<String>();
+    final ArrayList<String> filterAndAttributeStrings = argParser
+        .getTrailingArguments();
+    if (filterAndAttributeStrings.size() > 0)
+    {
+      // the list of trailing arguments should be structured as follow:
+      // the first trailing argument is considered the filter, the other as
+      // attributes.
+      runner.filter = filterAndAttributeStrings.remove(0);
+
+      // The rest are attributes
+      for (final String s : filterAndAttributeStrings)
+      {
+        attributes.add(s);
+      }
+    }
+    runner.attributes = attributes.toArray(new String[attributes.size()]);
+    runner.baseDN = baseDN.getValue();
+    try
+    {
+      runner.scope = searchScope.getTypedValue();
+      runner.dereferencesAliasesPolicy = dereferencePolicy.getTypedValue();
+      runner.invalidCredPercent = invalidCredPercent.getIntValue();
+    }
+    catch (final ArgumentException ex1)
+    {
+      println(ex1.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Try it out to make sure the format string and data sources
+    // match.
+    final Object[] data = DataSource
+        .generateData(runner.getDataSources(), null);
+    try
+    {
+      if (runner.baseDN != null && runner.filter != null)
+      {
+        String.format(runner.filter, data);
+        String.format(runner.baseDN, data);
+      }
+    }
+    catch (final Exception ex1)
+    {
+      println(LocalizableMessage.raw("Error formatting filter or base DN: "
+          + ex1.toString()));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    return runner.run(connectionFactory);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthenticatedConnectionFactory.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthenticatedConnectionFactory.java
new file mode 100644
index 0000000..4735781
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/AuthenticatedConnectionFactory.java
@@ -0,0 +1,473 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.BindRequest;
+import org.opends.sdk.responses.BindResult;
+
+import com.sun.opends.sdk.util.AsynchronousConnectionDecorator;
+import com.sun.opends.sdk.util.FutureResultTransformer;
+import com.sun.opends.sdk.util.RecursiveFutureResult;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An authenticated connection factory can be used to create pre-authenticated
+ * connections to a Directory Server.
+ * <p>
+ * The connections returned by an authenticated connection factory support all
+ * operations with the exception of Bind requests. Attempts to perform a Bind
+ * will result in an {@code UnsupportedOperationException}.
+ * <p>
+ * In addition, the returned connections support retrieval of the
+ * {@code BindResult} returned from the initial Bind request, or last rebind.
+ * <p>
+ * Support for connection re-authentication is provided through the
+ * {@link #setRebindAllowed} method which, if set to {@code true}, causes
+ * subsequent connections created using the factory to support the
+ * {@code rebind} method.
+ * <p>
+ * If the Bind request fails for some reason (e.g. invalid credentials), then
+ * the connection attempt will fail and an {@code ErrorResultException} will be
+ * thrown.
+ */
+final class AuthenticatedConnectionFactory extends AbstractConnectionFactory
+    implements ConnectionFactory
+{
+
+  /**
+   * An authenticated asynchronous connection supports all operations except
+   * Bind operations.
+   */
+  public static final class AuthenticatedAsynchronousConnection extends
+      AsynchronousConnectionDecorator
+  {
+
+    private final BindRequest request;
+
+    private volatile BindResult result;
+
+
+
+    private AuthenticatedAsynchronousConnection(
+        final AsynchronousConnection connection, final BindRequest request,
+        final BindResult result)
+    {
+      super(connection);
+      this.request = request;
+      this.result = result;
+    }
+
+
+
+    /**
+     * Bind operations are not supported by pre-authenticated connections. This
+     * method will always throw {@code UnsupportedOperationException}.
+     */
+    public FutureResult<BindResult> bind(final BindRequest request,
+        final ResultHandler<? super BindResult> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * Bind operations are not supported by pre-authenticated connections. This
+     * method will always throw {@code UnsupportedOperationException}.
+     */
+    public FutureResult<BindResult> bind(final BindRequest request,
+        final ResultHandler<? super BindResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * Returns an unmodifiable view of the Bind result which was returned from
+     * the server after authentication.
+     *
+     * @return The Bind result which was returned from the server after
+     *         authentication.
+     */
+    public BindResult getAuthenticatedBindResult()
+    {
+      return result;
+    }
+
+
+
+    /**
+     * Re-authenticates to the Directory Server using the bind request
+     * associated with this connection. If re-authentication fails for some
+     * reason then this connection will be automatically closed.
+     *
+     * @param handler
+     *          A result handler which can be used to asynchronously process the
+     *          operation result when it is received, may be {@code null}.
+     * @return A future representing the result of the operation.
+     * @throws UnsupportedOperationException
+     *           If this connection does not support rebind operations.
+     * @throws IllegalStateException
+     *           If this connection has already been closed, i.e. if
+     *           {@code isClosed() == true}.
+     */
+    public FutureResult<BindResult> rebind(
+        final ResultHandler<? super BindResult> handler)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      if (request == null)
+      {
+        throw new UnsupportedOperationException();
+      }
+
+      // Wrap the client handler so that we can update the connection
+      // state.
+      final ResultHandler<? super BindResult> clientHandler = handler;
+
+      final ResultHandler<BindResult> handlerWrapper = new ResultHandler<BindResult>()
+      {
+
+        public void handleErrorResult(final ErrorResultException error)
+        {
+          // This connection is now unauthenticated so prevent
+          // further use.
+          connection.close();
+
+          if (clientHandler != null)
+          {
+            clientHandler.handleErrorResult(error);
+          }
+        }
+
+
+
+        public void handleResult(final BindResult result)
+        {
+          // Save the result.
+          AuthenticatedAsynchronousConnection.this.result = result;
+
+          if (clientHandler != null)
+          {
+            clientHandler.handleResult(result);
+          }
+        }
+
+      };
+
+      return connection.bind(request, handlerWrapper);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+      StringBuilder builder = new StringBuilder();
+      builder.append("AuthenticatedConnection(");
+      builder.append(connection);
+      builder.append(')');
+      return builder.toString();
+    }
+
+  }
+
+
+
+  /**
+   * An authenticated synchronous connection supports all operations except Bind
+   * operations.
+   */
+  public static final class AuthenticatedConnection extends
+      SynchronousConnection
+  {
+    private final AuthenticatedAsynchronousConnection connection;
+
+
+
+    private AuthenticatedConnection(
+        final AuthenticatedAsynchronousConnection connection)
+    {
+      super(connection);
+      this.connection = connection;
+    }
+
+
+
+    /**
+     * Bind operations are not supported by pre-authenticated connections. This
+     * method will always throw {@code UnsupportedOperationException}.
+     */
+    @Override
+    public BindResult bind(final BindRequest request)
+        throws UnsupportedOperationException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * Bind operations are not supported by pre-authenticated connections. This
+     * method will always throw {@code UnsupportedOperationException}.
+     */
+    @Override
+    public BindResult bind(final String name, final char[] password)
+        throws UnsupportedOperationException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * Returns an unmodifiable view of the Bind result which was returned from
+     * the server after authentication.
+     *
+     * @return The Bind result which was returned from the server after
+     *         authentication.
+     */
+    public BindResult getAuthenticatedBindResult()
+    {
+      return connection.getAuthenticatedBindResult();
+    }
+
+
+
+    /**
+     * Re-authenticates to the Directory Server using the bind request
+     * associated with this connection. If re-authentication fails for some
+     * reason then this connection will be automatically closed.
+     *
+     * @return The result of the operation.
+     * @throws ErrorResultException
+     *           If the result code indicates that the request failed for some
+     *           reason.
+     * @throws InterruptedException
+     *           If the current thread was interrupted while waiting.
+     * @throws UnsupportedOperationException
+     *           If this connection does not support rebind operations.
+     * @throws IllegalStateException
+     *           If this connection has already been closed, i.e. if
+     *           {@code isClosed() == true}.
+     */
+    public BindResult rebind() throws ErrorResultException,
+        InterruptedException, UnsupportedOperationException,
+        IllegalStateException
+    {
+
+      if (connection.request == null)
+      {
+        throw new UnsupportedOperationException();
+      }
+      return super.bind(connection.request);
+    }
+  }
+
+
+
+  private static final class FutureResultImpl
+  {
+    private final FutureResultTransformer<BindResult, AsynchronousConnection> futureBindResult;
+
+    private final RecursiveFutureResult<AsynchronousConnection, BindResult> futureConnectionResult;
+
+    private final BindRequest bindRequest;
+
+    private AsynchronousConnection connection;
+
+
+
+    private FutureResultImpl(final BindRequest request,
+        final ResultHandler<? super AsynchronousConnection> handler)
+    {
+      this.bindRequest = request;
+      this.futureBindResult = new FutureResultTransformer<BindResult, AsynchronousConnection>(
+          handler)
+      {
+
+        @Override
+        protected ErrorResultException transformErrorResult(
+            final ErrorResultException errorResult)
+        {
+          // Ensure that the connection is closed.
+          try
+          {
+            connection.close();
+            connection = null;
+          }
+          catch (final Exception e)
+          {
+            // Ignore.
+          }
+          return errorResult;
+        }
+
+
+
+        @Override
+        protected AuthenticatedAsynchronousConnection transformResult(
+            final BindResult result) throws ErrorResultException
+        {
+          // FIXME: should make the result unmodifiable.
+          return new AuthenticatedAsynchronousConnection(connection,
+              bindRequest, result);
+        }
+
+      };
+      this.futureConnectionResult = new RecursiveFutureResult<AsynchronousConnection, BindResult>(
+          futureBindResult)
+      {
+
+        @Override
+        protected FutureResult<? extends BindResult> chainResult(
+            final AsynchronousConnection innerResult,
+            final ResultHandler<? super BindResult> handler)
+            throws ErrorResultException
+        {
+          connection = innerResult;
+          return connection.bind(bindRequest, handler);
+        }
+      };
+      futureBindResult.setFutureResult(futureConnectionResult);
+    }
+
+  }
+
+
+
+  private final BindRequest request;
+
+  private final ConnectionFactory parentFactory;
+
+  private boolean allowRebinds = false;
+
+
+
+  /**
+   * Creates a new authenticated connection factory which will obtain
+   * connections using the provided connection factory and immediately perform
+   * the provided Bind request.
+   *
+   * @param factory
+   *          The connection factory to use for connecting to the Directory
+   *          Server.
+   * @param request
+   *          The Bind request to use for authentication.
+   * @throws NullPointerException
+   *           If {@code factory} or {@code request} was {@code null}.
+   */
+  public AuthenticatedConnectionFactory(final ConnectionFactory factory,
+      final BindRequest request) throws NullPointerException
+  {
+    Validator.ensureNotNull(factory, request);
+    this.parentFactory = factory;
+
+    // FIXME: should do a defensive copy.
+    this.request = request;
+  }
+
+
+
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> handler)
+  {
+    final FutureResultImpl future = new FutureResultImpl(request, handler);
+    future.futureConnectionResult.setFutureResult(parentFactory
+        .getAsynchronousConnection(future.futureConnectionResult));
+    return future.futureBindResult;
+  }
+
+
+
+  /**
+   * Indicates whether or not rebind requests are to be supported by connections
+   * created by this authenticated connection factory.
+   * <p>
+   * Rebind requests are invoked using the connection's {@code rebind} method
+   * which will throw an {@code UnsupportedOperationException} if rebinds are
+   * not supported (the default).
+   *
+   * @return allowRebinds {@code true} if the {@code rebind} operation is to be
+   *         supported, otherwise {@code false}.
+   */
+  public boolean isRebindAllowed()
+  {
+    return allowRebinds;
+  }
+
+
+
+  /**
+   * Specifies whether or not rebind requests are to be supported by connections
+   * created by this authenticated connection factory.
+   * <p>
+   * Rebind requests are invoked using the connection's {@code rebind} method
+   * which will throw an {@code UnsupportedOperationException} if rebinds are
+   * not supported (the default).
+   *
+   * @param allowRebinds
+   *          {@code true} if the {@code rebind} operation is to be supported,
+   *          otherwise {@code false}.
+   * @return A reference to this connection factory.
+   */
+  public AuthenticatedConnectionFactory setRebindAllowed(
+      final boolean allowRebinds)
+  {
+    this.allowRebinds = allowRebinds;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AuthenticatedConnectionFactory(");
+    builder.append(String.valueOf(parentFactory));
+    builder.append(')');
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/BooleanArgument.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/BooleanArgument.java
new file mode 100644
index 0000000..a3a6f6e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/BooleanArgument.java
@@ -0,0 +1,126 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_BOOLEANARG_NO_VALUE_ALLOWED;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines an argument type that will be used to represent Boolean
+ * values. These arguments will never take values from the command line but and
+ * will never be required. If the argument is provided, then it will be
+ * considered true, and if not then it will be considered false. As such, the
+ * default value will always be "false".
+ */
+final class BooleanArgument extends Argument
+{
+  /**
+   * Creates a new Boolean argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public BooleanArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final LocalizableMessage description)
+      throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, false, false, false, null,
+        String.valueOf(false), null, description);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  final public void addValue(final String valueString)
+  {
+    if (valueString != null)
+    {
+      clearValues();
+      super.addValue(valueString);
+      super.setPresent(Boolean.valueOf(valueString));
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  final public void setPresent(final boolean isPresent)
+  {
+    addValue(String.valueOf(isPresent));
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in this
+   * argument.
+   *
+   * @param valueString
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          A buffer into which the invalid reason may be written if the value
+   *          is not acceptable.
+   * @return <CODE>true</CODE> if the value is acceptable, or <CODE>false</CODE>
+   *         if it is not.
+   */
+  @Override
+  public boolean valueIsAcceptable(final String valueString,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    // This argument type should never have a value, so any value
+    // provided will
+    // be unacceptable.
+
+    invalidReason.append(ERR_BOOLEANARG_NO_VALUE_ALLOWED.get(getName()));
+
+    return false;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/CLIException.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/CLIException.java
new file mode 100755
index 0000000..8239c57
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/CLIException.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
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import org.opends.sdk.LocalizableException;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.messages.Messages;
+
+
+
+/**
+ * Thrown to indicate that a problem occurred when interacting with the client.
+ * For example, if input provided by the client was invalid.
+ */
+@SuppressWarnings("serial")
+final class CLIException extends Exception implements LocalizableException
+{
+
+  /**
+   * Adapts any exception that may have occurred whilst reading input from the
+   * console.
+   *
+   * @param cause
+   *          The exception that occurred whilst reading input from the console.
+   * @return Returns a new CLI exception describing a problem that occurred
+   *         whilst reading input from the console.
+   */
+  static CLIException adaptInputException(final Throwable cause)
+  {
+    return new CLIException(Messages.ERR_CONSOLE_INPUT_ERROR.get(cause
+        .getMessage()), cause);
+  }
+
+
+
+  private final LocalizableMessage message;
+
+
+
+  /**
+   * Creates a new CLI exception with the provided message.
+   *
+   * @param message
+   *          The message explaining the problem that occurred.
+   */
+  CLIException(final LocalizableMessage message)
+  {
+    super(message.toString());
+    this.message = message;
+  }
+
+
+
+  /**
+   * Creates a new CLI exception with the provided message and cause.
+   *
+   * @param message
+   *          The message explaining the problem that occurred.
+   * @param cause
+   *          The cause of this exception.
+   */
+  CLIException(final LocalizableMessage message, final Throwable cause)
+  {
+    super(message.toString(), cause);
+    this.message = message;
+  }
+
+
+
+  public LocalizableMessage getMessageObject()
+  {
+    return message;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java
new file mode 100644
index 0000000..3390a64
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConnectionFactoryProvider.java
@@ -0,0 +1,911 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.logging.Logger;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.*;
+
+
+
+/**
+ * A connection factory designed for use with command line tools.
+ */
+final class ConnectionFactoryProvider
+{
+  /**
+   * End Of Line.
+   */
+  static final String EOL = System.getProperty("line.separator");
+
+  /**
+   * The Logger.
+   */
+  static final Logger LOG = Logger
+      .getLogger(ConnectionFactoryProvider.class.getName());
+
+  /**
+   * The 'hostName' global argument.
+   */
+  private StringArgument hostNameArg = null;
+
+  /**
+   * The 'port' global argument.
+   */
+  private IntegerArgument portArg = null;
+
+  /**
+   * The 'bindDN' global argument.
+   */
+  private StringArgument bindNameArg = null;
+
+  /**
+   * The 'bindPasswordFile' global argument.
+   */
+  private FileBasedArgument bindPasswordFileArg = null;
+
+  /**
+   * The 'bindPassword' global argument.
+   */
+  private StringArgument bindPasswordArg = null;
+
+  /**
+   * The 'trustAllArg' global argument.
+   */
+  private BooleanArgument trustAllArg = null;
+
+  /**
+   * The 'trustStore' global argument.
+   */
+  private StringArgument trustStorePathArg = null;
+
+  /**
+   * The 'trustStorePassword' global argument.
+   */
+  private StringArgument trustStorePasswordArg = null;
+
+  /**
+   * The 'trustStorePasswordFile' global argument.
+   */
+  private FileBasedArgument trustStorePasswordFileArg = null;
+
+  /**
+   * The 'keyStore' global argument.
+   */
+  private StringArgument keyStorePathArg = null;
+
+  /**
+   * The 'keyStorePassword' global argument.
+   */
+  private StringArgument keyStorePasswordArg = null;
+
+  /**
+   * The 'keyStorePasswordFile' global argument.
+   */
+  private FileBasedArgument keyStorePasswordFileArg = null;
+
+  /**
+   * The 'certNicknameArg' global argument.
+   */
+  private StringArgument certNicknameArg = null;
+
+  /**
+   * The 'useSSLArg' global argument.
+   */
+  private BooleanArgument useSSLArg = null;
+
+  /**
+   * The 'useStartTLSArg' global argument.
+   */
+  private BooleanArgument useStartTLSArg = null;
+
+  /**
+   * Argument indicating a SASL option.
+   */
+  private StringArgument saslOptionArg = null;
+
+  /**
+   * Whether to request that the server return the authorization ID in the bind
+   * response.
+   */
+  private final BooleanArgument reportAuthzID;
+
+  /**
+   * Whether to use the password policy control in the bind request.
+   */
+  private final BooleanArgument usePasswordPolicyControl;
+
+  private int port = 389;
+
+  private SSLContext sslContext;
+
+  private ConnectionFactory connFactory;
+
+  private ConnectionFactory authenticatedConnFactory;
+
+  private BindRequest bindRequest = null;
+
+  private final ConsoleApplication app;
+
+
+
+  public ConnectionFactoryProvider(final ArgumentParser argumentParser,
+      final ConsoleApplication app) throws ArgumentException
+  {
+    this(argumentParser, app, "cn=Directory Manager", 389, false);
+  }
+
+
+
+  public ConnectionFactoryProvider(final ArgumentParser argumentParser,
+      final ConsoleApplication app, final String defaultBindDN,
+      final int defaultPort, final boolean alwaysSSL) throws ArgumentException
+  {
+    this.app = app;
+    useSSLArg = new BooleanArgument("useSSL", OPTION_SHORT_USE_SSL,
+        OPTION_LONG_USE_SSL, INFO_DESCRIPTION_USE_SSL.get());
+    useSSLArg.setPropertyName(OPTION_LONG_USE_SSL);
+    if (!alwaysSSL)
+    {
+      argumentParser.addLdapConnectionArgument(useSSLArg);
+    }
+    else
+    {
+      // simulate that the useSSL arg has been given in the CLI
+      useSSLArg.setPresent(true);
+    }
+
+    useStartTLSArg = new BooleanArgument("startTLS", OPTION_SHORT_START_TLS,
+        OPTION_LONG_START_TLS, INFO_DESCRIPTION_START_TLS.get());
+    useStartTLSArg.setPropertyName(OPTION_LONG_START_TLS);
+    if (!alwaysSSL)
+    {
+      argumentParser.addLdapConnectionArgument(useStartTLSArg);
+    }
+
+    String defaultHostName;
+    try
+    {
+      defaultHostName = InetAddress.getLocalHost().getHostName();
+    }
+    catch (final Exception e)
+    {
+      defaultHostName = "Unknown (" + e + ")";
+    }
+    hostNameArg = new StringArgument("host", OPTION_SHORT_HOST,
+        OPTION_LONG_HOST, false, false, true, INFO_HOST_PLACEHOLDER.get(),
+        defaultHostName, null, INFO_DESCRIPTION_HOST.get());
+    hostNameArg.setPropertyName(OPTION_LONG_HOST);
+    argumentParser.addLdapConnectionArgument(hostNameArg);
+
+    LocalizableMessage portDescription = INFO_DESCRIPTION_PORT.get();
+    if (alwaysSSL)
+    {
+      portDescription = INFO_DESCRIPTION_ADMIN_PORT.get();
+    }
+
+    portArg = new IntegerArgument("port", OPTION_SHORT_PORT, OPTION_LONG_PORT,
+        false, false, true, INFO_PORT_PLACEHOLDER.get(), defaultPort, null,
+        portDescription);
+    portArg.setPropertyName(OPTION_LONG_PORT);
+    argumentParser.addLdapConnectionArgument(portArg);
+
+    bindNameArg = new StringArgument("bindDN", OPTION_SHORT_BINDDN,
+        OPTION_LONG_BINDDN, false, false, true, INFO_BINDDN_PLACEHOLDER.get(),
+        defaultBindDN, null, INFO_DESCRIPTION_BINDDN.get());
+    bindNameArg.setPropertyName(OPTION_LONG_BINDDN);
+    argumentParser.addLdapConnectionArgument(bindNameArg);
+
+    bindPasswordArg = new StringArgument("bindPassword", OPTION_SHORT_BINDPWD,
+        OPTION_LONG_BINDPWD, false, false, true,
+        INFO_BINDPWD_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_BINDPASSWORD.get());
+    bindPasswordArg.setPropertyName(OPTION_LONG_BINDPWD);
+    argumentParser.addLdapConnectionArgument(bindPasswordArg);
+
+    bindPasswordFileArg = new FileBasedArgument("bindPasswordFile",
+        OPTION_SHORT_BINDPWD_FILE, OPTION_LONG_BINDPWD_FILE, false, false,
+        INFO_BINDPWD_FILE_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_BINDPASSWORDFILE.get());
+    bindPasswordFileArg.setPropertyName(OPTION_LONG_BINDPWD_FILE);
+    argumentParser.addLdapConnectionArgument(bindPasswordFileArg);
+
+    saslOptionArg = new StringArgument("sasloption", OPTION_SHORT_SASLOPTION,
+        OPTION_LONG_SASLOPTION, false, true, true, INFO_SASL_OPTION_PLACEHOLDER
+            .get(), null, null, INFO_LDAP_CONN_DESCRIPTION_SASLOPTIONS.get());
+    saslOptionArg.setPropertyName(OPTION_LONG_SASLOPTION);
+    argumentParser.addLdapConnectionArgument(saslOptionArg);
+
+    trustAllArg = new BooleanArgument("trustAll", OPTION_SHORT_TRUSTALL,
+        OPTION_LONG_TRUSTALL, INFO_DESCRIPTION_TRUSTALL.get());
+    trustAllArg.setPropertyName(OPTION_LONG_TRUSTALL);
+    argumentParser.addLdapConnectionArgument(trustAllArg);
+
+    trustStorePathArg = new StringArgument("trustStorePath",
+        OPTION_SHORT_TRUSTSTOREPATH, OPTION_LONG_TRUSTSTOREPATH, false, false,
+        true, INFO_TRUSTSTOREPATH_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_TRUSTSTOREPATH.get());
+    trustStorePathArg.setPropertyName(OPTION_LONG_TRUSTSTOREPATH);
+    argumentParser.addLdapConnectionArgument(trustStorePathArg);
+
+    trustStorePasswordArg = new StringArgument("trustStorePassword",
+        OPTION_SHORT_TRUSTSTORE_PWD, OPTION_LONG_TRUSTSTORE_PWD, false, false,
+        true, INFO_TRUSTSTORE_PWD_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_TRUSTSTOREPASSWORD.get());
+    trustStorePasswordArg.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD);
+    argumentParser.addLdapConnectionArgument(trustStorePasswordArg);
+
+    trustStorePasswordFileArg = new FileBasedArgument("trustStorePasswordFile",
+        OPTION_SHORT_TRUSTSTORE_PWD_FILE, OPTION_LONG_TRUSTSTORE_PWD_FILE,
+        false, false, INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE.get());
+    trustStorePasswordFileArg.setPropertyName(OPTION_LONG_TRUSTSTORE_PWD_FILE);
+    argumentParser.addLdapConnectionArgument(trustStorePasswordFileArg);
+
+    keyStorePathArg = new StringArgument("keyStorePath",
+        OPTION_SHORT_KEYSTOREPATH, OPTION_LONG_KEYSTOREPATH, false, false,
+        true, INFO_KEYSTOREPATH_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_KEYSTOREPATH.get());
+    keyStorePathArg.setPropertyName(OPTION_LONG_KEYSTOREPATH);
+    argumentParser.addLdapConnectionArgument(keyStorePathArg);
+
+    keyStorePasswordArg = new StringArgument("keyStorePassword",
+        OPTION_SHORT_KEYSTORE_PWD, OPTION_LONG_KEYSTORE_PWD, false, false,
+        true, INFO_KEYSTORE_PWD_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_KEYSTOREPASSWORD.get());
+    keyStorePasswordArg.setPropertyName(OPTION_LONG_KEYSTORE_PWD);
+    argumentParser.addLdapConnectionArgument(keyStorePasswordArg);
+
+    keyStorePasswordFileArg = new FileBasedArgument("keystorePasswordFile",
+        OPTION_SHORT_KEYSTORE_PWD_FILE, OPTION_LONG_KEYSTORE_PWD_FILE, false,
+        false, INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE.get());
+    keyStorePasswordFileArg.setPropertyName(OPTION_LONG_KEYSTORE_PWD_FILE);
+    argumentParser.addLdapConnectionArgument(keyStorePasswordFileArg);
+
+    certNicknameArg = new StringArgument("certNickname",
+        OPTION_SHORT_CERT_NICKNAME, OPTION_LONG_CERT_NICKNAME, false, false,
+        true, INFO_NICKNAME_PLACEHOLDER.get(), null, null,
+        INFO_DESCRIPTION_CERT_NICKNAME.get());
+    certNicknameArg.setPropertyName(OPTION_LONG_CERT_NICKNAME);
+    argumentParser.addLdapConnectionArgument(certNicknameArg);
+
+    reportAuthzID = new BooleanArgument("reportauthzid", 'E',
+        OPTION_LONG_REPORT_AUTHZ_ID, INFO_DESCRIPTION_REPORT_AUTHZID.get());
+    reportAuthzID.setPropertyName(OPTION_LONG_REPORT_AUTHZ_ID);
+    argumentParser.addArgument(reportAuthzID);
+
+    usePasswordPolicyControl = new BooleanArgument("usepwpolicycontrol", null,
+        OPTION_LONG_USE_PW_POLICY_CTL, INFO_DESCRIPTION_USE_PWP_CONTROL.get());
+    usePasswordPolicyControl.setPropertyName(OPTION_LONG_USE_PW_POLICY_CTL);
+    argumentParser.addArgument(usePasswordPolicyControl);
+  }
+
+
+  public ConnectionFactory getConnectionFactory() throws ArgumentException
+  {
+    if(connFactory == null)
+    {
+      port = portArg.getIntValue();
+
+      // Couldn't have at the same time bindPassword and bindPasswordFile
+      if (bindPasswordArg.isPresent() && bindPasswordFileArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            bindPasswordArg.getLongIdentifier(), bindPasswordFileArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+
+      // Couldn't have at the same time trustAll and
+      // trustStore related arg
+      if (trustAllArg.isPresent() && trustStorePathArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustAllArg.getLongIdentifier(), trustStorePathArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+      if (trustAllArg.isPresent() && trustStorePasswordArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustAllArg.getLongIdentifier(), trustStorePasswordArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+      if (trustAllArg.isPresent() && trustStorePasswordFileArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustAllArg.getLongIdentifier(), trustStorePasswordFileArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+
+      // Couldn't have at the same time trustStorePasswordArg and
+      // trustStorePasswordFileArg
+      if (trustStorePasswordArg.isPresent()
+          && trustStorePasswordFileArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            trustStorePasswordArg.getLongIdentifier(), trustStorePasswordFileArg
+                .getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+
+      if (trustStorePathArg.isPresent())
+      {
+        // Check that the path exists and is readable
+        final String value = trustStorePathArg.getValue();
+        if (!canRead(trustStorePathArg.getValue()))
+        {
+          final LocalizableMessage message = ERR_CANNOT_READ_TRUSTSTORE
+              .get(value);
+          throw new ArgumentException(message);
+        }
+      }
+
+      if (keyStorePathArg.isPresent())
+      {
+        // Check that the path exists and is readable
+        final String value = keyStorePathArg.getValue();
+        if (!canRead(trustStorePathArg.getValue()))
+        {
+          final LocalizableMessage message =
+              ERR_CANNOT_READ_KEYSTORE.get(value);
+          throw new ArgumentException(message);
+        }
+      }
+
+      // Couldn't have at the same time startTLSArg and
+      // useSSLArg
+      if (useStartTLSArg.isPresent() && useSSLArg.isPresent())
+      {
+        final LocalizableMessage message = ERR_TOOL_CONFLICTING_ARGS.get(
+            useStartTLSArg.getLongIdentifier(), useSSLArg.getLongIdentifier());
+        throw new ArgumentException(message);
+      }
+
+      try
+      {
+        if (useSSLArg.isPresent() || useStartTLSArg.isPresent())
+        {
+          String clientAlias;
+          if (certNicknameArg.isPresent())
+          {
+            clientAlias = certNicknameArg.getValue();
+          }
+          else
+          {
+            clientAlias = null;
+          }
+
+          if (sslContext == null)
+          {
+            final TrustManager trustManager = getTrustManager();
+
+            X509KeyManager keyManager = null;
+            final X509KeyManager akm =
+                getKeyManager(keyStorePathArg.getValue());
+
+            if (akm != null && clientAlias != null)
+            {
+              keyManager = KeyManagers.useSingleCertificate(clientAlias, akm);
+            }
+
+            sslContext = new SSLContextBuilder().setTrustManager(trustManager)
+                .setKeyManager(keyManager).getSSLContext();
+          }
+        }
+      }
+      catch (final Exception e)
+      {
+        throw new ArgumentException(ERR_LDAP_CONN_CANNOT_INITIALIZE_SSL.get(e
+            .toString()), e);
+      }
+
+      if (sslContext != null)
+      {
+        final LDAPOptions options = new LDAPOptions().setSSLContext(sslContext)
+            .setUseStartTLS(useStartTLSArg.isPresent());
+        connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port,
+            options);
+      }
+      else
+      {
+        connFactory = new LDAPConnectionFactory(hostNameArg.getValue(), port);
+      }
+    }
+    return connFactory;
+  }
+
+  public ConnectionFactory getAuthenticatedConnectionFactory()
+      throws ArgumentException
+  {
+    if(authenticatedConnFactory == null)
+    {
+      authenticatedConnFactory = getConnectionFactory();
+      BindRequest bindRequest = getBindRequest();
+      if(bindRequest != null)
+      {
+        authenticatedConnFactory =
+            Connections.newAuthenticatedConnectionFactory(
+                authenticatedConnFactory, bindRequest);
+      }
+    }
+    return authenticatedConnFactory;
+  }
+
+  /**
+   * Returns <CODE>true</CODE> if we can read on the provided path and
+   * <CODE>false</CODE> otherwise.
+   *
+   * @param path
+   *          the path.
+   * @return <CODE>true</CODE> if we can read on the provided path and
+   *         <CODE>false</CODE> otherwise.
+   */
+  private boolean canRead(final String path)
+  {
+    boolean canRead;
+    final File file = new File(path);
+    canRead = file.exists() && file.canRead();
+    return canRead;
+  }
+
+
+
+  private String getAuthID(final String mech) throws ArgumentException
+  {
+    String value = null;
+    for (final String s : saslOptionArg.getValues())
+    {
+      if (s.startsWith(SASL_PROPERTY_AUTHID))
+      {
+        value = parseSASLOptionValue(s);
+        break;
+      }
+    }
+    if (value == null && bindNameArg.isPresent())
+    {
+      value = "dn: " + bindNameArg.getValue();
+    }
+    if (value == null && app.isInteractive())
+    {
+      try {
+        value = app.readInput(LocalizableMessage.raw("Authentication ID:"),
+            bindNameArg.getDefaultValue() == null ? null : "dn: "
+                + bindNameArg.getDefaultValue());
+      } catch (CLIException e) {
+        throw new ArgumentException(
+            LocalizableMessage.raw("Unable to read authentication ID"), e);
+      }
+    }
+    if (value == null)
+    {
+      final LocalizableMessage message = ERR_LDAPAUTH_SASL_AUTHID_REQUIRED
+          .get(mech);
+      throw new ArgumentException(message);
+    }
+    return value;
+  }
+
+
+
+  private String getAuthzID() throws ArgumentException
+  {
+    String value = null;
+    for (final String s : saslOptionArg.getValues())
+    {
+      if (s.startsWith(SASL_PROPERTY_AUTHZID))
+      {
+        value = parseSASLOptionValue(s);
+        break;
+      }
+    }
+    return value;
+  }
+
+
+
+  private String getBindName() throws ArgumentException
+  {
+    String value = "";
+    if (bindNameArg.isPresent())
+    {
+      value = bindNameArg.getValue();
+    }
+    else if (app.isInteractive())
+    {
+      try {
+        value = app.readInput(LocalizableMessage.raw("Bind name:"), bindNameArg
+            .getDefaultValue() == null ? value : bindNameArg.getDefaultValue());
+      } catch (CLIException e) {
+        throw new ArgumentException(
+            LocalizableMessage.raw("Unable to read bind name"), e);
+      }
+    }
+
+    return value;
+  }
+
+
+
+  public BindRequest getBindRequest() throws ArgumentException
+  {
+    if(bindRequest == null)
+    {
+      String mech = null;
+      for (final String s : saslOptionArg.getValues())
+      {
+        if (s.startsWith(SASL_PROPERTY_MECH))
+        {
+          mech = parseSASLOptionValue(s);
+          break;
+        }
+      }
+
+      if (mech == null)
+      {
+        if (bindNameArg.isPresent() || bindPasswordFileArg.isPresent()
+            || bindPasswordArg.isPresent())
+        {
+          bindRequest = Requests.newSimpleBindRequest(getBindName(),
+              getPassword().toCharArray());
+        }
+      }
+      else if (mech.equals(DigestMD5SASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        bindRequest = Requests.newDigestMD5SASLBindRequest(
+            getAuthID(DigestMD5SASLBindRequest.SASL_MECHANISM_NAME),
+            ByteString.valueOf(getPassword())).setAuthorizationID(getAuthzID())
+            .setRealm(getRealm());
+      }
+      else if (mech.equals(CRAMMD5SASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        bindRequest = Requests.newCRAMMD5SASLBindRequest(
+            getAuthID(CRAMMD5SASLBindRequest.SASL_MECHANISM_NAME), ByteString
+                .valueOf(getPassword()));
+      }
+      else if (mech.equals(GSSAPISASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        bindRequest = Requests.newGSSAPISASLBindRequest(
+            getAuthID(GSSAPISASLBindRequest.SASL_MECHANISM_NAME),
+            ByteString.valueOf(getPassword())).setKDCAddress(getKDC()).setRealm(
+            getRealm()).setAuthorizationID(getAuthzID());
+      }
+      else if (mech.equals(ExternalSASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        if (sslContext == null)
+        {
+          final LocalizableMessage message =
+              ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get();
+          throw new ArgumentException(message);
+        }
+        if (!keyStorePathArg.isPresent() && getKeyStore() == null)
+        {
+          final LocalizableMessage message =
+              ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get();
+          throw new ArgumentException(message);
+        }
+        bindRequest = Requests.newExternalSASLBindRequest().setAuthorizationID(
+            getAuthzID());
+      }
+      else if (mech.equals(PlainSASLBindRequest.SASL_MECHANISM_NAME))
+      {
+        bindRequest = Requests.newPlainSASLBindRequest(
+            getAuthID(PlainSASLBindRequest.SASL_MECHANISM_NAME),
+            ByteString.valueOf(getPassword())).setAuthorizationID(getAuthzID());
+      }
+      else
+      {
+        throw new ArgumentException(ERR_LDAPAUTH_UNSUPPORTED_SASL_MECHANISM
+            .get(mech));
+      }
+    }
+    return bindRequest;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    return connFactory.toString();
+  }
+
+
+
+  private String getKDC() throws ArgumentException
+  {
+    String value = null;
+    for (final String s : saslOptionArg.getValues())
+    {
+      if (s.startsWith(SASL_PROPERTY_KDC))
+      {
+        value = parseSASLOptionValue(s);
+        break;
+      }
+    }
+    return value;
+  }
+
+
+
+  /**
+   * Retrieves a <CODE>KeyManager</CODE> object that may be used for
+   * interactions requiring access to a key manager.
+   *
+   * @param keyStoreFile
+   *          The path to the file containing the key store data.
+   * @return A set of <CODE>KeyManager</CODE> objects that may be used for
+   *         interactions requiring access to a key manager.
+   * @throws java.security.KeyStoreException
+   *           If a problem occurs while interacting with the key store.
+   */
+
+  private X509KeyManager getKeyManager(String keyStoreFile)
+      throws KeyStoreException, IOException, NoSuchAlgorithmException,
+      CertificateException
+  {
+    if (keyStoreFile == null)
+    {
+      // Lookup the file name through the JDK property.
+      keyStoreFile = getKeyStore();
+    }
+
+    if (keyStoreFile == null)
+    {
+      return null;
+    }
+
+    final String keyStorePass = getKeyStorePIN();
+    char[] keyStorePIN = null;
+    if (keyStorePass != null)
+    {
+      keyStorePIN = keyStorePass.toCharArray();
+    }
+
+    final FileInputStream fos = new FileInputStream(keyStoreFile);
+    final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+    keystore.load(fos, keyStorePIN);
+    fos.close();
+
+    return new ApplicationKeyManager(keystore, keyStorePIN);
+  }
+
+
+
+  /**
+   * Read the KeyStore from the JSSE system property.
+   *
+   * @return The path to the key store file.
+   */
+
+  private String getKeyStore()
+  {
+    return System.getProperty("javax.net.ssl.keyStore");
+  }
+
+
+
+  /**
+   * Read the KeyStore PIN from the JSSE system property.
+   *
+   * @return The PIN that should be used to access the key store.
+   */
+
+  private String getKeyStorePIN()
+  {
+    String pwd;
+    if (keyStorePasswordArg.isPresent())
+    {
+      pwd = keyStorePasswordArg.getValue();
+    }
+    else if (keyStorePasswordFileArg.isPresent())
+    {
+      pwd = keyStorePasswordFileArg.getValue();
+    }
+    else
+    {
+      pwd = System.getProperty("javax.net.ssl.keyStorePassword");
+    }
+    return pwd;
+  }
+
+
+
+  /**
+   * Get the password which has to be used for the command. If no password was
+   * specified, return null.
+   *
+   * @return The password stored into the specified file on by the command line
+   *         argument, or null it if not specified.
+   */
+  private String getPassword() throws ArgumentException
+  {
+    String value = "";
+    if (bindPasswordArg.isPresent())
+    {
+      value = bindPasswordArg.getValue();
+    }
+    else if (bindPasswordFileArg.isPresent())
+    {
+      value = bindPasswordFileArg.getValue();
+    }
+    if (value.length() == 0 && app.isInteractive())
+    {
+      try
+      {
+        value = app.readLineOfInput(LocalizableMessage.raw("Bind Password:"));
+      }
+      catch(CLIException e)
+      {
+        throw new ArgumentException(
+            LocalizableMessage.raw("Unable to read password"), e);
+      }
+    }
+
+    return value;
+  }
+
+
+
+  private String getRealm() throws ArgumentException
+  {
+    String value = null;
+    for (final String s : saslOptionArg.getValues())
+    {
+      if (s.startsWith(SASL_PROPERTY_REALM))
+      {
+        value = parseSASLOptionValue(s);
+        break;
+      }
+    }
+    return value;
+  }
+
+
+
+  /**
+   * Retrieves a <CODE>TrustManager</CODE> object that may be used for
+   * interactions requiring access to a trust manager.
+   *
+   * @return A set of <CODE>TrustManager</CODE> objects that may be used for
+   *         interactions requiring access to a trust manager.
+   * @throws GeneralSecurityException
+   *           If a problem occurs while interacting with the trust store.
+   */
+  private TrustManager getTrustManager() throws IOException,
+      GeneralSecurityException
+  {
+    if (trustAllArg.isPresent())
+    {
+      return TrustManagers.trustAll();
+    }
+
+    X509TrustManager tm = null;
+    if (trustStorePathArg.isPresent()
+        && trustStorePathArg.getValue().length() > 0)
+    {
+      tm = TrustManagers.checkValidityDates(TrustManagers.checkHostName(
+          hostNameArg.getValue(), TrustManagers.checkUsingTrustStore(
+              trustStorePathArg.getValue(), getTrustStorePIN().toCharArray(),
+              null)));
+    }
+    else if (getTrustStore() != null)
+    {
+      tm = TrustManagers.checkValidityDates(TrustManagers.checkHostName(
+          hostNameArg.getValue(), TrustManagers.checkUsingTrustStore(
+              getTrustStore(), getTrustStorePIN().toCharArray(), null)));
+    }
+
+    if (app != null && !app.isQuiet())
+    {
+      return new PromptingTrustManager(app, tm);
+    }
+
+    return null;
+  }
+
+
+
+  /**
+   * Read the TrustStore from the JSSE system property.
+   *
+   * @return The path to the trust store file.
+   */
+
+  private String getTrustStore()
+  {
+    return System.getProperty("javax.net.ssl.trustStore");
+  }
+
+
+
+  /**
+   * Read the TrustStore PIN from the JSSE system property.
+   *
+   * @return The PIN that should be used to access the trust store.
+   */
+
+  private String getTrustStorePIN()
+  {
+    String pwd;
+    if (trustStorePasswordArg.isPresent())
+    {
+      pwd = trustStorePasswordArg.getValue();
+    }
+    else if (trustStorePasswordFileArg.isPresent())
+    {
+      pwd = trustStorePasswordFileArg.getValue();
+    }
+    else
+    {
+      pwd = System.getProperty("javax.net.ssl.trustStorePassword");
+    }
+    return pwd;
+  }
+
+
+
+  private String parseSASLOptionValue(final String option)
+      throws ArgumentException
+  {
+    final int equalPos = option.indexOf('=');
+    if (equalPos <= 0)
+    {
+      final LocalizableMessage message = ERR_LDAP_CONN_CANNOT_PARSE_SASL_OPTION
+          .get(option);
+      throw new ArgumentException(message);
+    }
+
+    return option.substring(equalPos + 1, option.length());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConsoleApplication.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConsoleApplication.java
new file mode 100755
index 0000000..077c02a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ConsoleApplication.java
@@ -0,0 +1,586 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2008-2009 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.INFO_ERROR_EMPTY_RESPONSE;
+import static com.sun.opends.sdk.messages.Messages.INFO_MENU_PROMPT_RETURN_TO_CONTINUE;
+import static com.sun.opends.sdk.messages.Messages.INFO_PROMPT_SINGLE_DEFAULT;
+import static com.sun.opends.sdk.tools.Utils.MAX_LINE_WIDTH;
+import static com.sun.opends.sdk.tools.Utils.wrapText;
+
+import java.io.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class provides an abstract base class which can be used as the basis of
+ * a console-based application.
+ */
+abstract class ConsoleApplication
+{
+  private static final class NullOutputStream extends OutputStream
+  {
+    /**
+     * The singleton instance for this class.
+     */
+    private static final NullOutputStream INSTANCE = new NullOutputStream();
+
+    /**
+     * The singleton print stream tied to the null output stream.
+     */
+    private static final PrintStream PRINT_STREAM = new PrintStream(INSTANCE);
+
+
+
+    /**
+     * Retrieves a print stream using this null output stream.
+     *
+     * @return A print stream using this null output stream.
+     */
+    static PrintStream printStream()
+    {
+      return PRINT_STREAM;
+    }
+
+
+
+    /**
+     * Creates a new instance of this null output stream.
+     */
+    private NullOutputStream()
+    {
+      // No implementation is required.
+    }
+
+
+
+    /**
+     * Closes the output stream. This has no effect.
+     */
+    @Override
+    public void close()
+    {
+      // No implementation is required.
+    }
+
+
+
+    /**
+     * Flushes the output stream. This has no effect.
+     */
+    @Override
+    public void flush()
+    {
+      // No implementation is required.
+    }
+
+
+
+    /**
+     * Writes the provided data to this output stream. This has no effect.
+     *
+     * @param b
+     *          The byte array containing the data to be written.
+     */
+    @Override
+    public void write(final byte[] b)
+    {
+      // No implementation is required.
+    }
+
+
+
+    /**
+     * Writes the provided data to this output stream. This has no effect.
+     *
+     * @param b
+     *          The byte array containing the data to be written.
+     * @param off
+     *          The offset at which the real data begins.
+     * @param len
+     *          The number of bytes to be written.
+     */
+    @Override
+    public void write(final byte[] b, final int off, final int len)
+    {
+      // No implementation is required.
+    }
+
+
+
+    /**
+     * Writes the provided byte to this output stream. This has no effect.
+     *
+     * @param b
+     *          The byte to be written.
+     */
+    @Override
+    public void write(final int b)
+    {
+      // No implementation is required.
+    }
+  }
+
+
+
+  /**
+   * A null reader.
+   */
+  private static final class NullReader extends Reader
+  {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close() throws IOException
+    {
+      // Do nothing.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int read(final char[] cbuf, final int off, final int len)
+        throws IOException
+    {
+      return -1;
+    }
+  }
+
+
+
+  // The error stream which this application should use.
+  private final PrintStream err;
+
+  // The input stream reader which this application should use.
+  private final BufferedReader reader;
+
+  private final InputStream in;
+
+  // The output stream which this application should use.
+  private final PrintStream out;
+
+
+
+  /**
+   * Creates a new console application instance.
+   *
+   * @param in
+   *          The application input stream.
+   * @param out
+   *          The application output stream.
+   * @param err
+   *          The application error stream.
+   */
+  ConsoleApplication(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    this.in = in;
+    if (in != null)
+    {
+      this.reader = new BufferedReader(new InputStreamReader(in));
+    }
+    else
+    {
+      this.reader = new BufferedReader(new NullReader());
+    }
+
+    if (out != null)
+    {
+      this.out = new PrintStream(out);
+    }
+    else
+    {
+      this.out = NullOutputStream.printStream();
+    }
+
+    if (err != null)
+    {
+      this.err = new PrintStream(err);
+    }
+    else
+    {
+      this.err = NullOutputStream.printStream();
+    }
+  }
+
+
+
+  /**
+   * Gets the application error stream.
+   *
+   * @return Returns the application error stream.
+   */
+  final PrintStream getErrorStream()
+  {
+    return err;
+  }
+
+
+
+  /**
+   * Gets the application input stream reader.
+   *
+   * @return Returns the application input stream.
+   */
+  final BufferedReader getInputReader()
+  {
+    return reader;
+  }
+
+
+
+  /**
+   * Gets the application input stream.
+   *
+   * @return Returns the application input stream.
+   */
+  final InputStream getInputStream()
+  {
+    return in;
+  }
+
+
+
+  /**
+   * Gets the application output stream.
+   *
+   * @return Returns the application output stream.
+   */
+  final PrintStream getOutputStream()
+  {
+    return out;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  abstract boolean isAdvancedMode();
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  abstract boolean isInteractive();
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  abstract boolean isMenuDrivenMode();
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  abstract boolean isQuiet();
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  abstract boolean isScriptFriendly();
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  abstract boolean isVerbose();
+
+
+
+  /**
+   * Interactively prompts the user to press return to continue. This method
+   * should be called in situations where a user needs to be given a chance to
+   * read some documentation before continuing (continuing may cause the
+   * documentation to be scrolled out of view).
+   */
+  final void pressReturnToContinue()
+  {
+    final LocalizableMessage msg = INFO_MENU_PROMPT_RETURN_TO_CONTINUE.get();
+    try
+    {
+      readLineOfInput(msg);
+    }
+    catch (final CLIException e)
+    {
+      // Ignore the exception - applications don't care.
+    }
+  }
+
+
+
+  /**
+   * Displays a message to the error stream.
+   *
+   * @param msg
+   *          The message.
+   */
+  final void print(final LocalizableMessage msg)
+  {
+    err.print(wrapText(msg, MAX_LINE_WIDTH));
+  }
+
+
+
+  /**
+   * Displays a blank line to the error stream.
+   */
+  final void println()
+  {
+    err.println();
+  }
+
+
+
+  /**
+   * Displays a message to the error stream.
+   *
+   * @param msg
+   *          The message.
+   */
+  final void println(final LocalizableMessage msg)
+  {
+    err.println(wrapText(msg, MAX_LINE_WIDTH));
+  }
+
+
+
+  /**
+   * Displays a message to the error stream indented by the specified number of
+   * columns.
+   *
+   * @param msg
+   *          The message.
+   * @param indent
+   *          The number of columns to indent.
+   */
+  final void println(final LocalizableMessage msg, final int indent)
+  {
+    err.println(wrapText(msg, MAX_LINE_WIDTH, indent));
+  }
+
+
+
+  /**
+   * Displays a blank line to the output stream if we are not in quiet mode.
+   */
+  final void printlnProgress()
+  {
+    if (!isQuiet())
+    {
+      out.println();
+    }
+  }
+
+
+
+  /**
+   * Displays a message to the output stream if we are not in quiet mode.
+   *
+   * @param msg
+   *          The message.
+   */
+  final void printProgress(final LocalizableMessage msg)
+  {
+    if (!isQuiet())
+    {
+      out.print(msg);
+    }
+  }
+
+
+
+  /**
+   * Displays a message to the error stream if verbose mode is enabled.
+   *
+   * @param msg
+   *          The verbose message.
+   */
+  final void printVerboseMessage(final LocalizableMessage msg)
+  {
+    if (isVerbose() || isInteractive())
+    {
+      err.println(wrapText(msg, MAX_LINE_WIDTH));
+    }
+  }
+
+
+
+  /**
+   * Commodity method that interactively prompts (on error output) the user to
+   * provide a string value. Any non-empty string will be allowed (the empty
+   * string will indicate that the default should be used, if there is one).
+   *
+   * @param prompt
+   *          The prompt to present to the user.
+   * @param defaultValue
+   *          The default value to assume if the user presses ENTER without
+   *          typing anything, or <CODE>null</CODE> if there should not be a
+   *          default and the user must explicitly provide a value.
+   * @throws CLIException
+   *           If the line of input could not be retrieved for some reason.
+   * @return The string value read from the user.
+   */
+  final String readInput(LocalizableMessage prompt, final String defaultValue)
+      throws CLIException
+  {
+    while (true)
+    {
+      if (defaultValue != null)
+      {
+        prompt = INFO_PROMPT_SINGLE_DEFAULT
+            .get(prompt.toString(), defaultValue);
+      }
+      final String response = readLineOfInput(prompt);
+
+      if ("".equals(response))
+      {
+        if (defaultValue == null)
+        {
+          print(INFO_ERROR_EMPTY_RESPONSE.get());
+        }
+        else
+        {
+          return defaultValue;
+        }
+      }
+      else
+      {
+        return response;
+      }
+    }
+  }
+
+
+
+  /**
+   * Commodity method that interactively prompts (on error output) the user to
+   * provide a string value. Any non-empty string will be allowed (the empty
+   * string will indicate that the default should be used, if there is one). If
+   * an error occurs a message will be logged to the provided logger.
+   *
+   * @param prompt
+   *          The prompt to present to the user.
+   * @param defaultValue
+   *          The default value to assume if the user presses ENTER without
+   *          typing anything, or <CODE>null</CODE> if there should not be a
+   *          default and the user must explicitly provide a value.
+   * @param logger
+   *          the Logger to be used to log the error message.
+   * @return The string value read from the user.
+   */
+  final String readInput(final LocalizableMessage prompt,
+      final String defaultValue, final Logger logger)
+  {
+    String s = defaultValue;
+    try
+    {
+      s = readInput(prompt, defaultValue);
+    }
+    catch (final CLIException ce)
+    {
+      logger.log(Level.WARNING, "Error reading input: " + ce, ce);
+    }
+    return s;
+  }
+
+
+
+  /**
+   * Interactively retrieves a line of input from the console.
+   *
+   * @param prompt
+   *          The prompt.
+   * @return Returns the line of input, or <code>null</code> if the end of input
+   *         has been reached.
+   * @throws CLIException
+   *           If the line of input could not be retrieved for some reason.
+   */
+  final String readLineOfInput(final LocalizableMessage prompt)
+      throws CLIException
+  {
+    if (prompt != null)
+    {
+      err.print(wrapText(prompt, MAX_LINE_WIDTH));
+      err.print(" ");
+    }
+    try
+    {
+      final String s = reader.readLine();
+      if (s == null)
+      {
+        throw CLIException
+            .adaptInputException(new EOFException("End of input"));
+      }
+      else
+      {
+        return s;
+      }
+    }
+    catch (final IOException e)
+    {
+      throw CLIException.adaptInputException(e);
+    }
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/DataSource.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/DataSource.java
new file mode 100644
index 0000000..49caa30
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/DataSource.java
@@ -0,0 +1,589 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+import org.opends.sdk.LocalizableMessage;
+
+
+/**
+ * A source of data for performance tools.
+ */
+final class DataSource
+{
+  private static interface IDataSource
+  {
+    public IDataSource duplicate();
+
+
+
+    public Object getData();
+  }
+
+
+
+  private static class IncrementLineFileDataSource implements IDataSource
+  {
+    private final List<String> lines;
+    private int next;
+
+
+
+    public IncrementLineFileDataSource(final String file) throws IOException
+    {
+      lines = new ArrayList<String>();
+      final BufferedReader in = new BufferedReader(new FileReader(file));
+      try
+      {
+        String line;
+        while ((line = in.readLine()) != null)
+        {
+          lines.add(line);
+        }
+      }
+      finally
+      {
+        in.close();
+      }
+    }
+
+
+
+    private IncrementLineFileDataSource(final List<String> lines)
+    {
+      this.lines = lines;
+    }
+
+
+
+    public IDataSource duplicate()
+    {
+      return new IncrementLineFileDataSource(lines);
+    }
+
+
+
+    public Object getData()
+    {
+      if (next == lines.size())
+      {
+        next = 0;
+      }
+
+      return lines.get(next++);
+    }
+
+    public static LocalizableMessage getUsage()
+    {
+      return LocalizableMessage.raw(
+        "\"inc({filename})\" Consecutive, incremental line from file");
+    }
+  }
+
+
+
+  private static class IncrementNumberDataSource implements IDataSource
+  {
+    private final int low;
+    private int next;
+    private final int high;
+
+
+
+    public IncrementNumberDataSource(final int low, final int high)
+    {
+      this.low = this.next = low;
+      this.high = high;
+    }
+
+
+
+    public IDataSource duplicate()
+    {
+      return new IncrementNumberDataSource(low, high);
+    }
+
+
+
+    public Object getData()
+    {
+      if (next == high)
+      {
+        next = low;
+        return high;
+      }
+
+      return next++;
+    }
+
+    public static LocalizableMessage getUsage()
+    {
+      return LocalizableMessage.raw(
+        "\"inc({min},{max})\" Consecutive, incremental number");
+    }
+  }
+
+
+
+  private static class RandomLineFileDataSource implements IDataSource
+  {
+    private final List<String> lines;
+    private final Random random;
+
+
+
+    public RandomLineFileDataSource(final long seed, final String file)
+        throws IOException
+    {
+      lines = new ArrayList<String>();
+      random = new Random(seed);
+      final BufferedReader in = new BufferedReader(new FileReader(file));
+      try
+      {
+        String line;
+        while ((line = in.readLine()) != null)
+        {
+          lines.add(line);
+        }
+      }
+      finally
+      {
+        in.close();
+      }
+    }
+
+
+
+    public IDataSource duplicate()
+    {
+      return this;
+    }
+
+
+
+    public Object getData()
+    {
+      return lines.get(random.nextInt(lines.size()));
+    }
+
+    public static LocalizableMessage getUsage()
+    {
+      return LocalizableMessage.raw(
+        "\"rand({filename})\" Random line from file");
+    }
+  }
+
+
+
+  private static class RandomNumberDataSource implements IDataSource
+  {
+    private final Random random;
+    private final int offset;
+    private final int range;
+
+
+
+    public RandomNumberDataSource(final long seed, final int low, final int high)
+    {
+      random = new Random(seed);
+      offset = low;
+      range = high - low;
+    }
+
+
+
+    public IDataSource duplicate()
+    {
+      // There is no state info so threads can just share one instance.
+      return this;
+    }
+
+
+
+    public Object getData()
+    {
+      return random.nextInt(range) + offset;
+    }
+
+    public static LocalizableMessage getUsage()
+    {
+      return LocalizableMessage.raw(
+          "\"rand({min},{max})\" Random number");
+    }
+  }
+
+
+
+  private static final class RandomStringDataSource implements IDataSource
+  {
+    private final Random random;
+    private final int length;
+    private final Character[] charSet;
+
+
+
+    private RandomStringDataSource(final int seed, final int length,
+        final String charSet)
+    {
+      this.length = length;
+      final Set<Character> chars = new HashSet<Character>();
+      for (int i = 0; i < charSet.length(); i++)
+      {
+        final char c = charSet.charAt(i);
+        if (c == '[')
+        {
+          i += 1;
+          final char start = charSet.charAt(i);
+          i += 2;
+          final char end = charSet.charAt(i);
+          i += 1;
+          for (int j = start; j <= end; j++)
+          {
+            chars.add((char) j);
+          }
+        }
+        else
+        {
+          chars.add(c);
+        }
+      }
+      this.charSet = chars.toArray(new Character[chars.size()]);
+      this.random = new Random(seed);
+    }
+
+
+
+    public IDataSource duplicate()
+    {
+      return this;
+    }
+
+
+
+    public Object getData()
+    {
+      final char[] str = new char[length];
+      for (int i = 0; i < length; i++)
+      {
+        str[i] = charSet[random.nextInt(charSet.length)];
+      }
+      return new String(str);
+    }
+
+    public static LocalizableMessage getUsage()
+    {
+      return LocalizableMessage.raw(
+        "\"randStr({length},<charSet>)\" Random string of specified " +
+            "length and optionally from characters in " +
+            "the charSet string. A range of character " +
+            "can be specified with [start-end] charSet notation. " +
+            "If no charSet is specified, the default charSet of " +
+            "[A-Z][a-z][0-9] will be used");
+    }
+  }
+
+
+
+  private static final class StaticDataSource implements IDataSource
+  {
+    private final Object data;
+
+
+
+    private StaticDataSource(final Object data)
+    {
+      this.data = data;
+    }
+
+
+
+    public IDataSource duplicate()
+    {
+      // There is no state info so threads can just share one instance.
+      return this;
+    }
+
+
+
+    public Object getData()
+    {
+      return data;
+    }
+  }
+
+
+
+  /**
+   * Returns Generated data from the specified data sources. Generated data will
+   * be placed in the specified data array. If the data array is null or smaller
+   * than the number of data sources, one will be allocated.
+   *
+   * @param dataSources
+   *          Data sources that will generate arguments referenced by the format
+   *          specifiers in the format string.
+   * @param data
+   *          The array where genereated data will be placed to format the
+   *          string.
+   * @return A formatted string
+   */
+  public static Object[] generateData(final DataSource[] dataSources,
+      Object[] data)
+  {
+    if (data == null || data.length < dataSources.length)
+    {
+      data = new Object[dataSources.length];
+    }
+    for (int i = 0; i < dataSources.length; i++)
+    {
+      data[i] = dataSources[i].getData();
+    }
+    return data;
+  }
+
+
+
+  /**
+   * Parses a list of source definitions into an array of data source objects. A
+   * data source is defined as follows: - rand({min},{max}) generates a random
+   * integer between the min and max. - rand({filename}) retrieves a random line
+   * from a file. - inc({min},{max}) returns incremental integer between the min
+   * and max. - inc({filename}) retrieves lines in order from a file. - {number}
+   * always return the integer as given. - {string} always return the string as
+   * given.
+   *
+   * @param sources
+   *          The list of source definitions to parse.
+   * @return The array of parsed data sources.
+   * @throws ArgumentException
+   *           If an exception occurs while parsing.
+   */
+  public static DataSource[] parse(final List<String> sources)
+      throws ArgumentException
+  {
+    Validator.ensureNotNull(sources);
+    final DataSource[] dataSources = new DataSource[sources.size()];
+    for (int i = 0; i < sources.size(); i++)
+    {
+      final String dataSourceDef = sources.get(i);
+      if (dataSourceDef.startsWith("rand(") && dataSourceDef.endsWith(")"))
+      {
+        final int lparenPos = dataSourceDef.indexOf("(");
+        final int commaPos = dataSourceDef.indexOf(",");
+        final int rparenPos = dataSourceDef.indexOf(")");
+
+        if (commaPos < 0)
+        {
+          try
+          {
+            // This is a file name
+            dataSources[i] = new DataSource(new RandomLineFileDataSource(0,
+                dataSourceDef.substring(lparenPos + 1, rparenPos)));
+          }
+          catch(IOException ioe)
+          {
+            throw new ArgumentException(LocalizableMessage.raw(
+                "Error opening file %s: %s",
+                dataSourceDef.substring(lparenPos + 1, rparenPos),
+                ioe.getMessage()), ioe);
+          }
+          catch(Exception e)
+          {
+            throw new ArgumentException(LocalizableMessage.raw(
+                "Error parsing value generator: %s", e.getMessage()), e);
+          }
+        }
+        else
+        {
+          try
+          {
+            // This range of integers
+            final int low = Integer.parseInt(dataSourceDef.substring(
+                lparenPos + 1, commaPos));
+            final int high = Integer.parseInt(dataSourceDef.substring(
+                commaPos + 1, rparenPos));
+            dataSources[i] = new DataSource(new RandomNumberDataSource(Thread
+                .currentThread().getId(), low, high));
+          }
+          catch(Exception e)
+          {
+            throw new ArgumentException(LocalizableMessage.raw(
+                "Error parsing value generator: %s", e.getMessage()), e);
+          }
+        }
+
+      }
+      else if (dataSourceDef.startsWith("randstr(")
+          && dataSourceDef.endsWith(")"))
+      {
+        final int lparenPos = dataSourceDef.indexOf("(");
+        final int commaPos = dataSourceDef.indexOf(",");
+        final int rparenPos = dataSourceDef.indexOf(")");
+        int length;
+        String charSet;
+        try
+        {
+          if (commaPos < 0)
+          {
+            length = Integer.parseInt(dataSourceDef.substring(lparenPos + 1,
+                rparenPos));
+            charSet = "[A-Z][a-z][0-9]";
+          }
+          else
+          {
+            // length and charSet
+            length = Integer.parseInt(dataSourceDef.substring(lparenPos + 1,
+                commaPos));
+            charSet = dataSourceDef.substring(commaPos + 1, rparenPos);
+          }
+          dataSources[i] = new DataSource(new RandomStringDataSource(0, length,
+              charSet));
+        }
+        catch(Exception e)
+        {
+          throw new ArgumentException(LocalizableMessage.raw(
+              "Error parsing value generator: %s", e.getMessage()), e);
+        }
+      }
+      else if (dataSourceDef.startsWith("inc(") && dataSourceDef.endsWith(")"))
+      {
+        final int lparenPos = dataSourceDef.indexOf("(");
+        final int commaPos = dataSourceDef.indexOf(",");
+        final int rparenPos = dataSourceDef.indexOf(")");
+        if (commaPos < 0)
+        {
+          try
+          {
+            // This is a file name
+            dataSources[i] = new DataSource(new IncrementLineFileDataSource(
+                dataSourceDef.substring(lparenPos + 1, rparenPos)));
+          }
+          catch(IOException ioe)
+          {
+            throw new ArgumentException(LocalizableMessage.raw(
+                "Error opening file %s: %s",
+                dataSourceDef.substring(lparenPos + 1, rparenPos),
+                ioe.getMessage()), ioe);
+          }
+          catch(Exception e)
+          {
+            throw new ArgumentException(LocalizableMessage.raw(
+                "Error parsing value generator: %s", e.getMessage()), e);
+          }
+        }
+        else
+        {
+          try
+          {
+            final int low = Integer.parseInt(dataSourceDef.substring(
+                lparenPos + 1, commaPos));
+            final int high = Integer.parseInt(dataSourceDef.substring(
+                commaPos + 1, rparenPos));
+            dataSources[i] = new DataSource(new IncrementNumberDataSource(low,
+                high));
+          }
+          catch(Exception e)
+          {
+            throw new ArgumentException(LocalizableMessage.raw(
+                "Error parsing value generator: %s", e.getMessage()), e);
+          }
+        }
+      }
+      else
+      {
+        try
+        {
+          dataSources[i] = new DataSource(new StaticDataSource(Integer
+              .parseInt(dataSourceDef)));
+        }
+        catch (final NumberFormatException nfe)
+        {
+          dataSources[i] = new DataSource(new StaticDataSource(dataSourceDef));
+        }
+      }
+    }
+
+    return dataSources;
+  }
+
+
+  public static LocalizableMessage getUsage()
+  {
+    StringBuilder builder = new StringBuilder();
+    builder.append(IncrementLineFileDataSource.getUsage());
+    builder.append(StaticUtils.EOL);
+    builder.append(IncrementNumberDataSource.getUsage());
+    builder.append(StaticUtils.EOL);
+    builder.append(RandomLineFileDataSource.getUsage());
+    builder.append(StaticUtils.EOL);
+    builder.append(RandomNumberDataSource.getUsage());
+    builder.append(StaticUtils.EOL);
+    builder.append(RandomStringDataSource.getUsage());
+    return LocalizableMessage.raw(builder.toString());
+  }
+
+
+
+  private final IDataSource impl;
+
+
+
+  private DataSource(final IDataSource impl)
+  {
+    this.impl = impl;
+  }
+
+
+
+  public DataSource duplicate()
+  {
+    final IDataSource dup = impl.duplicate();
+    if (dup == impl)
+    {
+      return this;
+    }
+    else
+    {
+      return new DataSource(dup);
+    }
+  }
+
+
+
+  public Object getData()
+  {
+    return impl.getData();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/FileBasedArgument.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/FileBasedArgument.java
new file mode 100644
index 0000000..0c333c9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/FileBasedArgument.java
@@ -0,0 +1,278 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.LinkedHashMap;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines an argument whose value will be read from a file rather
+ * than actually specified on the command-line. When a value is specified on the
+ * command line, it will be treated as the path to the file containing the
+ * actual value rather than the value itself. <BR>
+ * <BR>
+ * Note that if if no filename is provided on the command line but a default
+ * value is specified programatically or if the default value is read from a
+ * specified property, then that default value will be taken as the actual value
+ * rather than a filename. <BR>
+ * <BR>
+ * Also note that this argument type assumes that the entire value for the
+ * argument is on a single line in the specified file. If the file contains
+ * multiple lines, then only the first line will be read.
+ */
+final class FileBasedArgument extends Argument
+{
+  // The mapping between filenames specified and the first lines read
+  // from those
+  // files.
+  private final LinkedHashMap<String, String> namesToValues;
+
+
+
+  /**
+   * Creates a new file-based argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public FileBasedArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean isMultiValued, final LocalizableMessage valuePlaceholder,
+      final String defaultValue, final String propertyName,
+      final LocalizableMessage description) throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
+        true, valuePlaceholder, defaultValue, propertyName, description);
+
+    namesToValues = new LinkedHashMap<String, String>();
+  }
+
+
+
+  /**
+   * Creates a new file-based argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public FileBasedArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final LocalizableMessage valuePlaceholder,
+      final LocalizableMessage description) throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, false, true,
+        valuePlaceholder, null, null, description);
+
+    namesToValues = new LinkedHashMap<String, String>();
+  }
+
+
+
+  /**
+   * Adds a value to the set of values for this argument. This should only be
+   * called if the value is allowed by the <CODE>valueIsAcceptable</CODE>
+   * method. Note that in this case, correct behavior depends on a previous
+   * successful call to <CODE>valueIsAcceptable</CODE> so that the value read
+   * from the file may be stored in the name-to-value hash and used in place of
+   * the filename here.
+   *
+   * @param valueString
+   *          The string representation of the value to add to this argument.
+   */
+  @Override
+  public void addValue(final String valueString)
+  {
+    final String actualValue = namesToValues.get(valueString);
+    if (actualValue != null)
+    {
+      super.addValue(actualValue);
+    }
+  }
+
+
+
+  /**
+   * Retrieves a map between the filenames specified on the command line and the
+   * first lines read from those files.
+   *
+   * @return A map between the filenames specified on the command line and the
+   *         first lines read from those files.
+   */
+  public LinkedHashMap<String, String> getNameToValueMap()
+  {
+    return namesToValues;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in this
+   * argument.
+   *
+   * @param valueString
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          A buffer into which the invalid reason may be written if the value
+   *          is not acceptable.
+   * @return <CODE>true</CODE> if the value is acceptable, or <CODE>false</CODE>
+   *         if it is not.
+   */
+  @Override
+  public boolean valueIsAcceptable(final String valueString,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    // First, make sure that the specified file exists.
+    File valueFile;
+    try
+    {
+      valueFile = new File(valueString);
+      if (!valueFile.exists())
+      {
+        invalidReason.append(ERR_FILEARG_NO_SUCH_FILE.get(valueString,
+            getName()));
+        return false;
+      }
+    }
+    catch (final Exception e)
+    {
+      invalidReason.append(ERR_FILEARG_CANNOT_VERIFY_FILE_EXISTENCE.get(
+          valueString, getName(), getExceptionMessage(e)));
+      return false;
+    }
+
+    // Open the file for reading.
+    BufferedReader reader;
+    try
+    {
+      reader = new BufferedReader(new FileReader(valueFile));
+    }
+    catch (final Exception e)
+    {
+      invalidReason.append(ERR_FILEARG_CANNOT_OPEN_FILE.get(valueString,
+          getName(), getExceptionMessage(e)));
+      return false;
+    }
+
+    // Read the first line and close the file.
+    String line;
+    try
+    {
+      line = reader.readLine();
+    }
+    catch (final Exception e)
+    {
+      invalidReason.append(ERR_FILEARG_CANNOT_READ_FILE.get(valueString,
+          getName(), getExceptionMessage(e)));
+      return false;
+    }
+    finally
+    {
+      try
+      {
+        reader.close();
+      }
+      catch (final Exception e)
+      {
+      }
+    }
+
+    // If the line read is null, then that means the file was empty.
+    if (line == null)
+    {
+
+      invalidReason.append(ERR_FILEARG_EMPTY_FILE.get(valueString, getName()));
+      return false;
+    }
+
+    // Store the value in the hash so it will be available for addValue.
+    // We
+    // won't do any validation on the value itself, so anything that we
+    // read
+    // will be considered acceptable.
+    namesToValues.put(valueString, line);
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/IntegerArgument.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/IntegerArgument.java
new file mode 100644
index 0000000..10c616a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/IntegerArgument.java
@@ -0,0 +1,536 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ARG_CANNOT_DECODE_AS_INT;
+import static com.sun.opends.sdk.messages.Messages.ERR_INTARG_LOWER_BOUND_ABOVE_UPPER_BOUND;
+import static com.sun.opends.sdk.messages.Messages.ERR_INTARG_VALUE_ABOVE_UPPER_BOUND;
+import static com.sun.opends.sdk.messages.Messages.ERR_INTARG_VALUE_BELOW_LOWER_BOUND;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines an argument type that will only accept integer values, and
+ * potentially only those in a given range.
+ */
+final class IntegerArgument extends Argument
+{
+  // Indicates whether a lower bound will be enforced for this argument.
+  private final boolean hasLowerBound;
+
+  // Indicates whether an upper bound will be enforced for this
+  // argument.
+  private final boolean hasUpperBound;
+
+  // The lower bound that will be enforced for this argument.
+  private final double lowerBound;
+
+  // The upper bound that will be enforced for this argument.
+  private final double upperBound;
+
+
+
+  /**
+   * Creates a new integer argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param hasLowerBound
+   *          Indicates whether a lower bound should be enforced for values of
+   *          this argument.
+   * @param lowerBound
+   *          The lower bound that should be enforced for values of this
+   *          argument.
+   * @param hasUpperBound
+   *          Indicates whether an upperbound should be enforced for values of
+   *          this argument.
+   * @param upperBound
+   *          The upper bound that should be enforced for values of this
+   *          argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public IntegerArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean isMultiValued, final boolean needsValue,
+      final LocalizableMessage valuePlaceholder, final double defaultValue,
+      final String propertyName, final boolean hasLowerBound,
+      final double lowerBound, final boolean hasUpperBound,
+      final double upperBound, final LocalizableMessage description)
+      throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
+        needsValue, valuePlaceholder, String.valueOf(defaultValue),
+        propertyName, description);
+
+    this.hasLowerBound = hasLowerBound;
+    this.hasUpperBound = hasUpperBound;
+    this.lowerBound = lowerBound;
+    this.upperBound = upperBound;
+
+    if (hasLowerBound && hasUpperBound && (lowerBound > upperBound))
+    {
+      final LocalizableMessage message = ERR_INTARG_LOWER_BOUND_ABOVE_UPPER_BOUND
+          .get(name, lowerBound, upperBound);
+      throw new ArgumentException(message);
+    }
+  }
+
+
+
+  /**
+   * Creates a new integer argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public IntegerArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean isMultiValued, final boolean needsValue,
+      final LocalizableMessage valuePlaceholder, final double defaultValue,
+      final String propertyName, final LocalizableMessage description)
+      throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
+        needsValue, valuePlaceholder, String.format("%f", defaultValue),
+        propertyName, description);
+
+    hasLowerBound = false;
+    hasUpperBound = false;
+    lowerBound = Integer.MIN_VALUE;
+    upperBound = Integer.MAX_VALUE;
+  }
+
+
+
+  /**
+   * Creates a new integer argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param hasLowerBound
+   *          Indicates whether a lower bound should be enforced for values of
+   *          this argument.
+   * @param lowerBound
+   *          The lower bound that should be enforced for values of this
+   *          argument.
+   * @param hasUpperBound
+   *          Indicates whether an upperbound should be enforced for values of
+   *          this argument.
+   * @param upperBound
+   *          The upper bound that should be enforced for values of this
+   *          argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public IntegerArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean isMultiValued, final boolean needsValue,
+      final LocalizableMessage valuePlaceholder, final int defaultValue,
+      final String propertyName, final boolean hasLowerBound,
+      final double lowerBound, final boolean hasUpperBound,
+      final double upperBound, final LocalizableMessage description)
+      throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
+        needsValue, valuePlaceholder, String.valueOf(defaultValue),
+        propertyName, description);
+
+    this.hasLowerBound = hasLowerBound;
+    this.hasUpperBound = hasUpperBound;
+    this.lowerBound = lowerBound;
+    this.upperBound = upperBound;
+
+    if (hasLowerBound && hasUpperBound && (lowerBound > upperBound))
+    {
+      final LocalizableMessage message = ERR_INTARG_LOWER_BOUND_ABOVE_UPPER_BOUND
+          .get(name, lowerBound, upperBound);
+      throw new ArgumentException(message);
+    }
+  }
+
+
+
+  /**
+   * Creates a new integer argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public IntegerArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean isMultiValued, final boolean needsValue,
+      final LocalizableMessage valuePlaceholder, final int defaultValue,
+      final String propertyName, final LocalizableMessage description)
+      throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
+        needsValue, valuePlaceholder, String.valueOf(defaultValue),
+        propertyName, description);
+
+    hasLowerBound = false;
+    hasUpperBound = false;
+    lowerBound = Integer.MIN_VALUE;
+    upperBound = Integer.MAX_VALUE;
+  }
+
+
+
+  /**
+   * Creates a new integer argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param hasLowerBound
+   *          Indicates whether a lower bound should be enforced for values of
+   *          this argument.
+   * @param lowerBound
+   *          The lower bound that should be enforced for values of this
+   *          argument.
+   * @param hasUpperBound
+   *          Indicates whether an upperbound should be enforced for values of
+   *          this argument.
+   * @param upperBound
+   *          The upper bound that should be enforced for values of this
+   *          argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public IntegerArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean needsValue, final LocalizableMessage valuePlaceholder,
+      final boolean hasLowerBound, final double lowerBound,
+      final boolean hasUpperBound, final double upperBound,
+      final LocalizableMessage description) throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, false, needsValue,
+        valuePlaceholder, null, null, description);
+
+    this.hasLowerBound = hasLowerBound;
+    this.hasUpperBound = hasUpperBound;
+    this.lowerBound = lowerBound;
+    this.upperBound = upperBound;
+
+    if (hasLowerBound && hasUpperBound && (lowerBound > upperBound))
+    {
+      final LocalizableMessage message = ERR_INTARG_LOWER_BOUND_ABOVE_UPPER_BOUND
+          .get(name, lowerBound, upperBound);
+      throw new ArgumentException(message);
+    }
+  }
+
+
+
+  /**
+   * Creates a new integer argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public IntegerArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean needsValue, final LocalizableMessage valuePlaceholder,
+      final LocalizableMessage description) throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, false, needsValue,
+        valuePlaceholder, null, null, description);
+
+    hasLowerBound = false;
+    hasUpperBound = false;
+    lowerBound = Double.MIN_VALUE;
+    upperBound = Double.MAX_VALUE;
+  }
+
+
+
+  /**
+   * Retrieves the lower bound that may be enforced for values of this argument.
+   *
+   * @return The lower bound that may be enforced for values of this argument.
+   */
+  public double getLowerBound()
+  {
+    return lowerBound;
+  }
+
+
+
+  /**
+   * Retrieves the upper bound that may be enforced for values of this argument.
+   *
+   * @return The upper bound that may be enforced for values of this argument.
+   */
+  public double getUpperBound()
+  {
+    return upperBound;
+  }
+
+
+
+  /**
+   * Indicates whether a lower bound should be enforced for values of this
+   * argument.
+   *
+   * @return <CODE>true</CODE> if a lower bound should be enforced for values of
+   *         this argument, or <CODE>false</CODE> if not.
+   */
+  public boolean hasLowerBound()
+  {
+    return hasLowerBound;
+  }
+
+
+
+  /**
+   * Indicates whether a upper bound should be enforced for values of this
+   * argument.
+   *
+   * @return <CODE>true</CODE> if a upper bound should be enforced for values of
+   *         this argument, or <CODE>false</CODE> if not.
+   */
+  public boolean hasUpperBound()
+  {
+    return hasUpperBound;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in this
+   * argument.
+   *
+   * @param valueString
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          A buffer into which the invalid reason may be written if the value
+   *          is not acceptable.
+   * @return <CODE>true</CODE> if the value is acceptable, or <CODE>false</CODE>
+   *         if it is not.
+   */
+  @Override
+  public boolean valueIsAcceptable(final String valueString,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    // First, the value must be decodable as an integer.
+    double intValue;
+    try
+    {
+      intValue = Double.parseDouble(valueString);
+    }
+    catch (final Exception e)
+    {
+      invalidReason.append(ERR_ARG_CANNOT_DECODE_AS_INT.get(valueString,
+          getName()));
+      return false;
+    }
+
+    // If there is a lower bound, then the value must be greater than or
+    // equal to it.
+    if (hasLowerBound && (intValue < lowerBound))
+    {
+      invalidReason.append(ERR_INTARG_VALUE_BELOW_LOWER_BOUND.get(getName(),
+          intValue, lowerBound));
+      return false;
+    }
+
+    // If there is an upper bound, then the value must be less than or
+    // equal to it.
+    if (hasUpperBound && (intValue > upperBound))
+    {
+
+      invalidReason.append(ERR_INTARG_VALUE_ABOVE_UPPER_BOUND.get(getName(),
+          intValue, upperBound));
+      return false;
+    }
+
+    // At this point, the value should be acceptable.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPCompare.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPCompare.java
new file mode 100644
index 0000000..6012150
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPCompare.java
@@ -0,0 +1,660 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.AssertionRequestControl;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ProxiedAuthV2RequestControl;
+import org.opends.sdk.requests.CompareRequest;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+
+import com.sun.opends.sdk.util.Base64;
+
+
+
+/**
+ * A tool that can be used to issue Compare requests to the Directory Server.
+ */
+public final class LDAPCompare extends ConsoleApplication
+{
+  /**
+   * The main method for LDAPModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = mainCompare(args, System.in, System.out, System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the LDAPModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return The error code.
+   */
+
+  static int mainCompare(final String[] args)
+  {
+    return mainCompare(args, System.in, System.out, System.err);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the LDAPModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program. specified,
+   *          the number of matching entries should be returned or not.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+  static int mainCompare(final String[] args, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+  {
+    return new LDAPCompare(inStream, outStream, errStream).run(args);
+  }
+
+
+
+  private BooleanArgument verbose;
+
+
+
+  private LDAPCompare(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int executeCompare(final CompareRequest request,
+      final Connection connection)
+  {
+    println(INFO_PROCESSING_COMPARE_OPERATION.get(request
+        .getAttributeDescription().toString(), request
+        .getAssertionValueAsString(), request.getName().toString()));
+    if (connection != null)
+    {
+      try
+      {
+        Result result;
+        try
+        {
+          result = connection.compare(request);
+        }
+        catch (final InterruptedException e)
+        {
+          // This shouldn't happen because there are no other threads to
+          // interrupt this one.
+          result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED)
+              .setCause(e).setDiagnosticMessage(e.getLocalizedMessage());
+          throw ErrorResultException.wrap(result);
+        }
+
+        if (result.getResultCode() == ResultCode.COMPARE_FALSE)
+        {
+          println(INFO_COMPARE_OPERATION_RESULT_FALSE.get(request.getName()
+              .toString()));
+        }
+        else
+        {
+
+          println(INFO_COMPARE_OPERATION_RESULT_TRUE.get(request.getName()
+              .toString()));
+        }
+      }
+      catch (final ErrorResultException ere)
+      {
+        final LocalizableMessage msg = INFO_OPERATION_FAILED.get("COMPARE");
+        println(msg);
+        final Result r = ere.getResult();
+        println(ERR_TOOL_RESULT_CODE.get(r.getResultCode().intValue(), r
+            .getResultCode().toString()));
+        if ((r.getDiagnosticMessage() != null)
+            && (r.getDiagnosticMessage().length() > 0))
+        {
+          println(LocalizableMessage.raw(r.getDiagnosticMessage()));
+        }
+        if (r.getMatchedDN() != null && r.getMatchedDN().length() > 0)
+        {
+          println(ERR_TOOL_MATCHED_DN.get(r.getMatchedDN()));
+        }
+        return r.getResultCode().intValue();
+      }
+    }
+    return ResultCode.SUCCESS.intValue();
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription = INFO_LDAPCOMPARE_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(LDAPCompare.class
+        .getName(), toolDescription, false, true, 1, 0,
+        "attribute:value [DN ...]");
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+
+    BooleanArgument continueOnError;
+    BooleanArgument noop;
+    BooleanArgument showUsage;
+    IntegerArgument version;
+    StringArgument assertionFilter;
+    StringArgument controlStr;
+    StringArgument encodingStr;
+    StringArgument filename;
+    StringArgument proxyAuthzID;
+    StringArgument propertiesFileArgument;
+    BooleanArgument noPropertiesFileArgument;
+
+    try
+    {
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
+      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
+          OPTION_LONG_PROP_FILE_PATH, false, false, true,
+          INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      filename = new StringArgument("filename", OPTION_SHORT_FILENAME,
+          OPTION_LONG_FILENAME, false, false, true,
+          INFO_FILE_PLACEHOLDER.get(), null, null,
+          INFO_LDAPMODIFY_DESCRIPTION_FILENAME.get());
+      filename.setPropertyName(OPTION_LONG_FILENAME);
+      argParser.addArgument(filename);
+
+      proxyAuthzID = new StringArgument("proxy_authzid",
+          OPTION_SHORT_PROXYAUTHID, OPTION_LONG_PROXYAUTHID, false, false,
+          true, INFO_PROXYAUTHID_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROXY_AUTHZID.get());
+      proxyAuthzID.setPropertyName(OPTION_LONG_PROXYAUTHID);
+      argParser.addArgument(proxyAuthzID);
+
+      assertionFilter = new StringArgument("assertionfilter", null,
+          OPTION_LONG_ASSERTION_FILE, false, false, true,
+          INFO_ASSERTION_FILTER_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_ASSERTION_FILTER.get());
+      assertionFilter.setPropertyName(OPTION_LONG_ASSERTION_FILE);
+      argParser.addArgument(assertionFilter);
+
+      controlStr = new StringArgument("control", 'J', "control", false, true,
+          true, INFO_LDAP_CONTROL_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_CONTROLS.get());
+      controlStr.setPropertyName("control");
+      argParser.addArgument(controlStr);
+
+      version = new IntegerArgument("version", OPTION_SHORT_PROTOCOL_VERSION,
+          OPTION_LONG_PROTOCOL_VERSION, false, false, true,
+          INFO_PROTOCOL_VERSION_PLACEHOLDER.get(), 3, null,
+          INFO_DESCRIPTION_VERSION.get());
+      version.setPropertyName(OPTION_LONG_PROTOCOL_VERSION);
+      argParser.addArgument(version);
+
+      encodingStr = new StringArgument("encoding", 'i', "encoding", false,
+          false, true, INFO_ENCODING_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_ENCODING.get());
+      encodingStr.setPropertyName("encoding");
+      argParser.addArgument(encodingStr);
+
+      continueOnError = new BooleanArgument("continueOnError", 'c',
+          "continueOnError", INFO_DESCRIPTION_CONTINUE_ON_ERROR.get());
+      continueOnError.setPropertyName("continueOnError");
+      argParser.addArgument(continueOnError);
+
+      noop = new BooleanArgument("no-op", OPTION_SHORT_DRYRUN,
+          OPTION_LONG_DRYRUN, INFO_DESCRIPTION_NOOP.get());
+      noop.setPropertyName(OPTION_LONG_DRYRUN);
+      argParser.addArgument(noop);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    try
+    {
+      final int versionNumber = version.getIntValue();
+      if (versionNumber != 2 && versionNumber != 3)
+      {
+        println(ERR_DESCRIPTION_INVALID_VERSION.get(String
+            .valueOf(versionNumber)));
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      println(ERR_DESCRIPTION_INVALID_VERSION.get(String.valueOf(version
+          .getValue())));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    final ArrayList<String> dnStrings = new ArrayList<String>();
+    final ArrayList<String> attrAndDNStrings = argParser.getTrailingArguments();
+
+    if (attrAndDNStrings.isEmpty())
+    {
+      final LocalizableMessage message = ERR_LDAPCOMPARE_NO_ATTR.get();
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // First element should be an attribute string.
+    final String attributeString = attrAndDNStrings.remove(0);
+
+    // Rest are DN strings
+    for (final String s : attrAndDNStrings)
+    {
+      dnStrings.add(s);
+    }
+
+    // If no DNs were provided, then exit with an error.
+    if (dnStrings.isEmpty() && (!filename.isPresent()))
+    {
+      println(ERR_LDAPCOMPARE_NO_DNS.get());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // If trailing DNs were provided and the filename argument was also
+    // provided, exit with an error.
+    if (!dnStrings.isEmpty() && filename.isPresent())
+    {
+      println(ERR_LDAPCOMPARE_FILENAME_AND_DNS.get());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // parse the attribute string
+    final int idx = attributeString.indexOf(":");
+    if (idx == -1)
+    {
+      final LocalizableMessage message = ERR_LDAPCOMPARE_INVALID_ATTR_STRING
+          .get(attributeString);
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+    final String attributeType = attributeString.substring(0, idx);
+    ByteString attributeVal;
+    final String remainder = attributeString.substring(idx + 1, attributeString
+        .length());
+    if (remainder.length() > 0)
+    {
+      final char nextChar = remainder.charAt(0);
+      if (nextChar == ':')
+      {
+        final String base64 = remainder.substring(1, remainder.length());
+        try
+        {
+          attributeVal = Base64.decode(base64);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          println(INFO_COMPARE_CANNOT_BASE64_DECODE_ASSERTION_VALUE.get());
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+      else if (nextChar == '<')
+      {
+        try
+        {
+          final String filePath = remainder.substring(1, remainder.length());
+          attributeVal = ByteString.wrap(Utils.readBytesFromFile(filePath));
+        }
+        catch (final Exception e)
+        {
+          println(INFO_COMPARE_CANNOT_READ_ASSERTION_VALUE_FROM_FILE.get(String
+              .valueOf(e)));
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+      else
+      {
+        attributeVal = ByteString.valueOf(remainder);
+      }
+    }
+    else
+    {
+      attributeVal = ByteString.valueOf(remainder);
+    }
+
+    final CompareRequest compare = Requests.newCompareRequest("",
+        attributeType, attributeVal);
+
+    if (controlStr.isPresent())
+    {
+      for (final String ctrlString : controlStr.getValues())
+      {
+        try
+        {
+          final Control ctrl = Utils.getControl(ctrlString);
+          compare.addControl(ctrl);
+        }
+        catch (final DecodeException de)
+        {
+          final LocalizableMessage message = ERR_TOOL_INVALID_CONTROL_STRING
+              .get(ctrlString);
+          println(message);
+          ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+    }
+
+    if (proxyAuthzID.isPresent())
+    {
+      final Control proxyControl = ProxiedAuthV2RequestControl
+          .newControl(proxyAuthzID.getValue());
+      compare.addControl(proxyControl);
+    }
+
+    if (assertionFilter.isPresent())
+    {
+      final String filterString = assertionFilter.getValue();
+      Filter filter;
+      try
+      {
+        filter = Filter.valueOf(filterString);
+
+        // FIXME -- Change this to the correct OID when the official one
+        // is assigned.
+        final Control assertionControl = AssertionRequestControl.newControl(
+            true, filter);
+        compare.addControl(assertionControl);
+      }
+      catch (final LocalizedIllegalArgumentException le)
+      {
+        final LocalizableMessage message = ERR_LDAP_ASSERTION_INVALID_FILTER
+            .get(le.getMessage());
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+
+    BufferedReader rdr = null;
+    if (!filename.isPresent() && dnStrings.isEmpty())
+    {
+      // Read from stdin.
+      rdr = new BufferedReader(new InputStreamReader(System.in));
+    }
+    else if (filename.isPresent())
+    {
+      try
+      {
+        rdr = new BufferedReader(new FileReader(filename.getValue()));
+      }
+      catch (final FileNotFoundException t)
+      {
+        println(ERR_LDAPCOMPARE_ERROR_READING_FILE.get(filename.getValue(), t
+            .toString()));
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+
+    Connection connection = null;
+    if (!noop.isPresent())
+    {
+      try
+      {
+        connection = connectionFactory.getConnection();
+      }
+      catch (final ErrorResultException ere)
+      {
+        println(LocalizableMessage.raw(ere.getMessage()));
+        return ere.getResult().getResultCode().intValue();
+      }
+      catch (final InterruptedException e)
+      {
+        // This shouldn't happen because there are no other threads to
+        // interrupt this one.
+        println(LocalizableMessage.raw(e.getLocalizedMessage()));
+        return ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue();
+      }
+    }
+
+    try
+    {
+      int result;
+      if (rdr == null)
+      {
+        for (final String dn : dnStrings)
+        {
+          compare.setName(dn);
+          result = executeCompare(compare, connection);
+          if (result != 0 && !continueOnError.isPresent())
+          {
+            return result;
+          }
+        }
+      }
+      else
+      {
+        String dn;
+        try
+        {
+          while ((dn = rdr.readLine()) != null)
+          {
+            compare.setName(dn);
+            result = executeCompare(compare, connection);
+            if (result != 0 && !continueOnError.isPresent())
+            {
+              return result;
+            }
+          }
+        }
+        catch (final IOException ioe)
+        {
+          println(ERR_LDAPCOMPARE_ERROR_READING_FILE.get(filename.getValue(),
+              ioe.toString()));
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      if (rdr != null)
+      {
+        try
+        {
+          rdr.close();
+        }
+        catch (final IOException ioe)
+        {
+          // Just ignore
+        }
+      }
+    }
+
+    return 0;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPModify.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPModify.java
new file mode 100644
index 0000000..beedc3a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPModify.java
@@ -0,0 +1,798 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.*;
+import org.opends.sdk.ldif.*;
+import org.opends.sdk.requests.AddRequest;
+import org.opends.sdk.requests.DeleteRequest;
+import org.opends.sdk.requests.ModifyDNRequest;
+import org.opends.sdk.requests.ModifyRequest;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * A tool that can be used to issue update (Add/Delete/Modify/ModifyDN) requests
+ * to the Directory Server.
+ */
+public final class LDAPModify extends ConsoleApplication
+{
+  private class VisitorImpl implements
+      ChangeRecordVisitor<Integer, java.lang.Void>
+  {
+    public Integer visitChangeRecord(final Void aVoid, final AddRequest change)
+    {
+      for (final Control control : controls)
+      {
+        change.addControl(control);
+      }
+      final String opType = "ADD";
+      println(INFO_PROCESSING_OPERATION
+          .get(opType, change.getName().toString()));
+      if (connection != null)
+      {
+        try
+        {
+          Result r;
+          try
+          {
+            r = connection.add(change);
+          }
+          catch (final InterruptedException e)
+          {
+            // This shouldn't happen because there are no other threads
+            // to interrupt this one.
+            r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED)
+                .setCause(e).setDiagnosticMessage(e.getLocalizedMessage());
+            throw ErrorResultException.wrap(r);
+          }
+          printResult(opType, change.getName().toString(), r);
+          return r.getResultCode().intValue();
+        }
+        catch (final ErrorResultException ere)
+        {
+          return Utils.printErrorMessage(LDAPModify.this, ere);
+        }
+      }
+      return ResultCode.SUCCESS.intValue();
+    }
+
+
+
+    public Integer visitChangeRecord(final Void aVoid,
+        final DeleteRequest change)
+    {
+      for (final Control control : controls)
+      {
+        change.addControl(control);
+      }
+      final String opType = "DELETE";
+      println(INFO_PROCESSING_OPERATION
+          .get(opType, change.getName().toString()));
+      if (connection != null)
+      {
+        try
+        {
+          Result r;
+          try
+          {
+            r = connection.delete(change);
+          }
+          catch (final InterruptedException e)
+          {
+            // This shouldn't happen because there are no other threads
+            // to interrupt this one.
+            r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED)
+                .setCause(e).setDiagnosticMessage(e.getLocalizedMessage());
+            throw ErrorResultException.wrap(r);
+          }
+          printResult(opType, change.getName().toString(), r);
+          return r.getResultCode().intValue();
+        }
+        catch (final ErrorResultException ere)
+        {
+          return Utils.printErrorMessage(LDAPModify.this, ere);
+        }
+      }
+      return ResultCode.SUCCESS.intValue();
+    }
+
+
+
+    public Integer visitChangeRecord(final Void aVoid,
+        final ModifyDNRequest change)
+    {
+      for (final Control control : controls)
+      {
+        change.addControl(control);
+      }
+      final String opType = "MODIFY DN";
+      println(INFO_PROCESSING_OPERATION
+          .get(opType, change.getName().toString()));
+      if (connection != null)
+      {
+        try
+        {
+          Result r;
+          try
+          {
+            r = connection.modifyDN(change);
+          }
+          catch (final InterruptedException e)
+          {
+            // This shouldn't happen because there are no other threads
+            // to interrupt this one.
+            r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED)
+                .setCause(e).setDiagnosticMessage(e.getLocalizedMessage());
+            throw ErrorResultException.wrap(r);
+          }
+          printResult(opType, change.getName().toString(), r);
+          return r.getResultCode().intValue();
+        }
+        catch (final ErrorResultException ere)
+        {
+          return Utils.printErrorMessage(LDAPModify.this, ere);
+        }
+      }
+      return ResultCode.SUCCESS.intValue();
+    }
+
+
+
+    public Integer visitChangeRecord(final Void aVoid,
+        final ModifyRequest change)
+    {
+      for (final Control control : controls)
+      {
+        change.addControl(control);
+      }
+      final String opType = "MODIFY";
+      println(INFO_PROCESSING_OPERATION
+          .get(opType, change.getName().toString()));
+      if (connection != null)
+      {
+        try
+        {
+          Result r;
+          try
+          {
+            r = connection.modify(change);
+          }
+          catch (final InterruptedException e)
+          {
+            // This shouldn't happen because there are no other threads
+            // to interrupt this one.
+            r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED)
+                .setCause(e).setDiagnosticMessage(e.getLocalizedMessage());
+            throw ErrorResultException.wrap(r);
+          }
+          printResult(opType, change.getName().toString(), r);
+          return r.getResultCode().intValue();
+        }
+        catch (final ErrorResultException ere)
+        {
+          return Utils.printErrorMessage(LDAPModify.this, ere);
+        }
+      }
+      return ResultCode.SUCCESS.intValue();
+    }
+
+
+
+    private void printResult(final String operationType, final String name,
+        final Result r)
+    {
+      if (r.getResultCode() != ResultCode.SUCCESS
+          && r.getResultCode() != ResultCode.REFERRAL)
+      {
+        final LocalizableMessage msg = INFO_OPERATION_FAILED.get(operationType);
+        println(msg);
+        println(ERR_TOOL_RESULT_CODE.get(r.getResultCode().intValue(), r
+            .getResultCode().toString()));
+        if ((r.getDiagnosticMessage() != null)
+            && (r.getDiagnosticMessage().length() > 0))
+        {
+          println(LocalizableMessage.raw(r.getDiagnosticMessage()));
+        }
+        if (r.getMatchedDN() != null && r.getMatchedDN().length() > 0)
+        {
+          println(ERR_TOOL_MATCHED_DN.get(r.getMatchedDN()));
+        }
+      }
+      else
+      {
+        final LocalizableMessage msg = INFO_OPERATION_SUCCESSFUL.get(
+            operationType, name);
+        println(msg);
+        if ((r.getDiagnosticMessage() != null)
+            && (r.getDiagnosticMessage().length() > 0))
+        {
+          println(LocalizableMessage.raw(r.getDiagnosticMessage()));
+        }
+        if (r.getReferralURIs() != null)
+        {
+          for (final String uri : r.getReferralURIs())
+          {
+            println(LocalizableMessage.raw(uri));
+          }
+        }
+      }
+
+      try
+      {
+        final PreReadResponseControl control = r.getControl(
+            PreReadResponseControl.DECODER, new DecodeOptions());
+        if (control != null)
+        {
+          println(INFO_LDAPMODIFY_PREREAD_ENTRY.get());
+          writer.writeEntry(control.getEntry());
+        }
+      }
+      catch (final DecodeException de)
+      {
+        println(ERR_DECODE_CONTROL_FAILURE.get(de.getLocalizedMessage()));
+      }
+      catch (final IOException ioe)
+      {
+        throw new RuntimeException(ioe);
+      }
+
+      try
+      {
+        final PostReadResponseControl control = r.getControl(
+            PostReadResponseControl.DECODER, new DecodeOptions());
+        if (control != null)
+        {
+          println(INFO_LDAPMODIFY_POSTREAD_ENTRY.get());
+          writer.writeEntry(control.getEntry());
+        }
+      }
+      catch (final DecodeException de)
+      {
+        println(ERR_DECODE_CONTROL_FAILURE.get(de.getLocalizedMessage()));
+      }
+      catch (final IOException ioe)
+      {
+        throw new RuntimeException(ioe);
+      }
+
+      // TODO: CSN control
+    }
+  }
+
+
+
+  /**
+   * The main method for LDAPModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = mainModify(args, System.in, System.out, System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the LDAPModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return The error code.
+   */
+
+  static int mainModify(final String[] args)
+  {
+    return mainModify(args, System.in, System.out, System.err);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the LDAPModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program. specified,
+   *          the number of matching entries should be returned or not.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+  static int mainModify(final String[] args, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+  {
+    return new LDAPModify(inStream, outStream, errStream).run(args);
+  }
+
+
+
+  private Connection connection;
+
+  private EntryWriter writer;
+
+  private Collection<Control> controls;
+
+  private BooleanArgument verbose;
+
+
+
+  private LDAPModify(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription = INFO_LDAPMODIFY_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(LDAPModify.class
+        .getName(), toolDescription, false);
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+
+    BooleanArgument continueOnError;
+    // TODO: Remove this due to new LDIF reader api?
+    BooleanArgument defaultAdd;
+    BooleanArgument noop;
+    BooleanArgument showUsage;
+    IntegerArgument version;
+    StringArgument assertionFilter;
+    StringArgument controlStr;
+    StringArgument encodingStr;
+    StringArgument filename;
+    StringArgument postReadAttributes;
+    StringArgument preReadAttributes;
+    StringArgument proxyAuthzID;
+    StringArgument propertiesFileArgument;
+    BooleanArgument noPropertiesFileArgument;
+
+    try
+    {
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
+      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
+          OPTION_LONG_PROP_FILE_PATH, false, false, true,
+          INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      defaultAdd = new BooleanArgument("defaultAdd", 'a', "defaultAdd",
+          INFO_MODIFY_DESCRIPTION_DEFAULT_ADD.get());
+      argParser.addArgument(defaultAdd);
+
+      filename = new StringArgument("filename", OPTION_SHORT_FILENAME,
+          OPTION_LONG_FILENAME, false, false, true,
+          INFO_FILE_PLACEHOLDER.get(), null, null,
+          INFO_LDAPMODIFY_DESCRIPTION_FILENAME.get());
+      filename.setPropertyName(OPTION_LONG_FILENAME);
+      argParser.addArgument(filename);
+
+      proxyAuthzID = new StringArgument("proxy_authzid",
+          OPTION_SHORT_PROXYAUTHID, OPTION_LONG_PROXYAUTHID, false, false,
+          true, INFO_PROXYAUTHID_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROXY_AUTHZID.get());
+      proxyAuthzID.setPropertyName(OPTION_LONG_PROXYAUTHID);
+      argParser.addArgument(proxyAuthzID);
+
+      assertionFilter = new StringArgument("assertionfilter", null,
+          OPTION_LONG_ASSERTION_FILE, false, false, true,
+          INFO_ASSERTION_FILTER_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_ASSERTION_FILTER.get());
+      assertionFilter.setPropertyName(OPTION_LONG_ASSERTION_FILE);
+      argParser.addArgument(assertionFilter);
+
+      preReadAttributes = new StringArgument("prereadattrs", null,
+          "preReadAttributes", false, false, true,
+          INFO_ATTRIBUTE_LIST_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PREREAD_ATTRS.get());
+      preReadAttributes.setPropertyName("preReadAttributes");
+      argParser.addArgument(preReadAttributes);
+
+      postReadAttributes = new StringArgument("postreadattrs", null,
+          "postReadAttributes", false, false, true,
+          INFO_ATTRIBUTE_LIST_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_POSTREAD_ATTRS.get());
+      postReadAttributes.setPropertyName("postReadAttributes");
+      argParser.addArgument(postReadAttributes);
+
+      controlStr = new StringArgument("control", 'J', "control", false, true,
+          true, INFO_LDAP_CONTROL_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_CONTROLS.get());
+      controlStr.setPropertyName("control");
+      argParser.addArgument(controlStr);
+
+      version = new IntegerArgument("version", OPTION_SHORT_PROTOCOL_VERSION,
+          OPTION_LONG_PROTOCOL_VERSION, false, false, true,
+          INFO_PROTOCOL_VERSION_PLACEHOLDER.get(), 3, null,
+          INFO_DESCRIPTION_VERSION.get());
+      version.setPropertyName(OPTION_LONG_PROTOCOL_VERSION);
+      argParser.addArgument(version);
+
+      encodingStr = new StringArgument("encoding", 'i', "encoding", false,
+          false, true, INFO_ENCODING_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_ENCODING.get());
+      encodingStr.setPropertyName("encoding");
+      argParser.addArgument(encodingStr);
+
+      continueOnError = new BooleanArgument("continueOnError", 'c',
+          "continueOnError", INFO_DESCRIPTION_CONTINUE_ON_ERROR.get());
+      continueOnError.setPropertyName("continueOnError");
+      argParser.addArgument(continueOnError);
+
+      noop = new BooleanArgument("no-op", OPTION_SHORT_DRYRUN,
+          OPTION_LONG_DRYRUN, INFO_DESCRIPTION_NOOP.get());
+      noop.setPropertyName(OPTION_LONG_DRYRUN);
+      argParser.addArgument(noop);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    try
+    {
+      final int versionNumber = version.getIntValue();
+      if (versionNumber != 2 && versionNumber != 3)
+      {
+        println(ERR_DESCRIPTION_INVALID_VERSION.get(String
+            .valueOf(versionNumber)));
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      println(ERR_DESCRIPTION_INVALID_VERSION.get(String.valueOf(version
+          .getValue())));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // modifyOptions.setShowOperations(noop.isPresent());
+    // modifyOptions.setVerbose(verbose.isPresent());
+    // modifyOptions.setContinueOnError(continueOnError.isPresent());
+    // modifyOptions.setEncoding(encodingStr.getValue());
+    // modifyOptions.setDefaultAdd(defaultAdd.isPresent());
+
+    controls = new LinkedList<Control>();
+    if (controlStr.isPresent())
+    {
+      for (final String ctrlString : controlStr.getValues())
+      {
+        try
+        {
+          final Control ctrl = Utils.getControl(ctrlString);
+          controls.add(ctrl);
+        }
+        catch (final DecodeException de)
+        {
+          final LocalizableMessage message = ERR_TOOL_INVALID_CONTROL_STRING
+              .get(ctrlString);
+          println(message);
+          ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+    }
+
+    if (proxyAuthzID.isPresent())
+    {
+      final Control proxyControl = ProxiedAuthV2RequestControl
+          .newControl(proxyAuthzID.getValue());
+      controls.add(proxyControl);
+    }
+
+    if (assertionFilter.isPresent())
+    {
+      final String filterString = assertionFilter.getValue();
+      Filter filter;
+      try
+      {
+        filter = Filter.valueOf(filterString);
+
+        // FIXME -- Change this to the correct OID when the official one
+        // is assigned.
+        final Control assertionControl = AssertionRequestControl.newControl(
+            true, filter);
+        controls.add(assertionControl);
+      }
+      catch (final LocalizedIllegalArgumentException le)
+      {
+        final LocalizableMessage message = ERR_LDAP_ASSERTION_INVALID_FILTER
+            .get(le.getMessage());
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+
+    if (preReadAttributes.isPresent())
+    {
+      final String valueStr = preReadAttributes.getValue();
+      final StringTokenizer tokenizer = new StringTokenizer(valueStr, ", ");
+      final List<String> attributes = new LinkedList<String>();
+      while (tokenizer.hasMoreTokens())
+      {
+        attributes.add(tokenizer.nextToken());
+      }
+      final PreReadRequestControl control = PreReadRequestControl.newControl(
+          true, attributes);
+      controls.add(control);
+    }
+
+    if (postReadAttributes.isPresent())
+    {
+      final String valueStr = postReadAttributes.getValue();
+      final StringTokenizer tokenizer = new StringTokenizer(valueStr, ", ");
+      final List<String> attributes = new LinkedList<String>();
+      while (tokenizer.hasMoreTokens())
+      {
+        attributes.add(tokenizer.nextToken());
+      }
+      final PostReadRequestControl control = PostReadRequestControl.newControl(
+          true, attributes);
+      controls.add(control);
+    }
+
+    if (!noop.isPresent())
+    {
+      try
+      {
+        connection = connectionFactory.getConnection();
+      }
+      catch (final ErrorResultException ere)
+      {
+        return Utils.printErrorMessage(this, ere);
+      }
+      catch (final InterruptedException e)
+      {
+        // This shouldn't happen because there are no other threads to
+        // interrupt this one.
+        println(LocalizableMessage.raw(e.getLocalizedMessage()));
+        return ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue();
+      }
+    }
+
+    Utils.printPasswordPolicyResults(this, connection);
+
+    writer = new LDIFEntryWriter(getOutputStream());
+    final VisitorImpl visitor = new VisitorImpl();
+    try
+    {
+      ChangeRecordReader reader;
+      if (filename.isPresent())
+      {
+        try
+        {
+          reader = new LDIFChangeRecordReader(new FileInputStream(filename
+              .getValue()));
+        }
+        catch (final Exception e)
+        {
+          final LocalizableMessage message = ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ
+              .get(filename.getValue(), e.getLocalizedMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+      else
+      {
+        reader = new LDIFChangeRecordReader(getInputStream());
+      }
+
+      try
+      {
+        while (reader.hasNext())
+        {
+          final ChangeRecord cr = reader.readChangeRecord();
+          final int result = cr.accept(visitor, null);
+          if (result != 0 && !continueOnError.isPresent())
+          {
+            return result;
+          }
+        }
+      }
+      catch (final IOException ioe)
+      {
+        final LocalizableMessage message = ERR_LDIF_FILE_READ_ERROR.get(
+            filename.getValue(), ioe.getLocalizedMessage());
+        println(message);
+        return ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
+      }
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+    }
+
+    return ResultCode.SUCCESS.intValue();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPPasswordModify.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPPasswordModify.java
new file mode 100644
index 0000000..2e27060
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPPasswordModify.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.requests.PasswordModifyExtendedRequest;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.responses.PasswordModifyExtendedResult;
+import org.opends.sdk.responses.Responses;
+
+
+
+/**
+ * A tool that can be used to issue LDAP password modify extended requests to
+ * the Directory Server. It exposes the three primary options available for this
+ * operation, which are:
+ * <UL>
+ * <LI>The user identity whose password should be changed.</LI>
+ * <LI>The current password for the user.</LI>
+ * <LI>The new password for the user.
+ * </UL>
+ * All of these are optional components that may be included or omitted from the
+ * request.
+ */
+public final class LDAPPasswordModify extends ConsoleApplication
+{
+  /**
+   * Parses the command-line arguments, establishes a connection to the
+   * Directory Server, sends the password modify request, and reads the
+   * response.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+  public static void main(final String[] args)
+  {
+    final int retCode = mainPasswordModify(args, System.in, System.out,
+        System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * Parses the command-line arguments, establishes a connection to the
+   * Directory Server, sends the password modify request, and reads the
+   * response.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return An integer value of zero if everything completed successfully, or a
+   *         nonzero value if an error occurred.
+   */
+  static int mainPasswordModify(final String[] args)
+  {
+    return mainPasswordModify(args, System.in, System.out, System.err);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the LDAPPasswordModify tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program. specified,
+   *          the number of matching entries should be returned or not.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+  static int mainPasswordModify(final String[] args,
+      final InputStream inStream, final OutputStream outStream,
+      final OutputStream errStream)
+  {
+    return new LDAPPasswordModify(inStream, outStream, errStream).run(args);
+  }
+
+
+
+  private BooleanArgument verbose;
+
+
+
+  private LDAPPasswordModify(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription = INFO_LDAPPWMOD_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(
+        LDAPPasswordModify.class.getName(), toolDescription, false);
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+
+    FileBasedArgument currentPWFile;
+    FileBasedArgument newPWFile;
+    BooleanArgument showUsage;
+    IntegerArgument version;
+    StringArgument currentPW;
+    StringArgument controlStr;
+    StringArgument newPW;
+    StringArgument proxyAuthzID;
+    StringArgument propertiesFileArgument;
+    BooleanArgument noPropertiesFileArgument;
+
+    try
+    {
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
+      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
+          OPTION_LONG_PROP_FILE_PATH, false, false, true,
+          INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      newPW = new StringArgument("newpw", 'n', "newPassword", false, false,
+          true, INFO_NEW_PASSWORD_PLACEHOLDER.get(), null, null,
+          INFO_LDAPPWMOD_DESCRIPTION_NEWPW.get());
+      newPW.setPropertyName("newPassword");
+      argParser.addArgument(newPW);
+
+      newPWFile = new FileBasedArgument("newpwfile", 'F', "newPasswordFile",
+          false, false, INFO_FILE_PLACEHOLDER.get(), null, null,
+          INFO_LDAPPWMOD_DESCRIPTION_NEWPWFILE.get());
+      newPWFile.setPropertyName("newPasswordFile");
+      argParser.addArgument(newPWFile);
+
+      currentPW = new StringArgument("currentpw", 'c', "currentPassword",
+          false, false, true, INFO_CURRENT_PASSWORD_PLACEHOLDER.get(), null,
+          null, INFO_LDAPPWMOD_DESCRIPTION_CURRENTPW.get());
+      currentPW.setPropertyName("currentPassword");
+      argParser.addArgument(currentPW);
+
+      currentPWFile = new FileBasedArgument("currentpwfile", 'C',
+          "currentPasswordFile", false, false, INFO_FILE_PLACEHOLDER.get(),
+          null, null, INFO_LDAPPWMOD_DESCRIPTION_CURRENTPWFILE.get());
+      currentPWFile.setPropertyName("currentPasswordFile");
+      argParser.addArgument(currentPWFile);
+
+      proxyAuthzID = new StringArgument("authzid", 'a', "authzID", false,
+          false, true, INFO_PROXYAUTHID_PLACEHOLDER.get(), null, null,
+          INFO_LDAPPWMOD_DESCRIPTION_AUTHZID.get());
+      proxyAuthzID.setPropertyName("authzID");
+      argParser.addArgument(proxyAuthzID);
+
+      controlStr = new StringArgument("control", 'J', "control", false, true,
+          true, INFO_LDAP_CONTROL_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_CONTROLS.get());
+      controlStr.setPropertyName("control");
+      argParser.addArgument(controlStr);
+
+      version = new IntegerArgument("version", OPTION_SHORT_PROTOCOL_VERSION,
+          OPTION_LONG_PROTOCOL_VERSION, false, false, true,
+          INFO_PROTOCOL_VERSION_PLACEHOLDER.get(), 3, null,
+          INFO_DESCRIPTION_VERSION.get());
+      version.setPropertyName(OPTION_LONG_PROTOCOL_VERSION);
+      argParser.addArgument(version);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    final PasswordModifyExtendedRequest request = Requests
+        .newPasswordModifyExtendedRequest();
+    try
+    {
+      final int versionNumber = version.getIntValue();
+      if (versionNumber != 2 && versionNumber != 3)
+      {
+        println(ERR_DESCRIPTION_INVALID_VERSION.get(String
+            .valueOf(versionNumber)));
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      println(ERR_DESCRIPTION_INVALID_VERSION.get(String.valueOf(version
+          .getValue())));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    if (controlStr.isPresent())
+    {
+      for (final String ctrlString : controlStr.getValues())
+      {
+        try
+        {
+          final Control ctrl = Utils.getControl(ctrlString);
+          request.addControl(ctrl);
+        }
+        catch (final DecodeException de)
+        {
+          final LocalizableMessage message = ERR_TOOL_INVALID_CONTROL_STRING
+              .get(ctrlString);
+          println(message);
+          ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+    }
+
+    if (newPW.isPresent() && newPWFile.isPresent())
+    {
+      final LocalizableMessage message = ERR_LDAPPWMOD_CONFLICTING_ARGS.get(
+          newPW.getLongIdentifier(), newPWFile.getLongIdentifier());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    if (currentPW.isPresent() && currentPWFile.isPresent())
+    {
+      final LocalizableMessage message = ERR_LDAPPWMOD_CONFLICTING_ARGS.get(
+          currentPW.getLongIdentifier(), currentPWFile.getLongIdentifier());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    Connection connection;
+    try
+    {
+      connection = connectionFactory.getConnection();
+    }
+    catch (final ErrorResultException ere)
+    {
+      return Utils.printErrorMessage(this, ere);
+    }
+    catch (final InterruptedException e)
+    {
+      // This shouldn't happen because there are no other threads to
+      // interrupt this one.
+      println(LocalizableMessage.raw(e.getLocalizedMessage()));
+      return ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue();
+    }
+
+    if (proxyAuthzID.isPresent())
+    {
+      request.setUserIdentity(proxyAuthzID.getValue());
+    }
+
+    if (currentPW.isPresent())
+    {
+      request.setOldPassword(ByteString.valueOf(currentPW.getValue()));
+    }
+    else if (currentPWFile.isPresent())
+    {
+      request.setOldPassword(ByteString.valueOf(currentPWFile.getValue()));
+    }
+
+    if (newPW.isPresent())
+    {
+      request.setNewPassword(ByteString.valueOf(newPW.getValue()));
+    }
+    else if (newPWFile.isPresent())
+    {
+      request.setNewPassword(ByteString.valueOf(newPWFile.getValue()));
+    }
+
+    PasswordModifyExtendedResult result;
+    try
+    {
+      try
+      {
+        result = connection.extendedRequest(request);
+      }
+      catch (final InterruptedException e)
+      {
+        // This shouldn't happen because there are no other threads to
+        // interrupt this one.
+        result = Responses.newPasswordModifyExtendedResult(
+            ResultCode.CLIENT_SIDE_USER_CANCELLED).setCause(e)
+            .setDiagnosticMessage(e.getLocalizedMessage());
+        throw ErrorResultException.wrap(result);
+      }
+    }
+    catch (final ErrorResultException e)
+    {
+      LocalizableMessage message = ERR_LDAPPWMOD_FAILED
+          .get(e.getResult().getResultCode().intValue(), e.getResult()
+              .getResultCode().toString());
+      println(message);
+
+      final String errorMessage = e.getResult().getDiagnosticMessage();
+      if ((errorMessage != null) && (errorMessage.length() > 0))
+      {
+        message = ERR_LDAPPWMOD_FAILURE_ERROR_MESSAGE.get(errorMessage);
+        println(message);
+      }
+
+      final String matchedDN = e.getResult().getMatchedDN();
+      if (matchedDN != null && matchedDN.length() > 0)
+      {
+        message = ERR_LDAPPWMOD_FAILURE_MATCHED_DN.get(matchedDN);
+        println(message);
+      }
+      return e.getResult().getResultCode().intValue();
+    }
+
+    LocalizableMessage message = INFO_LDAPPWMOD_SUCCESSFUL.get();
+    println(message);
+
+    final String additionalInfo = result.getDiagnosticMessage();
+    if ((additionalInfo != null) && (additionalInfo.length() > 0))
+    {
+
+      message = INFO_LDAPPWMOD_ADDITIONAL_INFO.get(additionalInfo);
+      println(message);
+    }
+
+    if (result.getGeneratedPassword() != null)
+    {
+      message = INFO_LDAPPWMOD_GENERATED_PASSWORD.get(result
+          .getGeneratedPassword().toString());
+      println(message);
+    }
+
+    return 0;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPSearch.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPSearch.java
new file mode 100644
index 0000000..eb00b38
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/LDAPSearch.java
@@ -0,0 +1,1298 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+import java.io.*;
+import java.util.*;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.*;
+import org.opends.sdk.ldif.EntryWriter;
+import org.opends.sdk.ldif.LDIFEntryWriter;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.responses.SearchResultReference;
+
+import com.sun.opends.sdk.controls.AccountUsabilityResponseControl;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * A tool that can be used to issue Search requests to the Directory Server.
+ */
+public final class LDAPSearch extends ConsoleApplication
+{
+  private class LDAPSearchResultHandler implements SearchResultHandler
+  {
+    private int entryCount = 0;
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean handleEntry(final SearchResultEntry entry)
+    {
+      entryCount++;
+
+      try
+      {
+        final EntryChangeNotificationResponseControl control = entry
+            .getControl(EntryChangeNotificationResponseControl.DECODER,
+                new DecodeOptions());
+        if (control != null)
+        {
+          println(INFO_LDAPSEARCH_PSEARCH_CHANGE_TYPE.get(control
+              .getChangeType().toString()));
+          final DN previousDN = control.getPreviousName();
+          if (previousDN != null)
+          {
+            println(INFO_LDAPSEARCH_PSEARCH_PREVIOUS_DN.get(previousDN
+                .toString()));
+          }
+        }
+      }
+      catch (final DecodeException de)
+      {
+        println(ERR_DECODE_CONTROL_FAILURE.get(de.getLocalizedMessage()));
+      }
+
+      try
+      {
+        final AccountUsabilityResponseControl control = entry.getControl(
+            AccountUsabilityResponseControl.DECODER, new DecodeOptions());
+
+        if (control != null)
+        {
+          println(INFO_LDAPSEARCH_ACCTUSABLE_HEADER.get());
+          if (control.isUsable())
+          {
+
+            println(INFO_LDAPSEARCH_ACCTUSABLE_IS_USABLE.get());
+            if (control.getSecondsBeforeExpiration() > 0)
+            {
+              final int timeToExp = control.getSecondsBeforeExpiration();
+              final LocalizableMessage timeToExpStr = Utils
+                  .secondsToTimeString(timeToExp);
+
+              println(INFO_LDAPSEARCH_ACCTUSABLE_TIME_UNTIL_EXPIRATION
+                  .get(timeToExpStr));
+            }
+          }
+          else
+          {
+
+            println(INFO_LDAPSEARCH_ACCTUSABLE_NOT_USABLE.get());
+            if (control.isInactive())
+            {
+              println(INFO_LDAPSEARCH_ACCTUSABLE_ACCT_INACTIVE.get());
+            }
+            if (control.isReset())
+            {
+              println(INFO_LDAPSEARCH_ACCTUSABLE_PW_RESET.get());
+            }
+            if (control.isExpired())
+            {
+              println(INFO_LDAPSEARCH_ACCTUSABLE_PW_EXPIRED.get());
+
+              if (control.getRemainingGraceLogins() > 0)
+              {
+                println(INFO_LDAPSEARCH_ACCTUSABLE_REMAINING_GRACE.get(control
+                    .getRemainingGraceLogins()));
+              }
+            }
+            if (control.isLocked())
+            {
+              println(INFO_LDAPSEARCH_ACCTUSABLE_LOCKED.get());
+              if (control.getSecondsBeforeUnlock() > 0)
+              {
+                final int timeToUnlock = control.getSecondsBeforeUnlock();
+                final LocalizableMessage timeToUnlockStr = Utils
+                    .secondsToTimeString(timeToUnlock);
+
+                println(INFO_LDAPSEARCH_ACCTUSABLE_TIME_UNTIL_UNLOCK
+                    .get(timeToUnlockStr));
+              }
+            }
+          }
+        }
+      }
+      catch (final DecodeException de)
+      {
+        println(ERR_DECODE_CONTROL_FAILURE.get(de.getLocalizedMessage()));
+      }
+
+      try
+      {
+        ldifWriter.writeEntry(entry);
+        ldifWriter.flush();
+      }
+      catch (final IOException ioe)
+      {
+        // Something is seriously wrong
+        throw new RuntimeException(ioe);
+      }
+      return true;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean handleReference(final SearchResultReference reference)
+    {
+      println(LocalizableMessage.raw(reference.toString()));
+      return true;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleErrorResult(ErrorResultException error)
+    {
+      // Ignore.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleResult(Result result)
+    {
+      // Ignore.
+    }
+  }
+
+
+
+  /**
+   * The main method for LDAPSearch tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = mainSearch(args, false, System.in, System.out,
+        System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the ldapsearch tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return The error code.
+   */
+
+  static int mainSearch(final String[] args)
+  {
+    return mainSearch(args, true, System.in, System.out, System.err);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the ldapsearch tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @param returnMatchingEntries
+   *          whether when the option --countEntries is specified, the number of
+   *          matching entries should be returned or not.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+
+  static int mainSearch(final String[] args,
+      final boolean returnMatchingEntries, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+  {
+    return new LDAPSearch(inStream, outStream, errStream).run(args,
+        returnMatchingEntries);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the ldapsearch tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+  static int mainSearch(final String[] args, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+  {
+    return mainSearch(args, true, inStream, outStream, errStream);
+  }
+
+
+
+  private BooleanArgument verbose;
+
+  private EntryWriter ldifWriter;
+
+
+
+  private LDAPSearch(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int run(final String[] args, final boolean returnMatchingEntries)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription = INFO_LDAPSEARCH_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(LDAPSearch.class
+        .getName(), toolDescription, false, true, 0, 0,
+        "[filter] [attributes ...]");
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+
+    BooleanArgument countEntries;
+    BooleanArgument dontWrap;
+    BooleanArgument noop;
+    BooleanArgument typesOnly;
+    IntegerArgument simplePageSize;
+    IntegerArgument timeLimit;
+    IntegerArgument version;
+    StringArgument baseDN;
+    StringArgument controlStr;
+    MultiChoiceArgument<DereferenceAliasesPolicy> dereferencePolicy;
+    StringArgument filename;
+    StringArgument matchedValuesFilter;
+    StringArgument pSearchInfo;
+    MultiChoiceArgument<SearchScope> searchScope;
+    StringArgument vlvDescriptor;
+    StringArgument effectiveRightsUser;
+    StringArgument effectiveRightsAttrs;
+    StringArgument sortOrder;
+    StringArgument proxyAuthzID;
+    StringArgument assertionFilter;
+    IntegerArgument sizeLimit;
+    try
+    {
+      connectionFactoryProvider =
+          new ConnectionFactoryProvider(argParser, this);
+      final StringArgument propertiesFileArgument = new StringArgument(
+          "propertiesFilePath", null, OPTION_LONG_PROP_FILE_PATH, false, false,
+          true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      final BooleanArgument noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      baseDN = new StringArgument("baseDN", OPTION_SHORT_BASEDN,
+          OPTION_LONG_BASEDN, true, false, true, INFO_BASEDN_PLACEHOLDER.get(),
+          null, null, INFO_SEARCH_DESCRIPTION_BASEDN.get());
+      baseDN.setPropertyName(OPTION_LONG_BASEDN);
+      argParser.addArgument(baseDN);
+
+      searchScope = new MultiChoiceArgument<SearchScope>("searchScope", 's',
+          "searchScope", false, true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(),
+          SearchScope.values(), false, INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE
+              .get());
+      searchScope.setPropertyName("searchScope");
+      searchScope.setDefaultValue(SearchScope.WHOLE_SUBTREE);
+      argParser.addArgument(searchScope);
+
+      filename = new StringArgument("filename", OPTION_SHORT_FILENAME,
+          OPTION_LONG_FILENAME, false, false, true,
+          INFO_FILE_PLACEHOLDER.get(), null, null,
+          INFO_SEARCH_DESCRIPTION_FILENAME.get());
+      searchScope.setPropertyName(OPTION_LONG_FILENAME);
+      argParser.addArgument(filename);
+
+      proxyAuthzID = new StringArgument("proxy_authzid",
+          OPTION_SHORT_PROXYAUTHID, OPTION_LONG_PROXYAUTHID, false, false,
+          true, INFO_PROXYAUTHID_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROXY_AUTHZID.get());
+      proxyAuthzID.setPropertyName(OPTION_LONG_PROXYAUTHID);
+      argParser.addArgument(proxyAuthzID);
+
+      pSearchInfo = new StringArgument("psearchinfo", 'C', "persistentSearch",
+          false, false, true, INFO_PSEARCH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PSEARCH_INFO.get());
+      pSearchInfo.setPropertyName("persistentSearch");
+      argParser.addArgument(pSearchInfo);
+
+      simplePageSize = new IntegerArgument("simplepagesize", null,
+          "simplePageSize", false, false, true, INFO_NUM_ENTRIES_PLACEHOLDER
+              .get(), 1000, null, true, 1, false, 0,
+          INFO_DESCRIPTION_SIMPLE_PAGE_SIZE.get());
+      simplePageSize.setPropertyName("simplePageSize");
+      argParser.addArgument(simplePageSize);
+
+      assertionFilter = new StringArgument("assertionfilter", null,
+          OPTION_LONG_ASSERTION_FILE, false, false, true,
+          INFO_ASSERTION_FILTER_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_ASSERTION_FILTER.get());
+      assertionFilter.setPropertyName(OPTION_LONG_ASSERTION_FILE);
+      argParser.addArgument(assertionFilter);
+
+      matchedValuesFilter = new StringArgument("matchedvalues", null,
+          "matchedValuesFilter", false, true, true, INFO_FILTER_PLACEHOLDER
+              .get(), null, null, INFO_DESCRIPTION_MATCHED_VALUES_FILTER.get());
+      matchedValuesFilter.setPropertyName("matchedValuesFilter");
+      argParser.addArgument(matchedValuesFilter);
+
+      sortOrder = new StringArgument("sortorder", 'S', "sortOrder", false,
+          false, true, INFO_SORT_ORDER_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_SORT_ORDER.get());
+      sortOrder.setPropertyName("sortOrder");
+      argParser.addArgument(sortOrder);
+
+      vlvDescriptor = new StringArgument("vlvdescriptor", 'G',
+          "virtualListView", false, false, true, INFO_VLV_PLACEHOLDER.get(),
+          null, null, INFO_DESCRIPTION_VLV.get());
+      vlvDescriptor.setPropertyName("virtualListView");
+      argParser.addArgument(vlvDescriptor);
+
+      controlStr = new StringArgument("control", 'J', "control", false, true,
+          true, INFO_LDAP_CONTROL_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_CONTROLS.get());
+      controlStr.setPropertyName("control");
+      argParser.addArgument(controlStr);
+
+      effectiveRightsUser = new StringArgument("effectiveRightsUser",
+          OPTION_SHORT_EFFECTIVERIGHTSUSER, OPTION_LONG_EFFECTIVERIGHTSUSER,
+          false, false, true, INFO_PROXYAUTHID_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_EFFECTIVERIGHTS_USER.get());
+      effectiveRightsUser.setPropertyName(OPTION_LONG_EFFECTIVERIGHTSUSER);
+      argParser.addArgument(effectiveRightsUser);
+
+      effectiveRightsAttrs = new StringArgument("effectiveRightsAttrs",
+          OPTION_SHORT_EFFECTIVERIGHTSATTR, OPTION_LONG_EFFECTIVERIGHTSATTR,
+          false, true, true, INFO_ATTRIBUTE_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_EFFECTIVERIGHTS_ATTR.get());
+      effectiveRightsAttrs.setPropertyName(OPTION_LONG_EFFECTIVERIGHTSATTR);
+      argParser.addArgument(effectiveRightsAttrs);
+
+      version = new IntegerArgument("version", OPTION_SHORT_PROTOCOL_VERSION,
+          OPTION_LONG_PROTOCOL_VERSION, false, false, true,
+          INFO_PROTOCOL_VERSION_PLACEHOLDER.get(), 3, null,
+          INFO_DESCRIPTION_VERSION.get());
+      version.setPropertyName(OPTION_LONG_PROTOCOL_VERSION);
+      argParser.addArgument(version);
+
+      final StringArgument encodingStr = new StringArgument("encoding", 'i',
+          "encoding", false, false, true, INFO_ENCODING_PLACEHOLDER.get(),
+          null, null, INFO_DESCRIPTION_ENCODING.get());
+      encodingStr.setPropertyName("encoding");
+      argParser.addArgument(encodingStr);
+
+      dereferencePolicy = new MultiChoiceArgument<DereferenceAliasesPolicy>(
+          "derefpolicy", 'a', "dereferencePolicy", false, true,
+          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(), DereferenceAliasesPolicy
+              .values(), false, INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY
+              .get());
+      dereferencePolicy.setPropertyName("dereferencePolicy");
+      dereferencePolicy.setDefaultValue(DereferenceAliasesPolicy.NEVER);
+      argParser.addArgument(dereferencePolicy);
+
+      typesOnly = new BooleanArgument("typesOnly", 'A', "typesOnly",
+          INFO_DESCRIPTION_TYPES_ONLY.get());
+      typesOnly.setPropertyName("typesOnly");
+      argParser.addArgument(typesOnly);
+
+      sizeLimit = new IntegerArgument("sizeLimit", 'z', "sizeLimit", false,
+          false, true, INFO_SIZE_LIMIT_PLACEHOLDER.get(), 0, null,
+          INFO_SEARCH_DESCRIPTION_SIZE_LIMIT.get());
+      sizeLimit.setPropertyName("sizeLimit");
+      argParser.addArgument(sizeLimit);
+
+      timeLimit = new IntegerArgument("timeLimit", 'l', "timeLimit", false,
+          false, true, INFO_TIME_LIMIT_PLACEHOLDER.get(), 0, null,
+          INFO_SEARCH_DESCRIPTION_TIME_LIMIT.get());
+      timeLimit.setPropertyName("timeLimit");
+      argParser.addArgument(timeLimit);
+
+      dontWrap = new BooleanArgument("dontwrap", 't', "dontWrap",
+          INFO_DESCRIPTION_DONT_WRAP.get());
+      dontWrap.setPropertyName("dontWrap");
+      argParser.addArgument(dontWrap);
+
+      countEntries = new BooleanArgument("countentries", null, "countEntries",
+          INFO_DESCRIPTION_COUNT_ENTRIES.get());
+      countEntries.setPropertyName("countEntries");
+      argParser.addArgument(countEntries);
+
+      final BooleanArgument continueOnError = new BooleanArgument(
+          "continueOnError", 'c', "continueOnError",
+          INFO_DESCRIPTION_CONTINUE_ON_ERROR.get());
+      continueOnError.setPropertyName("continueOnError");
+      argParser.addArgument(continueOnError);
+
+      noop = new BooleanArgument("noop", OPTION_SHORT_DRYRUN,
+          OPTION_LONG_DRYRUN, INFO_DESCRIPTION_NOOP.get());
+      noop.setPropertyName(OPTION_LONG_DRYRUN);
+      argParser.addArgument(noop);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+
+      final BooleanArgument showUsage = new BooleanArgument("showUsage",
+          OPTION_SHORT_HELP, OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+
+      connectionFactory =
+          connectionFactoryProvider.getAuthenticatedConnectionFactory();
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    final List<Filter> filters = new LinkedList<Filter>();
+    final List<String> attributes = new LinkedList<String>();
+    final ArrayList<String> filterAndAttributeStrings = argParser
+        .getTrailingArguments();
+    if (filterAndAttributeStrings.size() > 0)
+    {
+      // the list of trailing arguments should be structured as follow:
+      // - If a filter file is present, trailing arguments are
+      // considered as attributes
+      // - If filter file is not present, the first trailing argument is
+      // considered the filter, the other as attributes.
+      if (!filename.isPresent())
+      {
+        final String filterString = filterAndAttributeStrings.remove(0);
+
+        try
+        {
+          filters.add(Filter.valueOf(filterString));
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          println(e.getMessageObject());
+          return ResultCode.CLIENT_SIDE_FILTER_ERROR.intValue();
+        }
+      }
+      // The rest are attributes
+      for (final String s : filterAndAttributeStrings)
+      {
+        attributes.add(s);
+      }
+    }
+
+    if (filename.isPresent())
+    {
+      // Read the filter strings.
+      BufferedReader in = null;
+      try
+      {
+        in = new BufferedReader(new FileReader(filename.getValue()));
+        String line = null;
+
+        while ((line = in.readLine()) != null)
+        {
+          if (line.trim().equals(""))
+          {
+            // ignore empty lines.
+            continue;
+          }
+          final Filter ldapFilter = Filter.valueOf(line);
+          filters.add(ldapFilter);
+        }
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        println(e.getMessageObject());
+        return ResultCode.CLIENT_SIDE_FILTER_ERROR.intValue();
+      }
+      catch (final IOException e)
+      {
+        println(LocalizableMessage.raw(e.toString()));
+        return ResultCode.CLIENT_SIDE_FILTER_ERROR.intValue();
+      }
+      finally
+      {
+        if (in != null)
+        {
+          try
+          {
+            in.close();
+          }
+          catch (final IOException ioe)
+          {
+          }
+        }
+      }
+    }
+
+    if (filters.isEmpty())
+    {
+      println(ERR_SEARCH_NO_FILTERS.get());
+      println(argParser.getUsageMessage());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    SearchScope scope;
+    try
+    {
+      scope = searchScope.getTypedValue();
+    }
+    catch (final ArgumentException ex1)
+    {
+      println(ex1.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    SearchRequest search;
+    try
+    {
+      search = Requests.newSearchRequest(DN.valueOf(baseDN.getValue()), scope,
+          filters.get(0), attributes.toArray(new String[attributes.size()]));
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      println(e.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Read the LDAP version number.
+    try
+    {
+      final int versionNumber = version.getIntValue();
+      if (versionNumber != 2 && versionNumber != 3)
+      {
+        println(ERR_DESCRIPTION_INVALID_VERSION.get(String
+            .valueOf(versionNumber)));
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+    catch (final ArgumentException ae)
+    {
+      println(ERR_DESCRIPTION_INVALID_VERSION.get(String.valueOf(version
+          .getValue())));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    search.setTypesOnly(typesOnly.isPresent());
+    // searchOptions.setShowOperations(noop.isPresent());
+    // searchOptions.setVerbose(verbose.isPresent());
+    // searchOptions.setContinueOnError(continueOnError.isPresent());
+    // searchOptions.setEncoding(encodingStr.getValue());
+    // searchOptions.setCountMatchingEntries(countEntries.isPresent());
+    try
+    {
+      search.setTimeLimit(timeLimit.getIntValue());
+      search.setSizeLimit(sizeLimit.getIntValue());
+    }
+    catch (final ArgumentException ex1)
+    {
+      println(ex1.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+    try
+    {
+      search.setDereferenceAliasesPolicy(dereferencePolicy.getTypedValue());
+    }
+    catch (final ArgumentException ex1)
+    {
+      println(ex1.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    if (controlStr.isPresent())
+    {
+      for (final String ctrlString : controlStr.getValues())
+      {
+        try
+        {
+          final Control ctrl = Utils.getControl(ctrlString);
+          search.addControl(ctrl);
+        }
+        catch (final DecodeException de)
+        {
+          final LocalizableMessage message = ERR_TOOL_INVALID_CONTROL_STRING
+              .get(ctrlString);
+          println(message);
+          ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+    }
+
+    if (effectiveRightsUser.isPresent())
+    {
+      final String authzID = effectiveRightsUser.getValue();
+      if (!authzID.startsWith("dn:"))
+      {
+        final LocalizableMessage message = ERR_EFFECTIVERIGHTS_INVALID_AUTHZID
+            .get(authzID);
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+      final Control effectiveRightsControl = GetEffectiveRightsRequestControl
+          .newControl(false, authzID.substring(3), effectiveRightsAttrs
+              .getValues().toArray(
+                  new String[effectiveRightsAttrs.getValues().size()]));
+      search.addControl(effectiveRightsControl);
+    }
+
+    if (proxyAuthzID.isPresent())
+    {
+      final Control proxyControl = ProxiedAuthV2RequestControl
+          .newControl(proxyAuthzID.getValue());
+      search.addControl(proxyControl);
+    }
+
+    if (pSearchInfo.isPresent())
+    {
+      final String infoString = StaticUtils.toLowerCase(pSearchInfo.getValue()
+          .trim());
+      boolean changesOnly = true;
+      boolean returnECs = true;
+
+      final StringTokenizer tokenizer = new StringTokenizer(infoString, ":");
+
+      if (!tokenizer.hasMoreTokens())
+      {
+        final LocalizableMessage message = ERR_PSEARCH_MISSING_DESCRIPTOR.get();
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+      else
+      {
+        final String token = tokenizer.nextToken();
+        if (!token.equals("ps"))
+        {
+          final LocalizableMessage message = ERR_PSEARCH_DOESNT_START_WITH_PS
+              .get(String.valueOf(infoString));
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      final ArrayList<PersistentSearchChangeType> ct = new ArrayList<PersistentSearchChangeType>(
+          4);
+      if (tokenizer.hasMoreTokens())
+      {
+        final StringTokenizer st = new StringTokenizer(tokenizer.nextToken(),
+            ", ");
+        if (!st.hasMoreTokens())
+        {
+          ct.add(PersistentSearchChangeType.ADD);
+          ct.add(PersistentSearchChangeType.DELETE);
+          ct.add(PersistentSearchChangeType.MODIFY);
+          ct.add(PersistentSearchChangeType.MODIFY_DN);
+        }
+        else
+        {
+          do
+          {
+            final String token = st.nextToken();
+            if (token.equals("add"))
+            {
+              ct.add(PersistentSearchChangeType.ADD);
+            }
+            else if (token.equals("delete") || token.equals("del"))
+            {
+              ct.add(PersistentSearchChangeType.DELETE);
+            }
+            else if (token.equals("modify") || token.equals("mod"))
+            {
+              ct.add(PersistentSearchChangeType.MODIFY);
+            }
+            else if (token.equals("modifydn") || token.equals("moddn")
+                || token.equals("modrdn"))
+            {
+              ct.add(PersistentSearchChangeType.MODIFY_DN);
+            }
+            else if (token.equals("any") || token.equals("all"))
+            {
+              ct.add(PersistentSearchChangeType.ADD);
+              ct.add(PersistentSearchChangeType.DELETE);
+              ct.add(PersistentSearchChangeType.MODIFY);
+              ct.add(PersistentSearchChangeType.MODIFY_DN);
+            }
+            else
+            {
+              final LocalizableMessage message = ERR_PSEARCH_INVALID_CHANGE_TYPE
+                  .get(String.valueOf(token));
+              println(message);
+              return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+            }
+          }
+          while (st.hasMoreTokens());
+        }
+      }
+
+      if (tokenizer.hasMoreTokens())
+      {
+        final String token = tokenizer.nextToken();
+        if (token.equals("1") || token.equals("true") || token.equals("yes"))
+        {
+          changesOnly = true;
+        }
+        else if (token.equals("0") || token.equals("false")
+            || token.equals("no"))
+        {
+          changesOnly = false;
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_PSEARCH_INVALID_CHANGESONLY
+              .get(String.valueOf(token));
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      if (tokenizer.hasMoreTokens())
+      {
+        final String token = tokenizer.nextToken();
+        if (token.equals("1") || token.equals("true") || token.equals("yes"))
+        {
+          returnECs = true;
+        }
+        else if (token.equals("0") || token.equals("false")
+            || token.equals("no"))
+        {
+          returnECs = false;
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_PSEARCH_INVALID_RETURN_ECS
+              .get(String.valueOf(token));
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      final PersistentSearchRequestControl psearchControl = PersistentSearchRequestControl
+          .newControl(true, changesOnly, returnECs, ct
+              .toArray(new PersistentSearchChangeType[ct.size()]));
+      search.addControl(psearchControl);
+    }
+
+    if (assertionFilter.isPresent())
+    {
+      final String filterString = assertionFilter.getValue();
+      Filter filter;
+      try
+      {
+        filter = Filter.valueOf(filterString);
+
+        // FIXME -- Change this to the correct OID when the official one
+        // is assigned.
+        final Control assertionControl = AssertionRequestControl.newControl(
+            true, filter);
+        search.addControl(assertionControl);
+      }
+      catch (final LocalizedIllegalArgumentException le)
+      {
+        final LocalizableMessage message = ERR_LDAP_ASSERTION_INVALID_FILTER
+            .get(le.getMessage());
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+
+    if (matchedValuesFilter.isPresent())
+    {
+      final LinkedList<String> mvFilterStrings = matchedValuesFilter
+          .getValues();
+      final List<Filter> mvFilters = new ArrayList<Filter>();
+      for (final String s : mvFilterStrings)
+      {
+        try
+        {
+          final Filter f = Filter.valueOf(s);
+          mvFilters.add(f);
+        }
+        catch (final LocalizedIllegalArgumentException le)
+        {
+          final LocalizableMessage message = ERR_LDAP_MATCHEDVALUES_INVALID_FILTER
+              .get(le.getMessage());
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+
+      final MatchedValuesRequestControl mvc = MatchedValuesRequestControl
+          .newControl(true, mvFilters);
+      search.addControl(mvc);
+    }
+
+    if (sortOrder.isPresent())
+    {
+      try
+      {
+        search.addControl(ServerSideSortRequestControl.newControl(false,
+            sortOrder.getValue()));
+      }
+      catch (final LocalizedIllegalArgumentException le)
+      {
+        final LocalizableMessage message = ERR_LDAP_SORTCONTROL_INVALID_ORDER
+            .get(le.getMessageObject());
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+
+    if (vlvDescriptor.isPresent())
+    {
+      if (!sortOrder.isPresent())
+      {
+        final LocalizableMessage message = ERR_LDAPSEARCH_VLV_REQUIRES_SORT
+            .get(vlvDescriptor.getLongIdentifier(), sortOrder
+                .getLongIdentifier());
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+
+      final StringTokenizer tokenizer = new StringTokenizer(vlvDescriptor
+          .getValue(), ":");
+      final int numTokens = tokenizer.countTokens();
+      if (numTokens == 3)
+      {
+        try
+        {
+          final int beforeCount = Integer.parseInt(tokenizer.nextToken());
+          final int afterCount = Integer.parseInt(tokenizer.nextToken());
+          final ByteString assertionValue = ByteString.valueOf(tokenizer
+              .nextToken());
+          search.addControl(VirtualListViewRequestControl.newAssertionControl(
+              true, assertionValue, beforeCount, afterCount, null));
+        }
+        catch (final Exception e)
+        {
+          final LocalizableMessage message = ERR_LDAPSEARCH_VLV_INVALID_DESCRIPTOR
+              .get();
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+      else if (numTokens == 4)
+      {
+        try
+        {
+          final int beforeCount = Integer.parseInt(tokenizer.nextToken());
+          final int afterCount = Integer.parseInt(tokenizer.nextToken());
+          final int offset = Integer.parseInt(tokenizer.nextToken());
+          final int contentCount = Integer.parseInt(tokenizer.nextToken());
+          search.addControl(VirtualListViewRequestControl.newOffsetControl(
+              true, offset, contentCount, beforeCount, afterCount, null));
+        }
+        catch (final Exception e)
+        {
+          final LocalizableMessage message = ERR_LDAPSEARCH_VLV_INVALID_DESCRIPTOR
+              .get();
+          println(message);
+          return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_LDAPSEARCH_VLV_INVALID_DESCRIPTOR
+            .get();
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+
+    int pageSize = 0;
+    if (simplePageSize.isPresent())
+    {
+      if (filters.size() > 1)
+      {
+        final LocalizableMessage message = ERR_PAGED_RESULTS_REQUIRES_SINGLE_FILTER
+            .get();
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+
+      try
+      {
+        pageSize = simplePageSize.getIntValue();
+        search.addControl(SimplePagedResultsControl.newControl(true, pageSize,
+            ByteString.empty()));
+      }
+      catch (final ArgumentException ae)
+      {
+        final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+            .getMessage());
+        println(message);
+        return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+      }
+    }
+    /*
+     * if(connectionOptions.useSASLExternal()) { if(!connectionOptions.useSSL()
+     * && !connectionOptions.useStartTLS()) { LocalizableMessage message =
+     * ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS.get();
+     * err.println(wrapText(message, MAX_LINE_WIDTH)); return
+     * CLIENT_SIDE_PARAM_ERROR; } if(keyStorePathValue == null) {
+     * LocalizableMessage message = ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE.get();
+     * err.println(wrapText(message, MAX_LINE_WIDTH)); return
+     * CLIENT_SIDE_PARAM_ERROR; } }
+     * connectionOptions.setVerbose(verbose.isPresent());
+     */
+
+    int wrapColumn = 80;
+    if (dontWrap.isPresent())
+    {
+      wrapColumn = 0;
+    }
+
+    if (noop.isPresent())
+    {
+      // We don't actually need to open a connection or perform the
+      // search, so we're done. We should return 0 to either mean that the
+      // processing was successful or that there were no matching entries, based
+      // on countEntries.isPresent() (but in either case the return value should
+      // be zero).
+      return 0;
+    }
+
+    Connection connection;
+    try
+    {
+      connection = connectionFactory.getConnection();
+    }
+    catch (final ErrorResultException ere)
+    {
+      return Utils.printErrorMessage(this, ere);
+    }
+    catch (final InterruptedException e)
+    {
+      // This shouldn't happen because there are no other threads to
+      // interrupt this one.
+      println(LocalizableMessage.raw(e.getLocalizedMessage()));
+      return ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue();
+    }
+
+    Utils.printPasswordPolicyResults(this, connection);
+
+    try
+    {
+      int filterIndex = 0;
+      ldifWriter = new LDIFEntryWriter(getOutputStream())
+          .setWrapColumn(wrapColumn);
+      final LDAPSearchResultHandler resultHandler = new LDAPSearchResultHandler();
+      while (true)
+      {
+        Result result;
+        try
+        {
+          result = connection.search(search, resultHandler);
+        }
+        catch (final InterruptedException e)
+        {
+          // This shouldn't happen because there are no other threads to
+          // interrupt this one.
+          result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED)
+              .setCause(e).setDiagnosticMessage(e.getLocalizedMessage());
+          throw ErrorResultException.wrap(result);
+        }
+
+        try
+        {
+          final ServerSideSortResponseControl control = result.getControl(
+              ServerSideSortResponseControl.DECODER, new DecodeOptions());
+          if (control != null)
+          {
+            if (control.getResult() != ResultCode.SUCCESS)
+            {
+              final LocalizableMessage msg = WARN_LDAPSEARCH_SORT_ERROR
+                  .get(control.getResult().toString());
+              println(msg);
+            }
+          }
+        }
+        catch (final DecodeException e)
+        {
+          println(ERR_DECODE_CONTROL_FAILURE.get(e.getLocalizedMessage()));
+        }
+
+        try
+        {
+          final VirtualListViewResponseControl control = result.getControl(
+              VirtualListViewResponseControl.DECODER, new DecodeOptions());
+          if (control != null)
+          {
+            if (control.getResult() == ResultCode.SUCCESS)
+            {
+              LocalizableMessage msg = INFO_LDAPSEARCH_VLV_TARGET_OFFSET
+                  .get(control.getTargetPosition());
+              println(msg);
+
+              msg = INFO_LDAPSEARCH_VLV_CONTENT_COUNT.get(control
+                  .getContentCount());
+              println(msg);
+            }
+            else
+            {
+              final LocalizableMessage msg = WARN_LDAPSEARCH_VLV_ERROR
+                  .get(control.getResult().toString());
+              println(msg);
+            }
+          }
+        }
+        catch (final DecodeException e)
+        {
+          println(ERR_DECODE_CONTROL_FAILURE.get(e.getLocalizedMessage()));
+        }
+
+        try
+        {
+          SimplePagedResultsControl control = result.getControl(
+              SimplePagedResultsControl.DECODER, new DecodeOptions());
+          if (control != null)
+          {
+            if (control.getCookie().length() > 0)
+            {
+              if (!isQuiet())
+              {
+                pressReturnToContinue();
+              }
+              final Iterator<Control> iterator = search.getControls()
+                  .iterator();
+              while (iterator.hasNext())
+              {
+                if (iterator.next().getOID().equals(
+                    SimplePagedResultsControl.OID))
+                {
+                  iterator.remove();
+                }
+              }
+              control = SimplePagedResultsControl.newControl(true, pageSize,
+                  control.getCookie());
+              search.addControl(control);
+              continue;
+            }
+          }
+        }
+        catch (final DecodeException e)
+        {
+          println(ERR_DECODE_CONTROL_FAILURE.get(e.getLocalizedMessage()));
+        }
+
+        println();
+        println(ERR_TOOL_RESULT_CODE.get(result.getResultCode().intValue(),
+            result.getResultCode().toString()));
+        if ((result.getDiagnosticMessage() != null)
+            && (result.getDiagnosticMessage().length() > 0))
+        {
+          println(LocalizableMessage.raw(result.getDiagnosticMessage()));
+        }
+        if (result.getMatchedDN() != null && result.getMatchedDN().length() > 0)
+        {
+          println(ERR_TOOL_MATCHED_DN.get(result.getMatchedDN()));
+        }
+
+        filterIndex++;
+        if (filterIndex < filters.size())
+        {
+          search.setFilter(filters.get(filterIndex));
+        }
+        else
+        {
+          break;
+        }
+      }
+      if (countEntries.isPresent() && !isQuiet())
+      {
+        final LocalizableMessage message = INFO_LDAPSEARCH_MATCHING_ENTRY_COUNT
+            .get(resultHandler.entryCount);
+        println(message);
+        println();
+      }
+    }
+    catch (final ErrorResultException ere)
+    {
+      return Utils.printErrorMessage(this, ere);
+    }
+    finally
+    {
+      connection.close();
+    }
+
+    return 0;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ModRate.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ModRate.java
new file mode 100644
index 0000000..664da15
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ModRate.java
@@ -0,0 +1,429 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.glassfish.grizzly.TransportFactory;
+import org.opends.sdk.*;
+import org.opends.sdk.requests.ModifyRequest;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * A load generation tool that can be used to load a Directory Server with
+ * Modify requests using one or more LDAP connections.
+ */
+public final class ModRate extends ConsoleApplication
+{
+  private static final class ModifyPerformanceRunner extends PerformanceRunner
+  {
+    private final class ModifyWorkerThread extends ConnectionWorker
+    {
+      private ModifyRequest mr;
+      private Object[] data;
+
+
+
+      private ModifyWorkerThread(final AsynchronousConnection connection,
+          final ConnectionFactory connectionFactory)
+      {
+        super(connection, connectionFactory);
+      }
+
+
+
+      @Override
+      public FutureResult<?> performOperation(
+          final AsynchronousConnection connection,
+          final DataSource[] dataSources, final long startTime)
+      {
+        if (dataSources != null)
+        {
+          data = DataSource.generateData(dataSources, data);
+        }
+        mr = newModifyRequest(data);
+        return connection.modify(mr, new UpdateStatsResultHandler<Result>(
+            startTime, connection, this));
+      }
+
+
+
+      private ModifyRequest newModifyRequest(final Object[] data)
+      {
+        String formattedString;
+        int colonPos;
+        ModifyRequest mr;
+        if (data == null)
+        {
+          mr = Requests.newModifyRequest(baseDN);
+        }
+        else
+        {
+          mr = Requests.newModifyRequest(String.format(baseDN, data));
+        }
+        for (final String modString : modStrings)
+        {
+          if (data == null)
+          {
+            formattedString = modString;
+          }
+          else
+          {
+            formattedString = String.format(modString, data);
+          }
+          colonPos = formattedString.indexOf(':');
+          if (colonPos > 0)
+          {
+            mr.addModification(ModificationType.REPLACE,
+                formattedString.substring(0, colonPos),
+                formattedString.substring(colonPos + 1));
+          }
+        }
+        return mr;
+      }
+    }
+
+
+
+    private String baseDN;
+
+    private String[] modStrings;
+
+
+
+    private ModifyPerformanceRunner(final ArgumentParser argParser,
+        final ConsoleApplication app) throws ArgumentException
+    {
+      super(argParser, app, false, false, false);
+    }
+
+
+
+    @Override
+    ConnectionWorker newConnectionWorker(
+        final AsynchronousConnection connection,
+        final ConnectionFactory connectionFactory)
+    {
+      return new ModifyWorkerThread(connection, connectionFactory);
+    }
+
+
+
+    @Override
+    StatsThread newStatsThread()
+    {
+      return new StatsThread(new String[0]);
+    }
+  }
+
+
+
+  /**
+   * The main method for ModRate tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = mainModRate(args, System.in, System.out, System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the modrate tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return The error code.
+   */
+
+  static int mainModRate(final String[] args)
+  {
+    return mainModRate(args, System.in, System.out, System.err);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the modrate tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+
+  static int mainModRate(final String[] args, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+
+  {
+    return new ModRate(inStream, outStream, errStream).run(args);
+  }
+
+
+
+  private BooleanArgument verbose;
+
+  private BooleanArgument scriptFriendly;
+
+
+
+  private ModRate(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return scriptFriendly.isPresent();
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription = INFO_MODRATE_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(
+        ModRate.class.getName(), toolDescription, false, true, 1, 0,
+        "[(attribute:value format string) ...]");
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+    ModifyPerformanceRunner runner;
+
+    BooleanArgument showUsage;
+    StringArgument propertiesFileArgument;
+    BooleanArgument noPropertiesFileArgument;
+    StringArgument baseDN;
+
+    try
+    {
+      TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
+      connectionFactoryProvider = new ConnectionFactoryProvider(argParser, this);
+      runner = new ModifyPerformanceRunner(argParser, this);
+      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
+          OPTION_LONG_PROP_FILE_PATH, false, false, true,
+          INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      baseDN = new StringArgument("targetDN", OPTION_SHORT_BASEDN,
+          OPTION_LONG_TARGETDN, true, false, true,
+          INFO_TARGETDN_PLACEHOLDER.get(), null, null,
+          INFO_MODRATE_TOOL_DESCRIPTION_TARGETDN.get());
+      baseDN.setPropertyName(OPTION_LONG_BASEDN);
+      argParser.addArgument(baseDN);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+
+      scriptFriendly = new BooleanArgument("scriptFriendly", 'S',
+          "scriptFriendly", INFO_DESCRIPTION_SCRIPT_FRIENDLY.get());
+      scriptFriendly.setPropertyName("scriptFriendly");
+      argParser.addArgument(scriptFriendly);
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+
+      connectionFactory = connectionFactoryProvider
+          .getAuthenticatedConnectionFactory();
+      runner.validate();
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    runner.modStrings = argParser.getTrailingArguments().toArray(
+        new String[argParser.getTrailingArguments().size()]);
+    runner.baseDN = baseDN.getValue();
+
+    try
+    {
+
+      // Try it out to make sure the format string and data sources
+      // match.
+      final Object[] data = DataSource.generateData(runner.getDataSources(),
+          null);
+      for (final String modString : runner.modStrings)
+      {
+        String.format(modString, data);
+      }
+      String.format(runner.baseDN, data);
+    }
+    catch (final Exception ex1)
+    {
+      println(LocalizableMessage.raw("Error formatting filter or base DN: "
+          + ex1.toString()));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    return runner.run(connectionFactory);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiChoiceArgument.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiChoiceArgument.java
new file mode 100644
index 0000000..61eb812
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiChoiceArgument.java
@@ -0,0 +1,271 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_MCARG_VALUE_NOT_ALLOWED;
+
+import java.util.Collection;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines an argument type that will only accept one or more of a
+ * specific set of string values.
+ *
+ * @param <T>
+ *          The type of values returned by this argument.
+ */
+final class MultiChoiceArgument<T> extends Argument
+{
+  // Indicates whether argument values should be treated in a
+  // case-sensitive manner.
+  private final boolean caseSensitive;
+
+  // The set of values that will be allowed for use with this argument.
+  private final Collection<T> allowedValues;
+
+
+
+  /**
+   * Creates a new string argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param allowedValues
+   *          The set of values that are allowed for use for this argument. If
+   *          they are not to be treated in a case-sensitive value then they
+   *          should all be formatted in lowercase.
+   * @param caseSensitive
+   *          Indicates whether the set of allowed values should be treated in a
+   *          case-sensitive manner.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public MultiChoiceArgument(final String name,
+      final Character shortIdentifier, final String longIdentifier,
+      final boolean isRequired, final boolean isMultiValued,
+      final boolean needsValue, final LocalizableMessage valuePlaceholder,
+      final String defaultValue, final String propertyName,
+      final Collection<T> allowedValues, final boolean caseSensitive,
+      final LocalizableMessage description) throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
+        needsValue, valuePlaceholder, defaultValue, propertyName, description);
+
+    this.allowedValues = allowedValues;
+    this.caseSensitive = caseSensitive;
+  }
+
+
+
+  /**
+   * Creates a new string argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param allowedValues
+   *          The set of values that are allowed for use for this argument. If
+   *          they are not to be treated in a case-sensitive value then they
+   *          should all be formatted in lowercase.
+   * @param caseSensitive
+   *          Indicates whether the set of allowed values should be treated in a
+   *          case-sensitive manner.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public MultiChoiceArgument(final String name,
+      final Character shortIdentifier, final String longIdentifier,
+      final boolean isRequired, final boolean needsValue,
+      final LocalizableMessage valuePlaceholder,
+      final Collection<T> allowedValues, final boolean caseSensitive,
+      final LocalizableMessage description) throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, false, needsValue,
+        valuePlaceholder, null, null, description);
+
+    this.allowedValues = allowedValues;
+    this.caseSensitive = caseSensitive;
+  }
+
+
+
+  /**
+   * Retrieves the set of allowed values for this argument. The contents of this
+   * set must not be altered by the caller.
+   *
+   * @return The set of allowed values for this argument.
+   */
+  public Collection<T> getAllowedValues()
+  {
+    return allowedValues;
+  }
+
+
+
+  /**
+   * Retrieves the string vale for this argument. If it has multiple values,
+   * then the first will be returned. If it does not have any values, then the
+   * default value will be returned.
+   *
+   * @return The string value for this argument, or <CODE>null</CODE> if there
+   *         are no values and no default value has been given.
+   * @throws ArgumentException
+   *           The value cannot be parsed.
+   */
+  public T getTypedValue() throws ArgumentException
+  {
+    final String v = super.getValue();
+    if (v == null)
+    {
+      return null;
+    }
+    for (final T o : allowedValues)
+    {
+      if ((caseSensitive && o.toString().equals(v))
+          || o.toString().equalsIgnoreCase(v))
+      {
+        return o;
+      }
+    }
+    // TODO: Some message
+    throw new ArgumentException(null);
+  }
+
+
+
+  /**
+   * Indicates whether the set of allowed values for this argument should be
+   * treated in a case-sensitive manner.
+   *
+   * @return <CODE>true</CODE> if the values are to be treated in a
+   *         case-sensitive manner, or <CODE>false</CODE> if not.
+   */
+  public boolean isCaseSensitive()
+  {
+    return caseSensitive;
+  }
+
+
+
+  /**
+   * Specifies the default value that will be used for this argument if it is
+   * not specified on the command line and it is not set from a properties file.
+   *
+   * @param defaultValue
+   *          The default value that will be used for this argument if it is not
+   *          specified on the command line and it is not set from a properties
+   *          file.
+   */
+  public void setDefaultValue(final T defaultValue)
+  {
+    super.setDefaultValue(defaultValue.toString());
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in this
+   * argument.
+   *
+   * @param valueString
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          A buffer into which the invalid reason may be written if the value
+   *          is not acceptable.
+   * @return <CODE>true</CODE> if the value is acceptable, or <CODE>false</CODE>
+   *         if it is not.
+   */
+  @Override
+  public boolean valueIsAcceptable(final String valueString,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    for (final T o : allowedValues)
+    {
+      if ((caseSensitive && o.toString().equals(valueString))
+          || o.toString().equalsIgnoreCase(valueString))
+      {
+        return true;
+      }
+    }
+    invalidReason.append(ERR_MCARG_VALUE_NOT_ALLOWED
+        .get(getName(), valueString));
+
+    return false;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiColumnPrinter.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiColumnPrinter.java
new file mode 100644
index 0000000..f0bcd44
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/MultiColumnPrinter.java
@@ -0,0 +1,547 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+
+
+/**
+ * Utility class for printing aligned columns of text.
+ * <P>
+ * This class allows you to specify:
+ * <UL>
+ * <LI>The number of columns in the output. This will determine the dimension of
+ * the string arrays passed to add(String[]) or addTitle(String[]).
+ * <LI>spacing/gap between columns
+ * <LI>character to use for title border (null means no border)
+ * <LI>column alignment. Only LEFT/CENTER is supported for now.
+ * </UL>
+ * <P>
+ * Example usage:
+ *
+ * <PRE>
+ * MyPrinter mp = new MyPrinter(3, 2, &quot;-&quot;);
+ * String oneRow[] = new String[3];
+ * oneRow[0] = &quot;User Name&quot;;
+ * oneRow[1] = &quot;Email Address&quot;;
+ * oneRow[2] = &quot;Phone Number&quot;;
+ * mp.addTitle(oneRow);
+ * oneRow[0] = &quot;Bob&quot;;
+ * oneRow[1] = &quot;bob@foo.com&quot;;
+ * oneRow[2] = &quot;123-4567&quot;;
+ * mp.add(oneRow);
+ * oneRow[0] = &quot;John&quot;;
+ * oneRow[1] = &quot;john@foo.com&quot;;
+ * oneRow[2] = &quot;456-7890&quot;;
+ * mp.add(oneRow);
+ * mp.print();
+ * </PRE>
+ * <P>
+ * The above would print:
+ * <P>
+ *
+ * <PRE>
+ *  --------------------------------------
+ *  User Name  Email Address  Phone Number
+ *  --------------------------------------
+ *  Bob        bob@foo.com    123-4567
+ *  John       john@foo.com   456-7890
+ * </PRE>
+ * <P>
+ * This class also supports multi-row titles and having title strings spanning
+ * multiple collumns. Example usage:
+ *
+ * <PRE>
+ * TestPrinter tp = new TestPrinter(4, 2, &quot;-&quot;);
+ * String oneRow[] = new String[4];
+ * int[] span = new int[4];
+ * span[0] = 2; // spans 2 collumns
+ * span[1] = 0; // spans 0 collumns
+ * span[2] = 2; // spans 2 collumns
+ * span[3] = 0; // spans 0 collumns
+ * tp.setTitleAlign(CENTER);
+ * oneRow[0] = &quot;Name&quot;;
+ * oneRow[1] = &quot;&quot;;
+ * oneRow[2] = &quot;Contact&quot;;
+ * oneRow[3] = &quot;&quot;;
+ * tp.addTitle(oneRow, span);
+ * oneRow[0] = &quot;First&quot;;
+ * oneRow[1] = &quot;Last&quot;;
+ * oneRow[2] = &quot;Email&quot;;
+ * oneRow[3] = &quot;Phone&quot;;
+ * tp.addTitle(oneRow);
+ * oneRow[0] = &quot;Bob&quot;;
+ * oneRow[1] = &quot;Jones&quot;;
+ * oneRow[2] = &quot;bob@foo.com&quot;;
+ * oneRow[3] = &quot;123-4567&quot;;
+ * tp.add(oneRow);
+ * oneRow[0] = &quot;John&quot;;
+ * oneRow[1] = &quot;Doe&quot;;
+ * oneRow[2] = &quot;john@foo.com&quot;;
+ * oneRow[3] = &quot;456-7890&quot;;
+ * tp.add(oneRow);
+ * tp.println();
+ * </PRE>
+ * <P>
+ * The above would print:
+ * <P>
+ *
+ * <PRE>
+ *      ------------------------------------
+ *          Name             Contact
+ *      First  Last      Email       Phone
+ *      ------------------------------------
+ *      Bob    Jones  bob@foo.com   123-4567
+ *      John   Doe    john@foo.com  456-7890
+ * </PRE>
+ */
+final class MultiColumnPrinter
+{
+
+  final public static int LEFT = 0;
+
+  final public static int CENTER = 1;
+
+  final public static int RIGHT = 2;
+
+  private int numCol = 2;
+
+  private int gap = 4;
+
+  private int align = CENTER;
+
+  private int titleAlign = CENTER;
+
+  private String border = null;
+
+  private Vector<String[]> titleTable = null;
+
+  private Vector<int[]> titleSpanTable = null;
+
+  private final int curLength[];
+
+  private final ConsoleApplication app;
+
+
+
+  /**
+   * Creates a sorted new MultiColumnPrinter class using LEFT alignment and with
+   * no title border.
+   *
+   * @param numCol
+   *          number of columns
+   * @param gap
+   *          gap between each column
+   */
+  MultiColumnPrinter(final int numCol, final int gap,
+      final ConsoleApplication app)
+  {
+    this(numCol, gap, null, LEFT, app);
+  }
+
+
+
+  /**
+   * Creates a sorted new MultiColumnPrinter class using LEFT alignment.
+   *
+   * @param numCol
+   *          number of columns
+   * @param gap
+   *          gap between each column
+   * @param border
+   *          character used to frame the titles
+   */
+  MultiColumnPrinter(final int numCol, final int gap, final String border,
+      final ConsoleApplication app)
+  {
+    this(numCol, gap, border, LEFT, app);
+  }
+
+
+
+  /**
+   * Creates a new MultiColumnPrinter class.
+   *
+   * @param numCol
+   *          number of columns
+   * @param gap
+   *          gap between each column
+   * @param border
+   *          character used to frame the titles
+   * @param align
+   *          type of alignment within columns
+   */
+  MultiColumnPrinter(final int numCol, final int gap, final String border,
+      final int align, final ConsoleApplication app)
+  {
+
+    titleTable = new Vector<String[]>();
+    titleSpanTable = new Vector<int[]>();
+    curLength = new int[numCol];
+
+    this.numCol = numCol;
+    this.gap = gap;
+    this.border = border;
+    this.align = align;
+    this.titleAlign = LEFT;
+
+    this.app = app;
+  }
+
+
+
+  /**
+   * Adds to the row of strings to be used as the title for the table.
+   *
+   * @param row
+   *          Array of strings to print in one row of title.
+   */
+  void addTitle(final String[] row)
+  {
+    if (row == null)
+    {
+      return;
+    }
+
+    final int[] span = new int[row.length];
+    for (int i = 0; i < row.length; i++)
+    {
+      span[i] = 1;
+    }
+
+    addTitle(row, span);
+  }
+
+
+
+  /**
+   * Adds to the row of strings to be used as the title for the table. Also
+   * allows for certain title strings to span multiple collumns The span
+   * parameter is an array of integers which indicate how many collumns the
+   * corresponding title string will occupy. For a row that is 4 collumns wide,
+   * it is possible to have some title strings in a row to 'span' multiple
+   * collumns:
+   * <P>
+   *
+   * <PRE>
+   * ------------------------------------
+   *     Name             Contact
+   * First  Last      Email       Phone
+   * ------------------------------------
+   * Bob    Jones  bob@foo.com   123-4567
+   * John   Doe    john@foo.com  456-7890
+   * </PRE>
+   *
+   * In the example above, the title row has a string 'Name' that spans 2
+   * collumns. The string 'Contact' also spans 2 collumns. The above is done by
+   * passing in to addTitle() an array that contains:
+   *
+   * <PRE>
+   * span[0] = 2; // spans 2 collumns
+   * span[1] = 0; // spans 0 collumns, ignore
+   * span[2] = 2; // spans 2 collumns
+   * span[3] = 0; // spans 0 collumns, ignore
+   * </PRE>
+   * <P>
+   * A span value of 1 is the default. The method addTitle(String[] row)
+   * basically does:
+   *
+   * <PRE>
+   * int[] span = new int[row.length];
+   * for (int i = 0; i &lt; row.length; i++)
+   * {
+   *   span[i] = 1;
+   * }
+   * addTitle(row, span);
+   * </PRE>
+   *
+   * @param row
+   *          Array of strings to print in one row of title.
+   * @param span
+   *          Array of integers that reflect the number of collumns the
+   *          corresponding title string will occupy.
+   */
+  void addTitle(final String[] row, final int span[])
+  {
+    // Need to create a new instance of it, otherwise the new values
+    // will always overwrite the old values.
+
+    final String[] rowInstance = new String[(row.length)];
+    for (int i = 0; i < row.length; i++)
+    {
+      rowInstance[i] = row[i];
+    }
+    titleTable.addElement(rowInstance);
+
+    titleSpanTable.addElement(span);
+  }
+
+
+
+  /**
+   * Clears title strings.
+   */
+  void clearTitle()
+  {
+    titleTable.clear();
+    titleSpanTable.clear();
+  }
+
+
+
+  /**
+   * Adds one row of text to output.
+   *
+   * @param row
+   *          Array of strings to print in one row.
+   */
+  void printRow(final String... row)
+  {
+    for (int i = 0; i < numCol; i++)
+    {
+      if (titleAlign == RIGHT)
+      {
+        final int spaceBefore = curLength[i] - row[i].length();
+        printSpaces(spaceBefore);
+        app.getOutputStream().print(row[i]);
+        if (i < numCol - 1)
+        {
+          printSpaces(gap);
+        }
+      }
+      else if (align == CENTER)
+      {
+        int space1, space2;
+        space1 = (curLength[i] - row[i].length()) / 2;
+        space2 = curLength[i] - row[i].length() - space1;
+
+        printSpaces(space1);
+        app.getOutputStream().print(row[i]);
+        printSpaces(space2);
+        if (i < numCol - 1)
+        {
+          printSpaces(gap);
+        }
+      }
+      else
+      {
+        app.getOutputStream().print(row[i]);
+        if (i < numCol - 1)
+        {
+          printSpaces(curLength[i] - row[i].length() + gap);
+        }
+      }
+    }
+    app.getOutputStream().println("");
+  }
+
+
+
+  /**
+   * Prints the table title
+   */
+  void printTitle()
+  {
+    // Get the longest string for each column and store in curLength[]
+
+    // Scan through title rows
+    Enumeration<String[]> elm = titleTable.elements();
+    Enumeration<int[]> spanEnum = titleSpanTable.elements();
+    while (elm.hasMoreElements())
+    {
+      final String[] row = elm.nextElement();
+      final int[] curSpan = spanEnum.nextElement();
+
+      for (int i = 0; i < numCol; i++)
+      {
+        // None of the fields should be null, but if it
+        // happens to be so, replace it with "-".
+        if (row[i] == null)
+        {
+          row[i] = "-";
+        }
+
+        int len = row[i].length();
+
+        /*
+         * If a title string spans multiple collumns, then the space it occupies
+         * in each collumn is at most len/span (since we have gap to take into
+         * account as well).
+         */
+        final int span = curSpan[i];
+        int rem = 0;
+        if (span > 1)
+        {
+          rem = len % span;
+          len = len / span;
+        }
+
+        if (curLength[i] < len)
+        {
+          curLength[i] = len;
+
+          if ((span > 1) && ((i + span) <= numCol))
+          {
+            for (int j = i + 1; j < (i + span); ++j)
+            {
+              curLength[j] = len;
+            }
+
+            /*
+             * Add remainder to last collumn in span to avoid round-off errors.
+             */
+            curLength[(i + span) - 1] += rem;
+          }
+        }
+      }
+    }
+
+    printBorder();
+    elm = titleTable.elements();
+    spanEnum = titleSpanTable.elements();
+
+    while (elm.hasMoreElements())
+    {
+      final String[] row = elm.nextElement();
+      final int[] curSpan = spanEnum.nextElement();
+
+      for (int i = 0; i < numCol; i++)
+      {
+        int availableSpace = 0;
+        final int span = curSpan[i];
+
+        if (span == 0)
+        {
+          continue;
+        }
+
+        availableSpace = curLength[i];
+
+        if ((span > 1) && ((i + span) <= numCol))
+        {
+          for (int j = i + 1; j < (i + span); ++j)
+          {
+            availableSpace += gap;
+            availableSpace += curLength[j];
+          }
+        }
+
+        if (titleAlign == RIGHT)
+        {
+          final int spaceBefore = availableSpace - row[i].length();
+          printSpaces(spaceBefore);
+          app.getOutputStream().print(row[i]);
+          if (i < numCol - 1)
+          {
+            printSpaces(gap);
+          }
+        }
+        else if (titleAlign == CENTER)
+        {
+          int spaceBefore, spaceAfter;
+          spaceBefore = (availableSpace - row[i].length()) / 2;
+          spaceAfter = availableSpace - row[i].length() - spaceBefore;
+
+          printSpaces(spaceBefore);
+          app.getOutputStream().print(row[i]);
+          printSpaces(spaceAfter);
+          if (i < numCol - 1)
+          {
+            printSpaces(gap);
+          }
+        }
+        else
+        {
+          app.getOutputStream().print(row[i]);
+          if (i < numCol - 1)
+          {
+            printSpaces(availableSpace - row[i].length() + gap);
+          }
+        }
+
+      }
+      app.getOutputStream().println("");
+    }
+    printBorder();
+  }
+
+
+
+  /**
+   * Set alignment for title strings
+   *
+   * @param titleAlign
+   */
+  void setTitleAlign(final int titleAlign)
+  {
+    this.titleAlign = titleAlign;
+  }
+
+
+
+  private void printBorder()
+  {
+    if (border == null)
+    {
+      return;
+    }
+
+    // For the value in each column
+    for (int i = 0; i < numCol; i++)
+    {
+      for (int j = 0; j < curLength[i]; j++)
+      {
+        app.getOutputStream().print(border);
+      }
+    }
+
+    // For the gap between each column
+    for (int i = 0; i < numCol - 1; i++)
+    {
+      for (int j = 0; j < gap; j++)
+      {
+        app.getOutputStream().print(border);
+      }
+    }
+    app.getOutputStream().println("");
+  }
+
+
+
+  private void printSpaces(final int count)
+  {
+    for (int i = 0; i < count; ++i)
+    {
+      app.getOutputStream().print(" ");
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactory.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactory.java
new file mode 100644
index 0000000..c0452ce
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactory.java
@@ -0,0 +1,171 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import org.glassfish.grizzly.Grizzly;
+import org.glassfish.grizzly.memory.HeapMemoryManager;
+import org.glassfish.grizzly.nio.DefaultNIOTransportFactory;
+import org.glassfish.grizzly.nio.DefaultSelectionKeyHandler;
+import org.glassfish.grizzly.nio.DefaultSelectorHandler;
+import org.glassfish.grizzly.nio.tmpselectors.TemporarySelectorPool;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+import org.glassfish.grizzly.nio.transport.UDPNIOTransport;
+import org.glassfish.grizzly.threadpool.AbstractThreadPool;
+import org.glassfish.grizzly.threadpool.GrizzlyExecutorService;
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+
+
+
+/**
+ * The TCPNIOTransportFactory which performance tools will use.
+ */
+public final class PerfToolTCPNIOTransportFactory extends
+    DefaultNIOTransportFactory
+{
+  private int selectors;
+
+  private int linger = 0;
+
+  private boolean tcpNoDelay = true;
+
+  private boolean reuseAddress = true;
+
+  private TCPNIOTransport singletonTransport = null;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public synchronized TCPNIOTransport createTCPTransport()
+  {
+    if (singletonTransport == null)
+    {
+      singletonTransport = super.createTCPTransport();
+
+      singletonTransport.setSelectorRunnersCount(selectors);
+      singletonTransport.setLinger(linger);
+      singletonTransport.setTcpNoDelay(tcpNoDelay);
+      singletonTransport.setReuseAddress(reuseAddress);
+    }
+
+    return singletonTransport;
+  }
+
+
+
+  /**
+   * Creating an UDP transport is unsupported with this factory. A
+   * {@code UnsupportedOperationException} will be thrown when this method is
+   * called.
+   *
+   * @return This method will always throw {@code UnsupportedOperationException}
+   *         .
+   */
+  @Override
+  public UDPNIOTransport createUDPTransport()
+  {
+    throw new UnsupportedOperationException();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void initialize()
+  {
+    final int cpus = Runtime.getRuntime().availableProcessors();
+    int threads = Math.max(5, (cpus / 2) - 1);
+    selectors = Math.max(2, cpus / 8);
+
+    final String threadsStr = System
+        .getProperty("org.opends.sdk.ldap.transport.threads");
+    if (threadsStr != null)
+    {
+      threads = Integer.parseInt(threadsStr);
+    }
+    final String selectorsStr = System
+        .getProperty("org.opends.sdk.ldap.transport.selectors");
+    if (selectorsStr != null)
+    {
+      selectors = Integer.parseInt(selectorsStr);
+    }
+
+    final String lingerStr = System
+        .getProperty("org.opends.sdk.ldap.transport.linger");
+    if (lingerStr != null)
+    {
+      linger = Integer.parseInt(lingerStr);
+    }
+
+    final String tcpNoDelayStr = System
+        .getProperty("org.opends.sdk.ldap.transport.tcpNoDelay");
+    if (tcpNoDelayStr != null)
+    {
+      tcpNoDelay = Integer.parseInt(tcpNoDelayStr) != 0;
+    }
+
+    final String reuseAddressStr = System
+        .getProperty("org.opends.sdk.ldap.transport.reuseAddress");
+    if (reuseAddressStr != null)
+    {
+      reuseAddress = Integer.parseInt(reuseAddressStr) != 0;
+    }
+
+    // Copied from TransportFactory.
+    defaultAttributeBuilder = Grizzly.DEFAULT_ATTRIBUTE_BUILDER;
+    defaultMemoryManager = new HeapMemoryManager();
+    defaultWorkerThreadPool = GrizzlyExecutorService
+        .createInstance(ThreadPoolConfig.defaultConfig()
+            .setMemoryManager(defaultMemoryManager).setCorePoolSize(threads)
+            .setMaxPoolSize(threads).setPoolName("OpenDS SDK Worker(Grizzly)"));
+
+    // Copied from NIOTransportFactory.
+    defaultSelectorHandler = new DefaultSelectorHandler();
+    defaultSelectionKeyHandler = new DefaultSelectionKeyHandler();
+
+    /*
+     * By default TemporarySelector pool size should be equal to the number of
+     * processing threads
+     */
+    int selectorPoolSize = TemporarySelectorPool.DEFAULT_SELECTORS_COUNT;
+    if (defaultWorkerThreadPool instanceof AbstractThreadPool)
+    {
+      selectorPoolSize = Math.min(
+          ((AbstractThreadPool) defaultWorkerThreadPool).getConfig()
+              .getMaxPoolSize(), selectorPoolSize);
+    }
+    defaultTemporarySelectorPool = new TemporarySelectorPool(selectorPoolSize);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerformanceRunner.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerformanceRunner.java
new file mode 100644
index 0000000..9f4ab43
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PerformanceRunner.java
@@ -0,0 +1,1283 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import java.io.IOException;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.opends.sdk.*;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.Result;
+
+import com.sun.opends.sdk.tools.AuthenticatedConnectionFactory.AuthenticatedAsynchronousConnection;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Benchmark application framework.
+ */
+abstract class PerformanceRunner implements ConnectionEventListener
+{
+  abstract class ConnectionWorker
+  {
+    private final AtomicInteger operationsInFlight = new AtomicInteger();
+
+    private volatile int count;
+
+    private final AsynchronousConnection staticConnection;
+
+    private final ConnectionFactory connectionFactory;
+
+    private final CountDownLatch latch = new CountDownLatch(1);
+
+
+
+    ConnectionWorker(final AsynchronousConnection staticConnection,
+        final ConnectionFactory connectionFactory)
+    {
+      this.staticConnection = staticConnection;
+      this.connectionFactory = connectionFactory;
+    }
+
+
+
+    public void operationCompleted(final AsynchronousConnection connection)
+    {
+      if (operationsInFlight.decrementAndGet() == 0
+          && this.staticConnection == null)
+      {
+        connection.close();
+      }
+      startWork();
+    }
+
+
+
+    public abstract FutureResult<?> performOperation(
+        final AsynchronousConnection connection,
+        final DataSource[] dataSources, final long startTime);
+
+
+
+    public void startWork()
+    {
+      if (!stopRequested && !(maxIterations > 0 && count >= maxIterations))
+      {
+        if (this.staticConnection == null)
+        {
+          connectionFactory
+              .getAsynchronousConnection(new ResultHandler<AsynchronousConnection>()
+              {
+                public void handleErrorResult(final ErrorResultException e)
+                {
+                  app.println(LocalizableMessage.raw(e.getResult()
+                      .getDiagnosticMessage()));
+                  if (e.getCause() != null && app.isVerbose())
+                  {
+                    e.getCause().printStackTrace(app.getErrorStream());
+                  }
+                  stopRequested = true;
+                }
+
+
+
+                public void handleResult(final AsynchronousConnection result)
+                {
+                  doWork(result);
+                }
+              });
+        }
+        else
+        {
+          if (!noRebind
+              && this.staticConnection instanceof AuthenticatedAsynchronousConnection)
+          {
+            final AuthenticatedAsynchronousConnection ac =
+              (AuthenticatedAsynchronousConnection) this.staticConnection;
+            ac.rebind(new ResultHandler<BindResult>()
+            {
+              public void handleErrorResult(final ErrorResultException e)
+              {
+                app.println(LocalizableMessage.raw(e.getResult().toString()));
+                if (e.getCause() != null && app.isVerbose())
+                {
+                  e.getCause().printStackTrace(app.getErrorStream());
+                }
+                stopRequested = true;
+              }
+
+
+
+              public void handleResult(final BindResult result)
+              {
+                doWork(staticConnection);
+              }
+            });
+          }
+          else
+          {
+            doWork(staticConnection);
+          }
+        }
+      }
+      else
+      {
+        latch.countDown();
+      }
+    }
+
+
+
+    public void waitFor() throws InterruptedException
+    {
+      latch.await();
+    }
+
+
+
+    private void doWork(final AsynchronousConnection connection)
+    {
+      long start;
+      double sleepTimeInMS = 0;
+      final int opsToPerform = isAsync ? numConcurrentTasks : numConcurrentTasks
+          - operationsInFlight.get();
+      for (int i = 0; i < opsToPerform; i++)
+      {
+        if (maxIterations > 0 && count >= maxIterations)
+        {
+          break;
+        }
+        start = System.nanoTime();
+        performOperation(connection, dataSources.get(), start);
+        operationRecentCount.getAndIncrement();
+        operationsInFlight.getAndIncrement();
+        count++;
+
+        if (targetThroughput > 0)
+        {
+          try
+          {
+            if (sleepTimeInMS > 1)
+            {
+              Thread.sleep((long) Math.floor(sleepTimeInMS));
+            }
+          }
+          catch (final InterruptedException e)
+          {
+            continue;
+          }
+
+          sleepTimeInMS += targetTimeInMS
+              - ((System.nanoTime() - start) / 1000000.0);
+          if (sleepTimeInMS < -60000)
+          {
+            // If we fall behind by 60 seconds, just forget about
+            // catching up
+            sleepTimeInMS = -60000;
+          }
+        }
+      }
+    }
+  }
+
+
+
+  /**
+   * Statistics thread base implementation.
+   */
+  class StatsThread extends Thread
+  {
+    private final String[] additionalColumns;
+
+    private final List<GarbageCollectorMXBean> beans;
+
+    private final Set<Double> percentiles;
+
+    private final int numColumns;
+
+    private ReversableArray etimes = new ReversableArray(100000);
+
+    private final ReversableArray array = new ReversableArray(200000);
+
+    protected long totalSuccessCount;
+
+    protected long totalOperationCount;
+
+    protected long totalFailedCount;
+
+    protected long totalWaitTime;
+
+    protected int successCount;
+
+    protected int operationCount;
+
+    protected int failedCount;
+
+    protected long waitTime;
+
+    protected long lastStatTime;
+
+    protected long lastGCDuration;
+
+    protected double recentDuration;
+
+    protected double averageDuration;
+
+
+
+    public StatsThread(final String[] additionalColumns)
+    {
+      super("Stats Thread");
+
+      this.additionalColumns = additionalColumns;
+
+      final TreeSet<Double> pSet = new TreeSet<Double>();
+      if (!percentilesArgument.isPresent())
+      {
+        pSet.add(.1);
+        pSet.add(.01);
+        pSet.add(.001);
+      }
+      else
+      {
+        for (final String percentile : percentilesArgument.getValues())
+        {
+          pSet.add(100.0 - Double.parseDouble(percentile));
+        }
+      }
+      this.percentiles = pSet.descendingSet();
+      this.numColumns = 5 + this.percentiles.size() + additionalColumns.length
+          + (isAsync ? 1 : 0);
+      this.beans = ManagementFactory.getGarbageCollectorMXBeans();
+    }
+
+
+
+    @Override
+    public void run()
+    {
+      final MultiColumnPrinter printer;
+
+      if (!app.isScriptFriendly())
+      {
+        printer = new MultiColumnPrinter(numColumns, 2, "-",
+            MultiColumnPrinter.RIGHT, app);
+        printer.setTitleAlign(MultiColumnPrinter.RIGHT);
+
+        String[] title = new String[numColumns];
+        Arrays.fill(title, "");
+        title[0] = "Throughput";
+        title[2] = "Response Time";
+        int[] span = new int[numColumns];
+        span[0] = 2;
+        span[1] = 0;
+        span[2] = 2 + this.percentiles.size();
+        Arrays.fill(span, 3, 4 + this.percentiles.size(), 0);
+        Arrays.fill(span, 4 + this.percentiles.size(), span.length, 1);
+        printer.addTitle(title, span);
+        title = new String[numColumns];
+        Arrays.fill(title, "");
+        title[0] = "(ops/second)";
+        title[2] = "(milliseconds)";
+        printer.addTitle(title, span);
+        title = new String[numColumns];
+        title[0] = "recent";
+        title[1] = "average";
+        title[2] = "recent";
+        title[3] = "average";
+        int i = 4;
+        for (final Double percentile : this.percentiles)
+        {
+          title[i++] = Double.toString(100.0 - percentile) + "%";
+        }
+        title[i++] = "err/sec";
+        if (isAsync)
+        {
+          title[i++] = "req/res";
+        }
+        for (final String column : additionalColumns)
+        {
+          title[i++] = column;
+        }
+        span = new int[numColumns];
+        Arrays.fill(span, 1);
+        printer.addTitle(title, span);
+        printer.printTitle();
+      }
+      else
+      {
+        app.getOutputStream().print("Time (seconds)");
+        app.getOutputStream().print(",");
+        app.getOutputStream().print("Recent throughput (ops/second)");
+        app.getOutputStream().print(",");
+        app.getOutputStream().print("Average throughput (ops/second)");
+        app.getOutputStream().print(",");
+        app.getOutputStream().print("Recent response time (milliseconds)");
+        app.getOutputStream().print(",");
+        app.getOutputStream().print("Average response time (milliseconds)");
+        for (final Double percentile : this.percentiles)
+        {
+          app.getOutputStream().print(",");
+          app.getOutputStream().print(Double.toString(100.0 - percentile));
+          app.getOutputStream().print("% response time (milliseconds)");
+        }
+        app.getOutputStream().print(",");
+        app.getOutputStream().print("Errors/second");
+        if (isAsync)
+        {
+          app.getOutputStream().print(",");
+          app.getOutputStream().print("Requests/response");
+        }
+        for (final String column : additionalColumns)
+        {
+          app.getOutputStream().print(",");
+          app.getOutputStream().print(column);
+        }
+        app.getOutputStream().println();
+        printer = null;
+      }
+
+      final String[] strings = new String[numColumns];
+
+      final long startTime = System.currentTimeMillis();
+      long statTime = startTime;
+      long gcDuration = 0;
+      for (final GarbageCollectorMXBean bean : beans)
+      {
+        gcDuration += bean.getCollectionTime();
+      }
+      while (!stopRequested)
+      {
+        try
+        {
+          sleep(statsInterval);
+        }
+        catch (final InterruptedException ie)
+        {
+          // Ignore.
+        }
+
+        lastStatTime = statTime;
+        statTime = System.currentTimeMillis();
+
+        lastGCDuration = gcDuration;
+        gcDuration = 0;
+        for (final GarbageCollectorMXBean bean : beans)
+        {
+          gcDuration += bean.getCollectionTime();
+        }
+
+        operationCount = operationRecentCount.getAndSet(0);
+        successCount = successRecentCount.getAndSet(0);
+        failedCount = failedRecentCount.getAndSet(0);
+        waitTime = waitRecentTime.getAndSet(0);
+
+        final int resultCount = successCount + failedCount;
+
+        totalOperationCount += operationCount;
+        totalSuccessCount += successCount;
+        totalFailedCount += failedCount;
+        totalWaitTime += waitTime;
+
+        final long totalResultCount = totalSuccessCount + totalFailedCount;
+
+        recentDuration = statTime - lastStatTime;
+        averageDuration = statTime - startTime;
+        recentDuration -= gcDuration - lastGCDuration;
+        averageDuration -= gcDuration;
+        recentDuration /= 1000.0;
+        averageDuration /= 1000.0;
+
+        strings[0] = String.format("%.1f", resultCount / recentDuration);
+        strings[1] = String.format("%.1f", totalResultCount / averageDuration);
+
+        if (resultCount > 0)
+        {
+          strings[2] = String.format("%.3f",
+              (waitTime - (gcDuration - lastGCDuration)) / (double) resultCount
+                  / 1000000.0);
+        }
+        else
+        {
+          strings[2] = "-";
+        }
+
+        if (totalResultCount > 0)
+        {
+          strings[3] = String.format("%.3f", (totalWaitTime - gcDuration)
+              / (double) totalResultCount / 1000000.0);
+        }
+        else
+        {
+          strings[3] = "-";
+        }
+
+        boolean changed = false;
+        etimes = eTimeBuffer.getAndSet(etimes);
+        final int appendLength = Math.min(array.remaining(), etimes.size());
+        if (appendLength > 0)
+        {
+          array.append(etimes, appendLength);
+          for (int i = array.size - appendLength; i < array.size; i++)
+          {
+            array.siftUp(0, i);
+          }
+          changed = true;
+        }
+
+        // Our window buffer is now full. Replace smallest with anything
+        // larger and re-heapify
+        for (int i = appendLength; i < etimes.size(); i++)
+        {
+          if (etimes.get(i) > array.get(0))
+          {
+            array.set(0, etimes.get(i));
+            array.siftDown(0, array.size() - 1);
+            changed = true;
+          }
+        }
+        etimes.clear();
+
+        if (changed)
+        {
+          // Perform heapsort
+          int i = array.size() - 1;
+          while (i > 0)
+          {
+            array.swap(i, 0);
+            array.siftDown(0, i - 1);
+            i--;
+          }
+          array.reverse();
+        }
+
+        // Now everything is ordered from smallest to largest
+        int index;
+        int i = 4;
+        for (final Double percent : percentiles)
+        {
+          if (array.size() <= 0)
+          {
+            strings[i++] = "-";
+          }
+          else
+          {
+            index = array.size()
+                - (int) Math.floor((percent / 100.0) * totalResultCount) - 1;
+            if (index < 0)
+            {
+              strings[i++] = String.format("*%.3f", array.get(0) / 1000000.0);
+            }
+            else
+            {
+              strings[i++] = String
+                  .format("%.3f", array.get(index) / 1000000.0);
+            }
+          }
+        }
+        strings[i++] = String.format("%.1f", failedCount / recentDuration);
+        if (isAsync)
+        {
+          if (resultCount > 0)
+          {
+            strings[i++] = String.format("%.1f", (double) operationCount
+                / resultCount);
+          }
+          else
+          {
+            strings[i++] = "-";
+          }
+        }
+        for (final String column : getAdditionalColumns())
+        {
+          strings[i++] = column;
+        }
+
+        if (printer != null)
+        {
+          printer.printRow(strings);
+        }
+        else
+        {
+          // Script-friendly.
+          app.getOutputStream().print(averageDuration);
+          for (final String s : strings)
+          {
+            app.getOutputStream().print(",");
+            app.getOutputStream().print(s);
+          }
+          app.getOutputStream().println();
+        }
+      }
+    }
+
+
+
+    String[] getAdditionalColumns()
+    {
+      return EMPTY_STRINGS;
+    }
+  }
+
+
+
+  /**
+   * Statistics update result handler implementation.
+   *
+   * @param <S>
+   *          The type of expected result.
+   */
+  class UpdateStatsResultHandler<S extends Result> implements ResultHandler<S>
+  {
+    private final long startTime;
+    private final AsynchronousConnection connection;
+    private final ConnectionWorker worker;
+
+
+
+    UpdateStatsResultHandler(final long startTime,
+        final AsynchronousConnection connection, final ConnectionWorker worker)
+    {
+      this.startTime = startTime;
+      this.connection = connection;
+      this.worker = worker;
+    }
+
+
+
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      failedRecentCount.getAndIncrement();
+      updateStats();
+
+      if (app.isVerbose())
+      {
+        app.println(LocalizableMessage.raw(error.getResult().toString()));
+      }
+
+      worker.operationCompleted(connection);
+    }
+
+
+
+    public void handleResult(final S result)
+    {
+      successRecentCount.getAndIncrement();
+      updateStats();
+      worker.operationCompleted(connection);
+    }
+
+
+
+    private void updateStats()
+    {
+      final long eTime = System.nanoTime() - startTime;
+      waitRecentTime.getAndAdd(eTime);
+      synchronized (this)
+      {
+        final ReversableArray array = eTimeBuffer.get();
+        if (array.remaining() == 0)
+        {
+          array.set(array.size() - 1, eTime);
+        }
+        else
+        {
+          array.append(eTime);
+        }
+      }
+    }
+  }
+
+
+
+  /**
+   * Worker thread base implementation.
+   */
+  abstract class WorkerThread extends Thread
+  {
+    private int count;
+
+    private final AsynchronousConnection connection;
+
+    private final ConnectionFactory connectionFactory;
+
+
+
+    WorkerThread(final AsynchronousConnection connection,
+        final ConnectionFactory connectionFactory)
+    {
+      super("Worker Thread");
+      this.connection = connection;
+      this.connectionFactory = connectionFactory;
+    }
+
+
+
+    public abstract FutureResult<?> performOperation(
+        AsynchronousConnection connection, DataSource[] dataSources,
+        long startTime);
+
+
+
+    @Override
+    public void run()
+    {
+      FutureResult<?> future;
+      AsynchronousConnection connection;
+
+      final double targetTimeInMS =
+        (1.0 / (targetThroughput / (double) (numConcurrentTasks * numConnections))) * 1000.0;
+      double sleepTimeInMS = 0;
+      long start;
+      while (!stopRequested && !(maxIterations > 0 && count >= maxIterations))
+      {
+        if (this.connection == null)
+        {
+          try
+          {
+            connection = connectionFactory.getAsynchronousConnection(null)
+                .get();
+          }
+          catch (final InterruptedException e)
+          {
+            // Ignore and check stop requested
+            continue;
+          }
+          catch (final ErrorResultException e)
+          {
+            app.println(LocalizableMessage.raw(e.getResult()
+                .getDiagnosticMessage()));
+            if (e.getCause() != null && app.isVerbose())
+            {
+              e.getCause().printStackTrace(app.getErrorStream());
+            }
+            stopRequested = true;
+            break;
+          }
+        }
+        else
+        {
+          connection = this.connection;
+          if (!noRebind
+              && connection instanceof AuthenticatedAsynchronousConnection)
+          {
+            final AuthenticatedAsynchronousConnection ac =
+              (AuthenticatedAsynchronousConnection) connection;
+            try
+            {
+              ac.rebind(null).get();
+            }
+            catch (final InterruptedException e)
+            {
+              // Ignore and check stop requested
+              continue;
+            }
+            catch (final ErrorResultException e)
+            {
+              app.println(LocalizableMessage.raw(e.getResult().toString()));
+              if (e.getCause() != null && app.isVerbose())
+              {
+                e.getCause().printStackTrace(app.getErrorStream());
+              }
+              stopRequested = true;
+              break;
+            }
+          }
+        }
+
+        start = System.nanoTime();
+        future = performOperation(connection, dataSources.get(), start);
+        operationRecentCount.getAndIncrement();
+        count++;
+        if (!isAsync)
+        {
+          try
+          {
+            future.get();
+          }
+          catch (final InterruptedException e)
+          {
+            // Ignore and check stop requested
+            continue;
+          }
+          catch (final ErrorResultException e)
+          {
+            if (e.getCause() instanceof IOException)
+            {
+              e.getCause().printStackTrace(app.getErrorStream());
+              stopRequested = true;
+              break;
+            }
+            // Ignore. Handled by result handler
+          }
+          finally
+          {
+            if (this.connection == null)
+            {
+              connection.close();
+            }
+          }
+        }
+        if (targetThroughput > 0)
+        {
+          try
+          {
+            if (sleepTimeInMS > 1)
+            {
+              sleep((long) Math.floor(sleepTimeInMS));
+            }
+          }
+          catch (final InterruptedException e)
+          {
+            continue;
+          }
+
+          sleepTimeInMS += targetTimeInMS
+              - ((System.nanoTime() - start) / 1000000.0);
+          if (sleepTimeInMS < -60000)
+          {
+            // If we fall behind by 60 seconds, just forget about
+            // catching up
+            sleepTimeInMS = -60000;
+          }
+        }
+      }
+    }
+  }
+
+
+
+  private static class ReversableArray
+  {
+    private final long[] array;
+
+    private boolean reversed;
+
+    private int size;
+
+
+
+    public ReversableArray(final int capacity)
+    {
+      this.array = new long[capacity];
+    }
+
+
+
+    public void append(final long value)
+    {
+      if (size == array.length)
+      {
+        throw new IndexOutOfBoundsException();
+      }
+
+      if (!reversed)
+      {
+        array[size] = value;
+      }
+      else
+      {
+        System.arraycopy(array, 0, array, 1, size);
+        array[0] = value;
+      }
+      size++;
+    }
+
+
+
+    public void append(final ReversableArray a, final int length)
+    {
+      if (length > a.size() || length > remaining())
+      {
+        throw new IndexOutOfBoundsException();
+      }
+      if (!reversed)
+      {
+        System.arraycopy(a.array, 0, array, size, length);
+      }
+      else
+      {
+        System.arraycopy(array, 0, array, length, size);
+        System.arraycopy(a.array, 0, array, 0, length);
+      }
+      size += length;
+    }
+
+
+
+    public void clear()
+    {
+      size = 0;
+    }
+
+
+
+    public long get(final int index)
+    {
+      if (index >= size)
+      {
+        throw new IndexOutOfBoundsException();
+      }
+      if (!reversed)
+      {
+        return array[index];
+      }
+      else
+      {
+        return array[size - index - 1];
+      }
+    }
+
+
+
+    public int remaining()
+    {
+      return array.length - size;
+    }
+
+
+
+    public void reverse()
+    {
+      reversed = !reversed;
+    }
+
+
+
+    public void set(final int index, final long value)
+    {
+      if (index >= size)
+      {
+        throw new IndexOutOfBoundsException();
+      }
+      if (!reversed)
+      {
+        array[index] = value;
+      }
+      else
+      {
+        array[size - index - 1] = value;
+      }
+    }
+
+
+
+    public void siftDown(final int start, final int end)
+    {
+      int root = start;
+      int child;
+      while (root * 2 + 1 <= end)
+      {
+        child = root * 2 + 1;
+        if (child + 1 <= end && get(child) > get(child + 1))
+        {
+          child = child + 1;
+        }
+        if (get(root) > get(child))
+        {
+          swap(root, child);
+          root = child;
+        }
+        else
+        {
+          return;
+        }
+      }
+    }
+
+
+
+    public void siftUp(final int start, final int end)
+    {
+      int child = end;
+      int parent;
+      while (child > start)
+      {
+        parent = (int) Math.floor((child - 1) / 2.0);
+        if (get(parent) > get(child))
+        {
+          swap(parent, child);
+          child = parent;
+        }
+        else
+        {
+          return;
+        }
+      }
+    }
+
+
+
+    public int size()
+    {
+      return size;
+    }
+
+
+
+    private void swap(final int i, final int i2)
+    {
+      final long temp = get(i);
+      set(i, get(i2));
+      set(i2, temp);
+    }
+  }
+
+
+
+  private static final String[] EMPTY_STRINGS = new String[0];
+
+  private final AtomicInteger operationRecentCount = new AtomicInteger();
+
+  protected final AtomicInteger successRecentCount = new AtomicInteger();
+
+  protected final AtomicInteger failedRecentCount = new AtomicInteger();
+
+  private final AtomicLong waitRecentTime = new AtomicLong();
+
+  private final AtomicReference<ReversableArray> eTimeBuffer = new AtomicReference<ReversableArray>(
+      new ReversableArray(100000));
+
+  private final ConsoleApplication app;
+
+  private DataSource[] dataSourcePrototypes;
+
+  // Thread local copies of the data sources
+  private final ThreadLocal<DataSource[]> dataSources = new ThreadLocal<DataSource[]>()
+  {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected DataSource[] initialValue()
+    {
+      final DataSource[] prototypes = getDataSources();
+      final int sz = prototypes.length;
+      final DataSource[] threadLocalCopy = new DataSource[sz];
+      for (int i = 0; i < sz; i++)
+      {
+        threadLocalCopy[i] = prototypes[i].duplicate();
+      }
+      return threadLocalCopy;
+    }
+
+  };
+
+  private volatile boolean stopRequested;
+
+  private int numConcurrentTasks;
+
+  private int numConnections;
+
+  private int targetThroughput;
+
+  private int maxIterations;
+
+  private boolean isAsync;
+
+  private boolean noRebind;
+
+  private int statsInterval;
+
+  private double targetTimeInMS;
+
+  private final IntegerArgument numConcurrentTasksArgument;
+
+  private final IntegerArgument maxIterationsArgument;
+
+  private final IntegerArgument statsIntervalArgument;
+
+  private final IntegerArgument targetThroughputArgument;
+
+  private final IntegerArgument numConnectionsArgument;
+
+  private final IntegerArgument percentilesArgument;
+
+  private final BooleanArgument keepConnectionsOpen;
+
+  private final BooleanArgument noRebindArgument;
+
+  private final BooleanArgument asyncArgument;
+
+  private final StringArgument arguments;
+
+
+
+  PerformanceRunner(final ArgumentParser argParser,
+      final ConsoleApplication app, final boolean neverRebind,
+      final boolean neverAsynchronous, final boolean alwaysSingleThreaded)
+      throws ArgumentException
+  {
+    this.app = app;
+    numConcurrentTasksArgument = new IntegerArgument("numConcurrentTasks", 't',
+        "numConcurrentTasks", false, false, true,
+        LocalizableMessage.raw("{numConcurrentTasks}"), 1, null, true, 1,
+        false, 0,
+        LocalizableMessage.raw("Number of concurrent tasks per connection"));
+    numConcurrentTasksArgument.setPropertyName("numConcurrentTasks");
+    if (!alwaysSingleThreaded)
+    {
+      argParser.addArgument(numConcurrentTasksArgument);
+    }
+    else
+    {
+      numConcurrentTasksArgument.addValue("1");
+    }
+
+    numConnectionsArgument = new IntegerArgument("numConnections", 'c',
+        "numConnections", false, false, true,
+        LocalizableMessage.raw("{numConnections}"), 1, null, true, 1, false, 0,
+        LocalizableMessage.raw("Number of connections"));
+    numConnectionsArgument.setPropertyName("numConnections");
+    argParser.addArgument(numConnectionsArgument);
+
+    maxIterationsArgument = new IntegerArgument("maxIterations", 'm',
+        "maxIterations", false, false, true,
+        LocalizableMessage.raw("{maxIterations}"), 0, null,
+        LocalizableMessage.raw("Max iterations, 0 for unlimited"));
+    maxIterationsArgument.setPropertyName("maxIterations");
+    argParser.addArgument(maxIterationsArgument);
+
+    statsIntervalArgument = new IntegerArgument("statInterval", 'i',
+        "statInterval", false, false, true,
+        LocalizableMessage.raw("{statInterval}"), 5, null, true, 1, false, 0,
+        LocalizableMessage
+            .raw("Display results each specified number of seconds"));
+    statsIntervalArgument.setPropertyName("statInterval");
+    argParser.addArgument(statsIntervalArgument);
+
+    targetThroughputArgument = new IntegerArgument("targetThroughput", 'M',
+        "targetThroughput", false, false, true,
+        LocalizableMessage.raw("{targetThroughput}"), 0, null,
+        LocalizableMessage.raw("Target average throughput to achieve"));
+    targetThroughputArgument.setPropertyName("targetThroughput");
+    argParser.addArgument(targetThroughputArgument);
+
+    percentilesArgument = new IntegerArgument("percentile", 'e', "percentile",
+        false, true, LocalizableMessage.raw("{percentile}"), true, 0, true,
+        100, LocalizableMessage.raw("Calculate max response time for a "
+            + "percentile of operations"));
+    percentilesArgument.setPropertyName("percentile");
+    percentilesArgument.setMultiValued(true);
+    argParser.addArgument(percentilesArgument);
+
+    keepConnectionsOpen = new BooleanArgument("keepConnectionsOpen", 'f',
+        "keepConnectionsOpen", LocalizableMessage.raw("Keep connections open"));
+    keepConnectionsOpen.setPropertyName("keepConnectionsOpen");
+    argParser.addArgument(keepConnectionsOpen);
+
+    noRebindArgument = new BooleanArgument("noRebind", 'F', "noRebind",
+        LocalizableMessage.raw("Keep connections open and don't rebind"));
+    noRebindArgument.setPropertyName("noRebind");
+    if (!neverRebind)
+    {
+      argParser.addArgument(noRebindArgument);
+    }
+    else
+    {
+      noRebindArgument.addValue(String.valueOf(true));
+    }
+
+    asyncArgument = new BooleanArgument("asynchronous", 'A', "asynchronous",
+        LocalizableMessage.raw("Use asynchronous mode and don't "
+            + "wait for results before sending the next request"));
+    asyncArgument.setPropertyName("asynchronous");
+    if (!neverAsynchronous)
+    {
+      argParser.addArgument(asyncArgument);
+    }
+
+    arguments = new StringArgument(
+        "argument",
+        'g',
+        "argument",
+        false,
+        true,
+        true,
+        LocalizableMessage.raw("{generator function or static string}"),
+        null,
+        null,
+        LocalizableMessage.raw("Argument used to evaluate the Java "
+            + "style format strings in program parameters (ie. Base DN, "
+            + "Search Filter). The set of all arguments provided form the "
+            + "the argument list in order. Besides static string "
+            + "arguments, they can be generated per iteration with the "
+            + "following functions: " + StaticUtils.EOL + DataSource.getUsage()));
+    argParser.addArgument(arguments);
+  }
+
+
+
+  public void handleConnectionClosed()
+  {
+    // Ignore
+  }
+
+
+
+  public synchronized void handleConnectionError(
+      final boolean isDisconnectNotification, final ErrorResultException error)
+  {
+    if (!stopRequested)
+    {
+      app.println(LocalizableMessage.raw("Error occurred on one or more "
+          + "connections: " + error.getResult().toString()));
+      if (error.getCause() != null && app.isVerbose())
+      {
+        error.getCause().printStackTrace(app.getErrorStream());
+      }
+      stopRequested = true;
+    }
+  }
+
+
+
+  public void handleUnsolicitedNotification(final ExtendedResult notification)
+  {
+    // Ignore
+  }
+
+
+
+  public final void validate() throws ArgumentException
+  {
+    numConnections = numConnectionsArgument.getIntValue();
+    numConcurrentTasks = numConcurrentTasksArgument.getIntValue();
+    maxIterations = maxIterationsArgument.getIntValue() / numConnections;
+    statsInterval = statsIntervalArgument.getIntValue() * 1000;
+    targetThroughput = targetThroughputArgument.getIntValue();
+
+    isAsync = asyncArgument.isPresent();
+    noRebind = noRebindArgument.isPresent();
+
+    if (!noRebindArgument.isPresent() && this.numConcurrentTasks > 1)
+    {
+      throw new ArgumentException(LocalizableMessage.raw("--"
+          + noRebindArgument.getLongIdentifier() + " must be used if --"
+          + numConcurrentTasksArgument.getLongIdentifier() + " is > 1"));
+    }
+
+    if (!noRebindArgument.isPresent() && asyncArgument.isPresent())
+    {
+      throw new ArgumentException(LocalizableMessage.raw("--"
+          + noRebindArgument.getLongIdentifier()
+          + " must be used when using --" + asyncArgument.getLongIdentifier()));
+    }
+
+    dataSourcePrototypes = DataSource.parse(arguments.getValues());
+
+    targetTimeInMS =
+      (1.0 / (targetThroughput / (double) (numConcurrentTasks * numConnections))) * 1000.0;
+  }
+
+
+
+  final DataSource[] getDataSources()
+  {
+    if (dataSourcePrototypes == null)
+    {
+      throw new IllegalStateException(
+          "dataSources are null - validate() must be called first");
+    }
+    return dataSourcePrototypes;
+  }
+
+
+
+  abstract ConnectionWorker newConnectionWorker(
+      final AsynchronousConnection connection,
+      final ConnectionFactory connectionFactory);
+
+
+
+  abstract StatsThread newStatsThread();
+
+
+
+  final int run(final ConnectionFactory connectionFactory)
+  {
+    final List<ConnectionWorker> workers = new ArrayList<ConnectionWorker>();
+    final List<AsynchronousConnection> connections = new ArrayList<AsynchronousConnection>();
+
+    AsynchronousConnection connection = null;
+    try
+    {
+      for (int i = 0; i < numConnections; i++)
+      {
+        if (keepConnectionsOpen.isPresent() || noRebindArgument.isPresent())
+        {
+          connection = connectionFactory.getAsynchronousConnection(null).get();
+          connection.addConnectionEventListener(this);
+          connections.add(connection);
+        }
+        final ConnectionWorker worker = newConnectionWorker(connection,
+            connectionFactory);
+        workers.add(worker);
+        worker.startWork();
+      }
+
+      final Thread statsThread = newStatsThread();
+      statsThread.start();
+
+      for (final ConnectionWorker w : workers)
+      {
+        w.waitFor();
+      }
+      stopRequested = true;
+      statsThread.join();
+    }
+    catch (final InterruptedException e)
+    {
+      stopRequested = true;
+    }
+    catch (final ErrorResultException e)
+    {
+      stopRequested = true;
+      app.println(LocalizableMessage.raw(e.getResult().getDiagnosticMessage()));
+    }
+    finally
+    {
+      for (final AsynchronousConnection c : connections)
+      {
+        c.close();
+      }
+    }
+
+    return 0;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PromptingTrustManager.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PromptingTrustManager.java
new file mode 100644
index 0000000..53d55ca
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/PromptingTrustManager.java
@@ -0,0 +1,482 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2008-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A trust manager which prompts the user for the length of time that they would
+ * like to trust a server certificate.
+ */
+final class PromptingTrustManager implements X509TrustManager
+{
+  /**
+   * Enumeration description server certificate trust option.
+   */
+  private static enum TrustOption
+  {
+    UNTRUSTED(1, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_NO.get()), SESSION(
+        2, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_SESSION.get()), PERMANENT(
+        3, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_ALWAYS.get()), CERTIFICATE_DETAILS(
+        4, INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_DETAILS.get());
+
+    private Integer choice;
+
+    private LocalizableMessage msg;
+
+
+
+    /**
+     * Private constructor.
+     *
+     * @param i
+     *          the menu return value.
+     * @param msg
+     *          the message message.
+     */
+    private TrustOption(final int i, final LocalizableMessage msg)
+    {
+      choice = i;
+      this.msg = msg;
+    }
+
+
+
+    /**
+     * Returns the choice number.
+     *
+     * @return the attribute name.
+     */
+    Integer getChoice()
+    {
+      return choice;
+    }
+
+
+
+    /**
+     * Return the menu message.
+     *
+     * @return the menu message.
+     */
+    LocalizableMessage getMenuMessage()
+    {
+      return msg;
+    }
+  }
+
+
+
+  static private final Logger LOG = Logger
+      .getLogger(PromptingTrustManager.class.getName());
+
+  static private final String DEFAULT_PATH = System.getProperty("user.home")
+      + File.separator + ".opends" + File.separator + "keystore";
+
+  static private final char[] DEFAULT_PASSWORD = "OpenDS".toCharArray();
+
+  private final KeyStore inMemoryTrustStore;
+
+  private final KeyStore onDiskTrustStore;
+
+  private final X509TrustManager inMemoryTrustManager;
+
+  private final X509TrustManager onDiskTrustManager;
+
+  private final X509TrustManager nestedTrustManager;
+
+  private final ConsoleApplication app;
+
+
+
+  PromptingTrustManager(final ConsoleApplication app,
+      final String acceptedStorePath, final X509TrustManager sourceTrustManager)
+      throws KeyStoreException, IOException, NoSuchAlgorithmException,
+      CertificateException
+  {
+    Validator.ensureNotNull(app, acceptedStorePath);
+    this.app = app;
+    this.nestedTrustManager = sourceTrustManager;
+    inMemoryTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+    onDiskTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+
+    final File onDiskTrustStorePath = new File(acceptedStorePath);
+    inMemoryTrustStore.load(null, null);
+    if (!onDiskTrustStorePath.exists())
+    {
+      onDiskTrustStore.load(null, null);
+    }
+    else
+    {
+      final FileInputStream fos = new FileInputStream(onDiskTrustStorePath);
+      try
+      {
+        onDiskTrustStore.load(fos, DEFAULT_PASSWORD);
+      }
+      finally
+      {
+        fos.close();
+      }
+    }
+    final TrustManagerFactory tmf = TrustManagerFactory
+        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
+
+    tmf.init(inMemoryTrustStore);
+    X509TrustManager x509tm = null;
+    for (final TrustManager tm : tmf.getTrustManagers())
+    {
+      if (tm instanceof X509TrustManager)
+      {
+        x509tm = (X509TrustManager) tm;
+        break;
+      }
+    }
+    if (x509tm == null)
+    {
+      throw new NoSuchAlgorithmException();
+    }
+    this.inMemoryTrustManager = x509tm;
+
+    tmf.init(onDiskTrustStore);
+    x509tm = null;
+    for (final TrustManager tm : tmf.getTrustManagers())
+    {
+      if (tm instanceof X509TrustManager)
+      {
+        x509tm = (X509TrustManager) tm;
+        break;
+      }
+    }
+    if (x509tm == null)
+    {
+      throw new NoSuchAlgorithmException();
+    }
+    this.onDiskTrustManager = x509tm;
+  }
+
+
+
+  PromptingTrustManager(final ConsoleApplication app,
+      final X509TrustManager sourceTrustManager) throws KeyStoreException,
+      IOException, NoSuchAlgorithmException, CertificateException
+  {
+    this(app, DEFAULT_PATH, sourceTrustManager);
+  }
+
+
+
+  public void checkClientTrusted(final X509Certificate[] x509Certificates,
+      final String s) throws CertificateException
+  {
+    try
+    {
+      inMemoryTrustManager.checkClientTrusted(x509Certificates, s);
+    }
+    catch (final Exception ce1)
+    {
+      try
+      {
+        onDiskTrustManager.checkClientTrusted(x509Certificates, s);
+      }
+      catch (final Exception ce2)
+      {
+        if (nestedTrustManager != null)
+        {
+          try
+          {
+            nestedTrustManager.checkClientTrusted(x509Certificates, s);
+          }
+          catch (final Exception ce3)
+          {
+            checkManuallyTrusted(x509Certificates, ce3);
+          }
+        }
+        else
+        {
+          checkManuallyTrusted(x509Certificates, ce1);
+        }
+      }
+    }
+  }
+
+
+
+  public void checkServerTrusted(final X509Certificate[] x509Certificates,
+      final String s) throws CertificateException
+  {
+    try
+    {
+      inMemoryTrustManager.checkServerTrusted(x509Certificates, s);
+    }
+    catch (final Exception ce1)
+    {
+      try
+      {
+        onDiskTrustManager.checkServerTrusted(x509Certificates, s);
+      }
+      catch (final Exception ce2)
+      {
+        if (nestedTrustManager != null)
+        {
+          try
+          {
+            nestedTrustManager.checkServerTrusted(x509Certificates, s);
+          }
+          catch (final Exception ce3)
+          {
+            checkManuallyTrusted(x509Certificates, ce3);
+          }
+        }
+        else
+        {
+          checkManuallyTrusted(x509Certificates, ce1);
+        }
+      }
+    }
+  }
+
+
+
+  public X509Certificate[] getAcceptedIssuers()
+  {
+    if (nestedTrustManager != null)
+    {
+      return nestedTrustManager.getAcceptedIssuers();
+    }
+    return new X509Certificate[0];
+  }
+
+
+
+  /**
+   * This method is called when the user accepted a certificate.
+   *
+   * @param chain
+   *          the certificate chain accepted by the user. certificate.
+   */
+  private void acceptCertificate(final X509Certificate[] chain,
+      final boolean permanent)
+  {
+    if (permanent)
+    {
+      LOG.log(Level.INFO, "Permanently accepting certificate chain to "
+          + "truststore");
+    }
+    else
+    {
+      LOG.log(Level.INFO, "Accepting certificate chain for this session");
+    }
+
+    for (final X509Certificate aChain : chain)
+    {
+      try
+      {
+        final String alias = aChain.getSubjectDN().getName();
+        inMemoryTrustStore.setCertificateEntry(alias, aChain);
+        if (permanent)
+        {
+          onDiskTrustStore.setCertificateEntry(alias, aChain);
+        }
+      }
+      catch (final Exception e)
+      {
+        LOG.log(Level.WARNING, "Error setting certificate to store: " + e
+            + "\nCert: " + aChain.toString());
+      }
+    }
+
+    if (permanent)
+    {
+      try
+      {
+        final File truststoreFile = new File(DEFAULT_PATH);
+        if (!truststoreFile.exists())
+        {
+          createFile(truststoreFile);
+        }
+        final FileOutputStream fos = new FileOutputStream(truststoreFile);
+        onDiskTrustStore.store(fos, DEFAULT_PASSWORD);
+        fos.close();
+      }
+      catch (final Exception e)
+      {
+        LOG.log(Level.WARNING, "Error saving store to disk: " + e);
+      }
+    }
+  }
+
+
+
+  /**
+   * Indicate if the certificate chain can be trusted.
+   *
+   * @param chain
+   *          The certificate chain to validate certificate.
+   */
+  private void checkManuallyTrusted(final X509Certificate[] chain,
+      final Exception exception) throws CertificateException
+  {
+    app.println();
+    app.println(INFO_LDAP_CONN_PROMPT_SECURITY_SERVER_CERTIFICATE.get());
+    app.println();
+    for (final X509Certificate element : chain)
+    {
+      // Certificate DN
+      app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_USER_DN
+          .get(element.getSubjectDN().toString()));
+
+      // certificate validity
+      app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_VALIDITY.get(
+          element.getNotBefore().toString(), element.getNotAfter().toString()));
+
+      // certificate Issuer
+      app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_ISSUER.get(element
+          .getIssuerDN().toString()));
+
+      app.println();
+      app.println();
+    }
+
+    app.println();
+    app.println(INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION.get());
+    app.println();
+
+    final Map<String, TrustOption> menuOptions = new HashMap<String, TrustOption>();
+    for (final TrustOption t : TrustOption.values())
+    {
+      menuOptions.put(t.getChoice().toString(), t);
+
+      final LocalizableMessageBuilder builder = new LocalizableMessageBuilder();
+      builder.append(t.getChoice());
+      builder.append(") ");
+      builder.append(t.getMenuMessage());
+      app.println(builder.toMessage(), 2 /* Indent options */);
+    }
+
+    final TrustOption defaultTrustMethod = TrustOption.SESSION;
+    final LocalizableMessage promptMsg = INFO_MENU_PROMPT_SINGLE.get();
+
+    while (true)
+    {
+      app.println();
+      String choice;
+      try
+      {
+        choice = app.readInput(promptMsg, defaultTrustMethod.getChoice()
+            .toString());
+      }
+      catch (final CLIException e)
+      {
+        // What can we do here?
+        throw new CertificateException(exception);
+      }
+      finally
+      {
+        app.println();
+      }
+
+      final TrustOption option = menuOptions.get(choice.trim());
+      if (option == null)
+      {
+        app.println(ERR_MENU_BAD_CHOICE_SINGLE.get());
+        app.println();
+        continue;
+      }
+
+      switch (option)
+      {
+      case UNTRUSTED:
+        if (exception instanceof CertificateException)
+        {
+          throw (CertificateException) exception;
+        }
+        else
+        {
+          throw new CertificateException(exception);
+        }
+      case CERTIFICATE_DETAILS:
+        for (final X509Certificate aChain : chain)
+        {
+          app.println();
+          app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE.get(aChain
+              .toString()));
+          app.println();
+        }
+        break;
+      default: // SESSION / PERMANENT.
+        // Update the trust manager with the new certificate
+        acceptCertificate(chain, option == TrustOption.PERMANENT);
+        return;
+      }
+    }
+  }
+
+
+
+  private boolean createFile(final File f) throws IOException
+  {
+    boolean success = false;
+    if (f != null)
+    {
+      final File parent = f.getParentFile();
+      if (!parent.exists())
+      {
+        parent.mkdirs();
+      }
+      success = f.createNewFile();
+    }
+    return success;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/SearchRate.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/SearchRate.java
new file mode 100644
index 0000000..8ee12d6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/SearchRate.java
@@ -0,0 +1,525 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.tools.ToolConstants.*;
+import static com.sun.opends.sdk.tools.Utils.filterExitCode;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.glassfish.grizzly.TransportFactory;
+import org.opends.sdk.*;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.responses.SearchResultReference;
+
+
+
+/**
+ * A load generation tool that can be used to load a Directory Server with
+ * Search requests using one or more LDAP connections.
+ */
+public final class SearchRate extends ConsoleApplication
+{
+  private final class SearchPerformanceRunner extends PerformanceRunner
+  {
+    private final class SearchStatsHandler extends
+        UpdateStatsResultHandler<Result> implements SearchResultHandler
+    {
+      private SearchStatsHandler(final long startTime,
+          final AsynchronousConnection connection, final ConnectionWorker worker)
+      {
+        super(startTime, connection, worker);
+      }
+
+
+
+      @Override
+      public boolean handleEntry(final SearchResultEntry entry)
+      {
+        entryRecentCount.getAndIncrement();
+        return true;
+      }
+
+
+
+      @Override
+      public boolean handleReference(final SearchResultReference reference)
+      {
+        return true;
+      }
+    }
+
+
+
+    private final class SearchStatsThread extends StatsThread
+    {
+      private final String[] extraColumn;
+
+
+
+      private SearchStatsThread()
+      {
+        super(new String[] { "Entries/Srch" });
+        extraColumn = new String[1];
+      }
+
+
+
+      @Override
+      String[] getAdditionalColumns()
+      {
+        final int entryCount = entryRecentCount.getAndSet(0);
+        if (successCount > 0)
+        {
+          extraColumn[0] = String.format("%.1f", (double) entryCount
+              / successCount);
+        }
+        else
+        {
+          extraColumn[0] = String.format("%.1f", 0.0);
+        }
+        return extraColumn;
+      }
+    }
+
+
+
+    private final class SearchWorkerThread extends ConnectionWorker
+    {
+      private SearchRequest sr;
+
+      private Object[] data;
+
+
+
+      private SearchWorkerThread(final AsynchronousConnection connection,
+          final ConnectionFactory connectionFactory)
+      {
+        super(connection, connectionFactory);
+      }
+
+
+
+      @Override
+      public FutureResult<?> performOperation(
+          final AsynchronousConnection connection,
+          final DataSource[] dataSources, final long startTime)
+      {
+        if (sr == null)
+        {
+          if (dataSources == null)
+          {
+            sr = Requests.newSearchRequest(baseDN, scope, filter, attributes);
+          }
+          else
+          {
+            data = DataSource.generateData(dataSources, data);
+            sr = Requests.newSearchRequest(String.format(baseDN, data), scope,
+                String.format(filter, data), attributes);
+          }
+          sr.setDereferenceAliasesPolicy(dereferencesAliasesPolicy);
+        }
+        else if (dataSources != null)
+        {
+          data = DataSource.generateData(dataSources, data);
+          sr.setFilter(String.format(filter, data));
+          sr.setName(String.format(baseDN, data));
+        }
+        return connection.search(sr, new SearchStatsHandler(startTime,
+            connection, this));
+      }
+    }
+
+
+
+    private String filter;
+
+    private String baseDN;
+
+    private SearchScope scope;
+
+    private DereferenceAliasesPolicy dereferencesAliasesPolicy;
+
+    private String[] attributes;
+
+
+
+    private SearchPerformanceRunner(final ArgumentParser argParser,
+        final ConsoleApplication app) throws ArgumentException
+    {
+      super(argParser, app, false, false, false);
+    }
+
+
+
+    @Override
+    ConnectionWorker newConnectionWorker(
+        final AsynchronousConnection connection,
+        final ConnectionFactory connectionFactory)
+    {
+      return new SearchWorkerThread(connection, connectionFactory);
+    }
+
+
+
+    @Override
+    StatsThread newStatsThread()
+    {
+      return new SearchStatsThread();
+    }
+  }
+
+
+
+  /**
+   * The main method for SearchRate tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   */
+
+  public static void main(final String[] args)
+  {
+    final int retCode = mainSearchRate(args, System.in, System.out, System.err);
+    System.exit(filterExitCode(retCode));
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the ldapsearch tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @return The error code.
+   */
+
+  static int mainSearchRate(final String[] args)
+  {
+    return mainSearchRate(args, System.in, System.out, System.err);
+  }
+
+
+
+  /**
+   * Parses the provided command-line arguments and uses that information to run
+   * the ldapsearch tool.
+   *
+   * @param args
+   *          The command-line arguments provided to this program.
+   * @param inStream
+   *          The input stream to use for standard input, or <CODE>null</CODE>
+   *          if standard input is not needed.
+   * @param outStream
+   *          The output stream to use for standard output, or <CODE>null</CODE>
+   *          if standard output is not needed.
+   * @param errStream
+   *          The output stream to use for standard error, or <CODE>null</CODE>
+   *          if standard error is not needed.
+   * @return The error code.
+   */
+
+  static int mainSearchRate(final String[] args, final InputStream inStream,
+      final OutputStream outStream, final OutputStream errStream)
+
+  {
+    return new SearchRate(inStream, outStream, errStream).run(args);
+  }
+
+
+
+  private BooleanArgument verbose;
+
+  private BooleanArgument scriptFriendly;
+
+  private final AtomicInteger entryRecentCount = new AtomicInteger();
+
+
+
+  private SearchRate(final InputStream in, final OutputStream out,
+      final OutputStream err)
+  {
+    super(in, out, err);
+
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested advanced mode.
+   *
+   * @return Returns <code>true</code> if the user has requested advanced mode.
+   */
+  @Override
+  public boolean isAdvancedMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested interactive behavior.
+   *
+   * @return Returns <code>true</code> if the user has requested interactive
+   *         behavior.
+   */
+  @Override
+  public boolean isInteractive()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not this console application is running in its
+   * menu-driven mode. This can be used to dictate whether output should go to
+   * the error stream or not. In addition, it may also dictate whether or not
+   * sub-menus should display a cancel option as well as a quit option.
+   *
+   * @return Returns <code>true</code> if this console application is running in
+   *         its menu-driven mode.
+   */
+  @Override
+  public boolean isMenuDrivenMode()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested quiet output.
+   *
+   * @return Returns <code>true</code> if the user has requested quiet output.
+   */
+  @Override
+  public boolean isQuiet()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested script-friendly output.
+   *
+   * @return Returns <code>true</code> if the user has requested script-friendly
+   *         output.
+   */
+  @Override
+  public boolean isScriptFriendly()
+  {
+    return scriptFriendly.isPresent();
+  }
+
+
+
+  /**
+   * Indicates whether or not the user has requested verbose output.
+   *
+   * @return Returns <code>true</code> if the user has requested verbose output.
+   */
+  @Override
+  public boolean isVerbose()
+  {
+    return verbose.isPresent();
+  }
+
+
+
+  private int run(final String[] args)
+  {
+    // Create the command-line argument parser for use with this
+    // program.
+    final LocalizableMessage toolDescription = INFO_SEARCHRATE_TOOL_DESCRIPTION
+        .get();
+    final ArgumentParser argParser = new ArgumentParser(
+        SearchRate.class.getName(), toolDescription, false, true, 1, 0,
+        "[filter format string] [attributes ...]");
+
+    ConnectionFactoryProvider connectionFactoryProvider;
+    ConnectionFactory connectionFactory;
+    SearchPerformanceRunner runner;
+
+    StringArgument baseDN;
+    MultiChoiceArgument<SearchScope> searchScope;
+    MultiChoiceArgument<DereferenceAliasesPolicy> dereferencePolicy;
+    BooleanArgument showUsage;
+    StringArgument propertiesFileArgument;
+    BooleanArgument noPropertiesFileArgument;
+
+    try
+    {
+      TransportFactory.setInstance(new PerfToolTCPNIOTransportFactory());
+      connectionFactoryProvider = new ConnectionFactoryProvider(argParser, this);
+      runner = new SearchPerformanceRunner(argParser, this);
+
+      propertiesFileArgument = new StringArgument("propertiesFilePath", null,
+          OPTION_LONG_PROP_FILE_PATH, false, false, true,
+          INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null,
+          INFO_DESCRIPTION_PROP_FILE_PATH.get());
+      argParser.addArgument(propertiesFileArgument);
+      argParser.setFilePropertiesArgument(propertiesFileArgument);
+
+      noPropertiesFileArgument = new BooleanArgument(
+          "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE,
+          INFO_DESCRIPTION_NO_PROP_FILE.get());
+      argParser.addArgument(noPropertiesFileArgument);
+      argParser.setNoPropertiesFileArgument(noPropertiesFileArgument);
+
+      showUsage = new BooleanArgument("showUsage", OPTION_SHORT_HELP,
+          OPTION_LONG_HELP, INFO_DESCRIPTION_SHOWUSAGE.get());
+      argParser.addArgument(showUsage);
+      argParser.setUsageArgument(showUsage, getOutputStream());
+
+      baseDN = new StringArgument("baseDN", OPTION_SHORT_BASEDN,
+          OPTION_LONG_BASEDN, true, false, true, INFO_BASEDN_PLACEHOLDER.get(),
+          null, null, INFO_SEARCHRATE_TOOL_DESCRIPTION_BASEDN.get());
+      baseDN.setPropertyName(OPTION_LONG_BASEDN);
+      argParser.addArgument(baseDN);
+
+      searchScope = new MultiChoiceArgument<SearchScope>("searchScope", 's',
+          "searchScope", false, true, INFO_SEARCH_SCOPE_PLACEHOLDER.get(),
+          SearchScope.values(), false,
+          INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE.get());
+      searchScope.setPropertyName("searchScope");
+      searchScope.setDefaultValue(SearchScope.WHOLE_SUBTREE);
+      argParser.addArgument(searchScope);
+
+      dereferencePolicy = new MultiChoiceArgument<DereferenceAliasesPolicy>(
+          "derefpolicy", 'a', "dereferencePolicy", false, true,
+          INFO_DEREFERENCE_POLICE_PLACEHOLDER.get(),
+          DereferenceAliasesPolicy.values(), false,
+          INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY.get());
+      dereferencePolicy.setPropertyName("dereferencePolicy");
+      dereferencePolicy.setDefaultValue(DereferenceAliasesPolicy.NEVER);
+      argParser.addArgument(dereferencePolicy);
+
+      verbose = new BooleanArgument("verbose", 'v', "verbose",
+          INFO_DESCRIPTION_VERBOSE.get());
+      verbose.setPropertyName("verbose");
+      argParser.addArgument(verbose);
+
+      scriptFriendly = new BooleanArgument("scriptFriendly", 'S',
+          "scriptFriendly", INFO_DESCRIPTION_SCRIPT_FRIENDLY.get());
+      scriptFriendly.setPropertyName("scriptFriendly");
+      argParser.addArgument(scriptFriendly);
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_CANNOT_INITIALIZE_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    // Parse the command-line arguments provided to this program.
+    try
+    {
+      argParser.parseArguments(args);
+
+      // If we should just display usage or version information,
+      // then print it and exit.
+      if (argParser.usageOrVersionDisplayed())
+      {
+        return 0;
+      }
+
+      connectionFactory = connectionFactoryProvider
+          .getAuthenticatedConnectionFactory();
+      runner.validate();
+    }
+    catch (final ArgumentException ae)
+    {
+      final LocalizableMessage message = ERR_ERROR_PARSING_ARGS.get(ae
+          .getMessage());
+      println(message);
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    final List<String> attributes = new LinkedList<String>();
+    final ArrayList<String> filterAndAttributeStrings = argParser
+        .getTrailingArguments();
+    if (filterAndAttributeStrings.size() > 0)
+    {
+      // the list of trailing arguments should be structured as follow:
+      // the first trailing argument is
+      // considered the filter, the other as attributes.
+      runner.filter = filterAndAttributeStrings.remove(0);
+      // The rest are attributes
+      for (final String s : filterAndAttributeStrings)
+      {
+        attributes.add(s);
+      }
+    }
+    runner.attributes = attributes.toArray(new String[attributes.size()]);
+    runner.baseDN = baseDN.getValue();
+    try
+    {
+      runner.scope = searchScope.getTypedValue();
+      runner.dereferencesAliasesPolicy = dereferencePolicy.getTypedValue();
+    }
+    catch (final ArgumentException ex1)
+    {
+      println(ex1.getMessageObject());
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    try
+    {
+      // Try it out to make sure the format string and data sources
+      // match.
+      final Object[] data = DataSource.generateData(runner.getDataSources(),
+          null);
+      String.format(runner.filter, data);
+      String.format(runner.baseDN, data);
+    }
+    catch (final Exception ex1)
+    {
+      println(LocalizableMessage.raw("Error formatting filter or base DN: "
+          + ex1.toString()));
+      return ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue();
+    }
+
+    return runner.run(connectionFactory);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/StringArgument.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/StringArgument.java
new file mode 100644
index 0000000..0c07572
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/StringArgument.java
@@ -0,0 +1,147 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines an argument type that will accept any string value.
+ */
+final class StringArgument extends Argument
+{
+  /**
+   * Creates a new string argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param isMultiValued
+   *          Indicates whether this argument may be specified more than once to
+   *          provide multiple values.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param defaultValue
+   *          The default value that should be used for this argument if none is
+   *          provided in a properties file or on the command line. This may be
+   *          <CODE>null</CODE> if there is no generic default.
+   * @param propertyName
+   *          The name of the property in a property file that may be used to
+   *          override the default value but will be overridden by a
+   *          command-line argument.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public StringArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean isMultiValued, final boolean needsValue,
+      final LocalizableMessage valuePlaceholder, final String defaultValue,
+      final String propertyName, final LocalizableMessage description)
+      throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, isMultiValued,
+        needsValue, valuePlaceholder, defaultValue, propertyName, description);
+  }
+
+
+
+  /**
+   * Creates a new string argument with the provided information.
+   *
+   * @param name
+   *          The generic name that should be used to refer to this argument.
+   * @param shortIdentifier
+   *          The single-character identifier for this argument, or
+   *          <CODE>null</CODE> if there is none.
+   * @param longIdentifier
+   *          The long identifier for this argument, or <CODE>null</CODE> if
+   *          there is none.
+   * @param isRequired
+   *          Indicates whether this argument must be specified on the command
+   *          line.
+   * @param needsValue
+   *          Indicates whether this argument requires a value.
+   * @param valuePlaceholder
+   *          The placeholder for the argument value that will be displayed in
+   *          usage information, or <CODE>null</CODE> if this argument does not
+   *          require a value.
+   * @param description
+   *          LocalizableMessage for the description of this argument.
+   * @throws ArgumentException
+   *           If there is a problem with any of the parameters used to create
+   *           this argument.
+   */
+  public StringArgument(final String name, final Character shortIdentifier,
+      final String longIdentifier, final boolean isRequired,
+      final boolean needsValue, final LocalizableMessage valuePlaceholder,
+      final LocalizableMessage description) throws ArgumentException
+  {
+    super(name, shortIdentifier, longIdentifier, isRequired, false, needsValue,
+        valuePlaceholder, null, null, description);
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in this
+   * argument.
+   *
+   * @param valueString
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          A buffer into which the invalid reason may be written if the value
+   *          is not acceptable.
+   * @return <CODE>true</CODE> if the value is acceptable, or <CODE>false</CODE>
+   *         if it is not.
+   */
+  @Override
+  public boolean valueIsAcceptable(final String valueString,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for this argument.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ToolConstants.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ToolConstants.java
new file mode 100755
index 0000000..9eba321
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/ToolConstants.java
@@ -0,0 +1,619 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+/**
+ * This class defines a number of constants used in one or more Directory Server
+ * tools.
+ */
+final class ToolConstants
+{
+  /**
+   * The name of the SASL property that can be used to provide the
+   * authentication ID for the bind.
+   */
+  static final String SASL_PROPERTY_AUTHID = "authid";
+
+  /**
+   * The name of the SASL property that can be used to provide the authorization
+   * ID for the bind.
+   */
+  static final String SASL_PROPERTY_AUTHZID = "authzid";
+
+  /**
+   * The name of the SASL property that can be used to provide the digest URI
+   * for the bind.
+   */
+  static final String SASL_PROPERTY_DIGEST_URI = "digest-uri";
+
+  /**
+   * The name of the SASL property that can be used to provide the KDC for use
+   * in Kerberos authentication.
+   */
+  static final String SASL_PROPERTY_KDC = "kdc";
+
+  /**
+   * The name of the SASL property that can be used to provide the quality of
+   * protection for the bind.
+   */
+  static final String SASL_PROPERTY_QOP = "qop";
+
+  /**
+   * The name of the SASL property that can be used to provide the realm for the
+   * bind.
+   */
+  static final String SASL_PROPERTY_REALM = "realm";
+
+  /**
+   * The name of the SASL property that can be used to provide trace information
+   * for a SASL ANONYMOUS request.
+   */
+  static final String SASL_PROPERTY_TRACE = "trace";
+
+  /**
+   * The name of the SASL property that can be used to provide the SASL
+   * mechanism to use.
+   */
+  static final String SASL_PROPERTY_MECH = "mech";
+
+  /**
+   * The name of the opends configuration direction in the user home directory.
+   */
+  static final String DEFAULT_OPENDS_CONFIG_DIR = ".opends";
+
+  /**
+   * The default properties file name.
+   */
+  static final String DEFAULT_OPENDS_PROPERTIES_FILE_NAME = "tools";
+
+  /**
+   * The default properties file extension.
+   */
+  static final String DEFAULT_OPENDS_PROPERTIES_FILE_EXTENSION = ".properties";
+
+  /**
+   * The value for the short option batchFilePath.
+   */
+  static final char OPTION_SHORT_BATCH_FILE_PATH = 'F';
+
+  /**
+   * The value for the long option batchFilePath .
+   */
+  static final String OPTION_LONG_BATCH_FILE_PATH = "batchFilePath";
+
+  /**
+   * The value for the short option hostname.
+   */
+  static final char OPTION_SHORT_HOST = 'h';
+
+  /**
+   * The value for the long option hostname.
+   */
+  static final String OPTION_LONG_HOST = "hostname";
+
+  /**
+   * The value for the short option port.
+   */
+  static final char OPTION_SHORT_PORT = 'p';
+
+  /**
+   * The value for the long option port.
+   */
+  static final String OPTION_LONG_PORT = "port";
+
+  /**
+   * The value for the short option useSSL.
+   */
+  static final char OPTION_SHORT_USE_SSL = 'Z';
+
+  /**
+   * The value for the long option useSSL.
+   */
+  static final String OPTION_LONG_USE_SSL = "useSSL";
+
+  /**
+   * The value for the short option baseDN.
+   */
+  static final char OPTION_SHORT_BASEDN = 'b';
+
+  /**
+   * The value for the long option baseDN.
+   */
+  static final String OPTION_LONG_BASEDN = "baseDN";
+
+  /**
+   * The value for the short option bindDN.
+   */
+  static final char OPTION_SHORT_BINDDN = 'D';
+
+  /**
+   * The value for the long option bindDN.
+   */
+  static final String OPTION_LONG_BINDDN = "bindDN";
+
+  /**
+   * The value for the short option bindPassword.
+   */
+  static final char OPTION_SHORT_BINDPWD = 'w';
+
+  /**
+   * The value for the long option bindPassword.
+   */
+  static final String OPTION_LONG_BINDPWD = "bindPassword";
+
+  /**
+   * The value for the short option bindPasswordFile.
+   */
+  static final char OPTION_SHORT_BINDPWD_FILE = 'j';
+
+  /**
+   * The value for the long option bindPasswordFile.
+   */
+  static final String OPTION_LONG_BINDPWD_FILE = "bindPasswordFile";
+
+  /**
+   * The value for the short option compress.
+   */
+  static final char OPTION_SHORT_COMPRESS = 'c';
+
+  /**
+   * The value for the long option compress.
+   */
+  static final String OPTION_LONG_COMPRESS = "compress";
+
+  /**
+   * The value for the short option filename.
+   */
+  static final char OPTION_SHORT_FILENAME = 'f';
+
+  /**
+   * The value for the long option filename.
+   */
+  static final String OPTION_LONG_FILENAME = "filename";
+
+  /**
+   * The value for the short option ldifFile.
+   */
+  static final char OPTION_SHORT_LDIF_FILE = 'l';
+
+  /**
+   * The value for the long option ldifFile.
+   */
+  static final String OPTION_LONG_LDIF_FILE = "ldifFile";
+
+  /**
+   * The value for the short option useStartTLS.
+   */
+  static final char OPTION_SHORT_START_TLS = 'q';
+
+  /**
+   * The value for the long option useStartTLS.
+   */
+  static final String OPTION_LONG_START_TLS = "useStartTLS";
+
+  /**
+   * The value for the short option randomSeed.
+   */
+  static final char OPTION_SHORT_RANDOM_SEED = 's';
+
+  /**
+   * The value for the long option randomSeed.
+   */
+  static final String OPTION_LONG_RANDOM_SEED = "randomSeed";
+
+  /**
+   * The value for the short option keyStorePath.
+   */
+  static final char OPTION_SHORT_KEYSTOREPATH = 'K';
+
+  /**
+   * The value for the long option keyStorePath.
+   */
+  static final String OPTION_LONG_KEYSTOREPATH = "keyStorePath";
+
+  /**
+   * The value for the short option trustStorePath.
+   */
+  static final char OPTION_SHORT_TRUSTSTOREPATH = 'P';
+
+  /**
+   * The value for the long option trustStorePath.
+   */
+  static final String OPTION_LONG_TRUSTSTOREPATH = "trustStorePath";
+
+  /**
+   * The value for the short option keyStorePassword.
+   */
+  static final char OPTION_SHORT_KEYSTORE_PWD = 'W';
+
+  /**
+   * The value for the long option keyStorePassword.
+   */
+  static final String OPTION_LONG_KEYSTORE_PWD = "keyStorePassword";
+
+  /**
+   * The value for the short option trustStorePassword.
+   */
+  static final char OPTION_SHORT_TRUSTSTORE_PWD = 'T';
+
+  /**
+   * The value for the long option trustStorePassword.
+   */
+  static final String OPTION_LONG_TRUSTSTORE_PWD = "trustStorePassword";
+
+  /**
+   * The value for the short option keyStorePasswordFile .
+   */
+  static final char OPTION_SHORT_KEYSTORE_PWD_FILE = 'u';
+
+  /**
+   * The value for the long option keyStorePasswordFile .
+   */
+  static final String OPTION_LONG_KEYSTORE_PWD_FILE = "keyStorePasswordFile";
+
+  /**
+   * The value for the short option keyStorePasswordFile .
+   */
+  static final char OPTION_SHORT_TRUSTSTORE_PWD_FILE = 'U';
+
+  /**
+   * The value for the long option keyStorePasswordFile .
+   */
+  static final String OPTION_LONG_TRUSTSTORE_PWD_FILE = "trustStorePasswordFile";
+
+  /**
+   * The value for the short option trustAll .
+   */
+  static final char OPTION_SHORT_TRUSTALL = 'X';
+
+  /**
+   * The value for the long option trustAll .
+   */
+  static final String OPTION_LONG_TRUSTALL = "trustAll";
+
+  /**
+   * The value for the short option certNickname .
+   */
+  static final char OPTION_SHORT_CERT_NICKNAME = 'N';
+
+  /**
+   * The value for the long option certNickname .
+   */
+  static final String OPTION_LONG_CERT_NICKNAME = "certNickname";
+
+  /**
+   * The value for the long option assertionFilter .
+   */
+  static final String OPTION_LONG_ASSERTION_FILE = "assertionFilter";
+
+  /**
+   * The value for the short option dry-run.
+   */
+  static final char OPTION_SHORT_DRYRUN = 'n';
+
+  /**
+   * The value for the long option dry-run.
+   */
+  static final String OPTION_LONG_DRYRUN = "dry-run";
+
+  /**
+   * The value for the short option help.
+   */
+  static final char OPTION_SHORT_HELP = 'H';
+
+  /**
+   * The value for the long option help.
+   */
+  static final String OPTION_LONG_HELP = "help";
+
+  /**
+   * The value for the long option cli.
+   */
+  static final String OPTION_LONG_CLI = "cli";
+
+  /**
+   * The value for the short option cli.
+   */
+  static final char OPTION_SHORT_CLI = 'i';
+
+  /**
+   * The value for the short option proxyAs.
+   */
+  static final char OPTION_SHORT_PROXYAUTHID = 'Y';
+
+  /**
+   * The value for the long option proxyAs.
+   */
+  static final String OPTION_LONG_PROXYAUTHID = "proxyAs";
+
+  /**
+   * The value for the short option saslOption.
+   */
+  static final char OPTION_SHORT_SASLOPTION = 'o';
+
+  /**
+   * The value for the long option saslOption.
+   */
+  static final String OPTION_LONG_SASLOPTION = "saslOption";
+
+  /**
+   * The value for the short option geteffectiverights control authzid.
+   */
+  static final char OPTION_SHORT_EFFECTIVERIGHTSUSER = 'g';
+
+  /**
+   * The value for the long option geteffectiverights control authzid.
+   */
+  static final String OPTION_LONG_EFFECTIVERIGHTSUSER = "getEffectiveRightsAuthzid";
+
+  /**
+   * The value for the short option geteffectiveights control attributes.
+   */
+  static final char OPTION_SHORT_EFFECTIVERIGHTSATTR = 'e';
+
+  /**
+   * The value for the long option geteffectiverights control specific attribute
+   * list.
+   */
+  static final String OPTION_LONG_EFFECTIVERIGHTSATTR = "getEffectiveRightsAttribute";
+
+  /**
+   * The value for the short option protocol version attributes.
+   */
+  static final char OPTION_SHORT_PROTOCOL_VERSION = 'V';
+
+  /**
+   * The value for the long option protocol version attribute.
+   */
+  static final String OPTION_LONG_PROTOCOL_VERSION = "ldapVersion";
+
+  /**
+   * The value for the long option version.
+   */
+  static final char OPTION_SHORT_PRODUCT_VERSION = 'V';
+
+  /**
+   * The value for the long option version.
+   */
+  static final String OPTION_LONG_PRODUCT_VERSION = "version";
+
+  /**
+   * The value for the short option description attributes.
+   */
+  static final char OPTION_SHORT_DESCRIPTION = 'd';
+
+  /**
+   * The value for the long option description attribute.
+   */
+  static final String OPTION_LONG_DESCRIPTION = "description";
+
+  /**
+   * The value for the short option groupName attributes.
+   */
+  static final char OPTION_SHORT_GROUPNAME = 'g';
+
+  /**
+   * The value for the long option groupName attribute.
+   */
+  static final String OPTION_LONG_GROUPNAME = "groupName";
+
+  /**
+   * The value for the short option newGroupName attribute.
+   */
+  static final char OPTION_SHORT_NEWGROUPNAME = 'n';
+
+  /**
+   * The value for the long option groupName attribute.
+   */
+  static final String OPTION_LONG_NEWGROUPNAME = "newGroupName";
+
+  /**
+   * The value for the short option member-name attributes.
+   */
+  static final char OPTION_SHORT_MEMBERNAME = 'm';
+
+  /**
+   * The value for the long member-name version attribute.
+   */
+  static final String OPTION_LONG_MEMBERNAME = "memberName";
+
+  /**
+   * The value for the short option serverID attributes.
+   */
+  static final String OPTION_SHORT_SERVERID = null;
+
+  /**
+   * The value for the long option serverID attribute.
+   */
+  static final String OPTION_LONG_SERVERID = "serverID";
+
+  /**
+   * The value for the short option userID attributes.
+   */
+  static final String OPTION_SHORT_USERID = null;
+
+  /**
+   * The value for the long option userID attribute.
+   */
+  static final String OPTION_LONG_USERID = "userID";
+
+  /**
+   * The value for the short option set.
+   */
+  static final Character OPTION_SHORT_SET = null;
+
+  /**
+   * The value for the long option set.
+   */
+  static final String OPTION_LONG_SET = "set";
+
+  /**
+   * Value for the quiet option short form.
+   */
+  static final Character OPTION_SHORT_QUIET = 'Q';
+
+  /**
+   * Value for the quiet option long form.
+   */
+  static final String OPTION_LONG_QUIET = "quiet";
+
+  /**
+   * Value for noninteractive session short form.
+   */
+  static final Character OPTION_SHORT_NO_PROMPT = 'n';
+
+  /**
+   * Value for noninteractive session long form.
+   */
+  static final String OPTION_LONG_NO_PROMPT = "no-prompt";
+
+  /**
+   * Long form of script friendly option.
+   */
+  static final String OPTION_LONG_SCRIPT_FRIENDLY = "script-friendly";
+
+  /**
+   * Short form of script friendly option.
+   */
+  static final Character OPTION_SHORT_SCRIPT_FRIENDLY = 's';
+
+  /**
+   * Value for verbose option short form.
+   */
+  static final Character OPTION_SHORT_VERBOSE = 'v';
+
+  /**
+   * Value for verbose option long form.
+   */
+  static final String OPTION_LONG_VERBOSE = "verbose";
+
+  /**
+   * The value for the long option propertiesFilePAth .
+   */
+  static final String OPTION_LONG_PROP_FILE_PATH = "propertiesFilePath";
+
+  /**
+   * The value for the long option propertiesFilePAth .
+   */
+  static final String OPTION_LONG_NO_PROP_FILE = "noPropertiesFile";
+
+  /**
+   * Long form of referenced host name.
+   */
+  static final String OPTION_LONG_REFERENCED_HOST_NAME = "referencedHostName";
+
+  /**
+   * Long form of admin UID.
+   */
+  static final String OPTION_LONG_ADMIN_UID = "adminUID";
+
+  /**
+   * Long form of report authorization ID connection option.
+   */
+  static final String OPTION_LONG_REPORT_AUTHZ_ID = "reportAuthzID";
+
+  /**
+   * Long form of use password policy control connection option.
+   */
+  static final String OPTION_LONG_USE_PW_POLICY_CTL = "usePasswordPolicyControl";
+
+  /**
+   * Long form of use SASL external connection option.
+   */
+  static final String OPTION_LONG_USE_SASL_EXTERNAL = "useSASLExternal";
+
+  /**
+   * Long form of option for the command-line encoding option.
+   */
+  static final String OPTION_LONG_ENCODING = "encoding";
+
+  /**
+   * Long form of option specifying no wrapping of the command-line.
+   */
+  static final String OPTION_LONG_DONT_WRAP = "dontWrap";
+
+  /**
+   * The value for the long option targetDN.
+   */
+  static final String OPTION_LONG_TARGETDN = "targetDN";
+
+  /**
+   * Long form of email notification upon completion option.
+   */
+  static final String OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL = "completionNotify";
+
+  /**
+   * Short form of email notification upon completion option.
+   */
+  static final Character OPTION_SHORT_COMPLETION_NOTIFICATION_EMAIL = null;
+
+  /**
+   * Long form of email notification upon error option.
+   */
+  static final String OPTION_LONG_ERROR_NOTIFICATION_EMAIL = "errorNotify";
+
+  /**
+   * Short form of email notification upon error option.
+   */
+  static final Character OPTION_SHORT_ERROR_NOTIFICATION_EMAIL = null;
+
+  /**
+   * Long form of dependency option.
+   */
+  static final String OPTION_LONG_DEPENDENCY = "dependency";
+
+  /**
+   * Short form of dependency option.
+   */
+  static final Character OPTION_SHORT_DEPENDENCY = null;
+
+  /**
+   * Long form of failed dependency action option.
+   */
+  static final String OPTION_LONG_FAILED_DEPENDENCY_ACTION = "failedDependencyAction";
+
+  /**
+   * Short form of failed dependency action option.
+   */
+  static final Character OPTION_SHORT_FAILED_DEPENDENCY_ACTION = null;
+
+  /**
+   * The default separator to be used in tables.
+   */
+  static final String LIST_TABLE_SEPARATOR = ":";
+
+
+
+  // Prevent instantiation.
+  private ToolConstants()
+  {
+
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Utils.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Utils.java
new file mode 100644
index 0000000..855e1fe
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/Utils.java
@@ -0,0 +1,733 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.EOL;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.*;
+import org.opends.sdk.responses.BindResult;
+
+import com.sun.opends.sdk.controls.AccountUsabilityRequestControl;
+import com.sun.opends.sdk.tools.AuthenticatedConnectionFactory.AuthenticatedConnection;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class provides utility functions for all the client side tools.
+ */
+final class Utils
+{
+  /**
+   * The name of a command-line script used to launch a tool.
+   */
+  static final String PROPERTY_SCRIPT_NAME = "com.sun.opends.sdk.tools.scriptName";
+
+  /**
+   * The column at which to wrap long lines of output in the command-line tools.
+   */
+  static final int MAX_LINE_WIDTH;
+
+  static
+  {
+    int columns = 80;
+    try
+    {
+      final String s = System.getenv("COLUMNS");
+      if (s != null)
+      {
+        columns = Integer.parseInt(s);
+      }
+    }
+    catch (final Exception e)
+    {
+      // Do nothing.
+    }
+    MAX_LINE_WIDTH = columns - 1;
+  }
+
+
+
+  /**
+   * Filters the provided value to ensure that it is appropriate for use as an
+   * exit code. Exit code values are generally only allowed to be between 0 and
+   * 255, so any value outside of this range will be converted to 255, which is
+   * the typical exit code used to indicate an overflow value.
+   *
+   * @param exitCode
+   *          The exit code value to be processed.
+   * @return An integer value between 0 and 255, inclusive. If the provided exit
+   *         code was already between 0 and 255, then the original value will be
+   *         returned. If the provided value was out of this range, then 255
+   *         will be returned.
+   */
+  static int filterExitCode(final int exitCode)
+  {
+    if (exitCode < 0)
+    {
+      return 255;
+    }
+    else if (exitCode > 255)
+    {
+      return 255;
+    }
+    else
+    {
+      return exitCode;
+    }
+  }
+
+
+
+  /**
+   * Parse the specified command line argument to create the appropriate
+   * LDAPControl. The argument string should be in the format
+   * controloid[:criticality[:value|::b64value|:&lt;fileurl]]
+   *
+   * @param argString
+   *          The argument string containing the encoded control information.
+   * @return The control decoded from the provided string, or <CODE>null</CODE>
+   *         if an error occurs while parsing the argument value.
+   * @throws org.opends.sdk.DecodeException
+   *           If an error occurs.
+   */
+  static GenericControl getControl(final String argString)
+      throws DecodeException
+  {
+    String controlOID = null;
+    boolean controlCriticality = false;
+    ByteString controlValue = null;
+
+    int idx = argString.indexOf(":");
+
+    if (idx < 0)
+    {
+      controlOID = argString;
+    }
+    else
+    {
+      controlOID = argString.substring(0, idx);
+    }
+
+    final String lowerOID = StaticUtils.toLowerCase(controlOID);
+    if (lowerOID.equals("accountusable") || lowerOID.equals("accountusability"))
+    {
+      controlOID = AccountUsabilityRequestControl.OID;
+    }
+    else if (lowerOID.equals("authzid")
+        || lowerOID.equals("authorizationidentity"))
+    {
+      controlOID = AuthorizationIdentityRequestControl.OID;
+    }
+    else if (lowerOID.equals("noop") || lowerOID.equals("no-op"))
+    {
+      // controlOID = OID_LDAP_NOOP_OPENLDAP_ASSIGNED;
+    }
+    else if (lowerOID.equals("subentries"))
+    {
+      // controlOID = OID_LDAP_SUBENTRIES;
+    }
+    else if (lowerOID.equals("managedsait"))
+    {
+      // controlOID = OID_MANAGE_DSAIT_CONTROL;
+    }
+    else if (lowerOID.equals("pwpolicy") || lowerOID.equals("passwordpolicy"))
+    {
+      controlOID = PasswordPolicyRequestControl.OID;
+    }
+    else if (lowerOID.equals("subtreedelete") || lowerOID.equals("treedelete"))
+    {
+      controlOID = SubtreeDeleteRequestControl.OID;
+    }
+    else if (lowerOID.equals("realattrsonly")
+        || lowerOID.equals("realattributesonly"))
+    {
+      // controlOID = OID_REAL_ATTRS_ONLY;
+    }
+    else if (lowerOID.equals("virtualattrsonly")
+        || lowerOID.equals("virtualattributesonly"))
+    {
+      // controlOID = OID_VIRTUAL_ATTRS_ONLY;
+    }
+    else if (lowerOID.equals("effectiverights")
+        || lowerOID.equals("geteffectiverights"))
+    {
+      controlOID = GetEffectiveRightsRequestControl.OID;
+    }
+
+    if (idx < 0)
+    {
+      return GenericControl.newControl(controlOID);
+    }
+
+    final String remainder = argString.substring(idx + 1, argString.length());
+
+    idx = remainder.indexOf(":");
+    if (idx == -1)
+    {
+      if (remainder.equalsIgnoreCase("true"))
+      {
+        controlCriticality = true;
+      }
+      else if (remainder.equalsIgnoreCase("false"))
+      {
+        controlCriticality = false;
+      }
+      else
+      {
+        // TODO: I18N
+        throw DecodeException.error(LocalizableMessage
+            .raw("Invalid format for criticality value:" + remainder));
+      }
+      return GenericControl.newControl(controlOID, controlCriticality);
+
+    }
+
+    final String critical = remainder.substring(0, idx);
+    if (critical.equalsIgnoreCase("true"))
+    {
+      controlCriticality = true;
+    }
+    else if (critical.equalsIgnoreCase("false"))
+    {
+      controlCriticality = false;
+    }
+    else
+    {
+      // TODO: I18N
+      throw DecodeException.error(LocalizableMessage
+          .raw("Invalid format for criticality value:" + critical));
+    }
+
+    final String valString = remainder.substring(idx + 1, remainder.length());
+    if (valString.charAt(0) == ':')
+    {
+      controlValue = ByteString.valueOf(valString.substring(1, valString
+          .length()));
+    }
+    else if (valString.charAt(0) == '<')
+    {
+      // Read data from the file.
+      final String filePath = valString.substring(1, valString.length());
+      try
+      {
+        final byte[] val = readBytesFromFile(filePath);
+        controlValue = ByteString.wrap(val);
+      }
+      catch (final Exception e)
+      {
+        return null;
+      }
+    }
+    else
+    {
+      controlValue = ByteString.valueOf(valString);
+    }
+
+    return GenericControl.newControl(controlOID, controlCriticality,
+        controlValue);
+  }
+
+
+
+  /**
+   * Prints a multi-line error message with the provided information to the
+   * given print stream.
+   *
+   * @param app
+   *          The console app to use to write the error message.
+   * @param ere
+   *          The error result.
+   * @return The error code.
+   */
+  static int printErrorMessage(final ConsoleApplication app,
+      final ErrorResultException ere)
+  {
+    // if ((ere.getMessage() != null) && (ere.getMessage().length() >
+    // 0))
+    // {
+    // app.println(LocalizableMessage.raw(ere.getMessage()));
+    // }
+
+    if (ere.getResult().getResultCode().intValue() >= 0)
+    {
+      app.println(ERR_TOOL_RESULT_CODE.get(ere.getResult().getResultCode()
+          .intValue(), ere.getResult().getResultCode().toString()));
+    }
+
+    if ((ere.getResult().getDiagnosticMessage() != null)
+        && (ere.getResult().getDiagnosticMessage().length() > 0))
+    {
+      app.println(ERR_TOOL_ERROR_MESSAGE.get(ere.getResult()
+          .getDiagnosticMessage()));
+    }
+
+    if (ere.getResult().getMatchedDN() != null
+        && ere.getResult().getMatchedDN().length() > 0)
+    {
+      app.println(ERR_TOOL_MATCHED_DN.get(ere.getResult().getMatchedDN()));
+    }
+
+    if (app.isVerbose() && ere.getResult().getCause() != null)
+    {
+      ere.getResult().getCause().printStackTrace(app.getErrorStream());
+    }
+
+    return ere.getResult().getResultCode().intValue();
+  }
+
+
+
+  static void printPasswordPolicyResults(final ConsoleApplication app,
+      final Connection connection)
+  {
+    if (connection instanceof AuthenticatedConnection)
+    {
+      final AuthenticatedConnection conn = (AuthenticatedConnection) connection;
+      final BindResult result = conn.getAuthenticatedBindResult();
+
+      try
+      {
+        final AuthorizationIdentityResponseControl control = result.getControl(
+            AuthorizationIdentityResponseControl.DECODER, new DecodeOptions());
+        if (control != null)
+        {
+          final LocalizableMessage message = INFO_BIND_AUTHZID_RETURNED
+              .get(control.getAuthorizationID());
+          app.println(message);
+        }
+      }
+      catch (final DecodeException e)
+      {
+        app.println(ERR_DECODE_CONTROL_FAILURE.get(e.getLocalizedMessage()));
+      }
+
+      try
+      {
+        final PasswordExpiredResponseControl control = result.getControl(
+            PasswordExpiredResponseControl.DECODER, new DecodeOptions());
+        if (control != null)
+        {
+          final LocalizableMessage message = INFO_BIND_PASSWORD_EXPIRED.get();
+          app.println(message);
+        }
+      }
+      catch (final DecodeException e)
+      {
+        app.println(ERR_DECODE_CONTROL_FAILURE.get(e.getLocalizedMessage()));
+      }
+
+      try
+      {
+        final PasswordExpiringResponseControl control = result.getControl(
+            PasswordExpiringResponseControl.DECODER, new DecodeOptions());
+        if (control != null)
+        {
+          final LocalizableMessage timeString = Utils
+              .secondsToTimeString(control.getSecondsUntilExpiration());
+          final LocalizableMessage message = INFO_BIND_PASSWORD_EXPIRING
+              .get(timeString);
+          app.println(message);
+        }
+      }
+      catch (final DecodeException e)
+      {
+        app.println(ERR_DECODE_CONTROL_FAILURE.get(e.getLocalizedMessage()));
+      }
+
+      try
+      {
+        final PasswordPolicyResponseControl control = result.getControl(
+            PasswordPolicyResponseControl.DECODER, new DecodeOptions());
+        if (control != null)
+        {
+          final PasswordPolicyErrorType errorType = control.getErrorType();
+          if (errorType == PasswordPolicyErrorType.PASSWORD_EXPIRED)
+          {
+            final LocalizableMessage message = INFO_BIND_PASSWORD_EXPIRED.get();
+            app.println(message);
+          }
+          else if (errorType == PasswordPolicyErrorType.ACCOUNT_LOCKED)
+          {
+            final LocalizableMessage message = INFO_BIND_ACCOUNT_LOCKED.get();
+            app.println(message);
+          }
+          else if (errorType == PasswordPolicyErrorType.CHANGE_AFTER_RESET)
+          {
+
+            final LocalizableMessage message = INFO_BIND_MUST_CHANGE_PASSWORD
+                .get();
+            app.println(message);
+          }
+
+          final PasswordPolicyWarningType warningType = control
+              .getWarningType();
+          if (warningType == PasswordPolicyWarningType.TIME_BEFORE_EXPIRATION)
+          {
+            final LocalizableMessage timeString = Utils
+                .secondsToTimeString(control.getWarningValue());
+            final LocalizableMessage message = INFO_BIND_PASSWORD_EXPIRING
+                .get(timeString);
+            app.println(message);
+          }
+          else if (warningType == PasswordPolicyWarningType.GRACE_LOGINS_REMAINING)
+          {
+            final LocalizableMessage message = INFO_BIND_GRACE_LOGINS_REMAINING
+                .get(control.getWarningValue());
+            app.println(message);
+          }
+        }
+      }
+      catch (final DecodeException e)
+      {
+        app.println(ERR_DECODE_CONTROL_FAILURE.get(e.getLocalizedMessage()));
+      }
+    }
+  }
+
+
+
+  /**
+   * Read the data from the specified file and return it in a byte array.
+   *
+   * @param filePath
+   *          The path to the file that should be read.
+   * @return A byte array containing the contents of the requested file.
+   * @throws IOException
+   *           If a problem occurs while trying to read the specified file.
+   */
+  static byte[] readBytesFromFile(final String filePath) throws IOException
+  {
+    byte[] val = null;
+    FileInputStream fis = null;
+    try
+    {
+      final File file = new File(filePath);
+      fis = new FileInputStream(file);
+      final long length = file.length();
+      val = new byte[(int) length];
+      // Read in the bytes
+      int offset = 0;
+      int numRead = 0;
+      while (offset < val.length
+          && (numRead = fis.read(val, offset, val.length - offset)) >= 0)
+      {
+        offset += numRead;
+      }
+
+      // Ensure all the bytes have been read in
+      if (offset < val.length)
+      {
+        throw new IOException("Could not completely read file " + filePath);
+      }
+
+      return val;
+    }
+    finally
+    {
+      if (fis != null)
+      {
+        fis.close();
+      }
+    }
+  }
+
+
+
+  /**
+   * Retrieves a user-friendly string that indicates the length of time (in
+   * days, hours, minutes, and seconds) in the specified number of seconds.
+   *
+   * @param numSeconds
+   *          The number of seconds to be converted to a more user-friendly
+   *          value.
+   * @return The user-friendly representation of the specified number of
+   *         seconds.
+   */
+  static LocalizableMessage secondsToTimeString(final int numSeconds)
+  {
+    if (numSeconds < 60)
+    {
+      // We can express it in seconds.
+      return INFO_TIME_IN_SECONDS.get(numSeconds);
+    }
+    else if (numSeconds < 3600)
+    {
+      // We can express it in minutes and seconds.
+      final int m = numSeconds / 60;
+      final int s = numSeconds % 60;
+      return INFO_TIME_IN_MINUTES_SECONDS.get(m, s);
+    }
+    else if (numSeconds < 86400)
+    {
+      // We can express it in hours, minutes, and seconds.
+      final int h = numSeconds / 3600;
+      final int m = (numSeconds % 3600) / 60;
+      final int s = numSeconds % 3600 % 60;
+      return INFO_TIME_IN_HOURS_MINUTES_SECONDS.get(h, m, s);
+    }
+    else
+    {
+      // We can express it in days, hours, minutes, and seconds.
+      final int d = numSeconds / 86400;
+      final int h = (numSeconds % 86400) / 3600;
+      final int m = (numSeconds % 86400 % 3600) / 60;
+      final int s = numSeconds % 86400 % 3600 % 60;
+      return INFO_TIME_IN_DAYS_HOURS_MINUTES_SECONDS.get(d, h, m, s);
+    }
+  }
+
+
+
+  /**
+   * Inserts line breaks into the provided buffer to wrap text at no more than
+   * the specified column width. Wrapping will only be done at space boundaries
+   * and if there are no spaces within the specified width, then wrapping will
+   * be performed at the first space after the specified column.
+   *
+   * @param message
+   *          The message to be wrapped.
+   * @param width
+   *          The maximum number of characters to allow on a line if there is a
+   *          suitable breaking point.
+   * @return The wrapped text.
+   */
+  static String wrapText(final LocalizableMessage message, final int width)
+  {
+    return wrapText(message.toString(), width, 0);
+  }
+
+
+
+  /**
+   * Inserts line breaks into the provided buffer to wrap text at no more than
+   * the specified column width. Wrapping will only be done at space boundaries
+   * and if there are no spaces within the specified width, then wrapping will
+   * be performed at the first space after the specified column. In addition
+   * each line will be indented by the specified amount.
+   *
+   * @param message
+   *          The message to be wrapped.
+   * @param width
+   *          The maximum number of characters to allow on a line if there is a
+   *          suitable breaking point (including any indentation).
+   * @param indent
+   *          The number of columns to indent each line.
+   * @return The wrapped text.
+   */
+  static String wrapText(final LocalizableMessage message, final int width,
+      final int indent)
+  {
+    return wrapText(message.toString(), width, indent);
+  }
+
+
+
+  /**
+   * Inserts line breaks into the provided buffer to wrap text at no more than
+   * the specified column width. Wrapping will only be done at space boundaries
+   * and if there are no spaces within the specified width, then wrapping will
+   * be performed at the first space after the specified column.
+   *
+   * @param text
+   *          The text to be wrapped.
+   * @param width
+   *          The maximum number of characters to allow on a line if there is a
+   *          suitable breaking point.
+   * @return The wrapped text.
+   */
+  static String wrapText(final String text, final int width)
+  {
+    return wrapText(text, width, 0);
+  }
+
+
+
+  /**
+   * Inserts line breaks into the provided buffer to wrap text at no more than
+   * the specified column width. Wrapping will only be done at space boundaries
+   * and if there are no spaces within the specified width, then wrapping will
+   * be performed at the first space after the specified column. In addition
+   * each line will be indented by the specified amount.
+   *
+   * @param text
+   *          The text to be wrapped.
+   * @param width
+   *          The maximum number of characters to allow on a line if there is a
+   *          suitable breaking point (including any indentation).
+   * @param indent
+   *          The number of columns to indent each line.
+   * @return The wrapped text.
+   */
+  static String wrapText(final String text, int width, final int indent)
+  {
+    // Calculate the real width and indentation padding.
+    width -= indent;
+    final StringBuilder pb = new StringBuilder();
+    for (int i = 0; i < indent; i++)
+    {
+      pb.append(' ');
+    }
+    final String padding = pb.toString();
+
+    final StringBuilder buffer = new StringBuilder();
+    if (text != null)
+    {
+      final StringTokenizer lineTokenizer = new StringTokenizer(text, "\r\n",
+          true);
+      while (lineTokenizer.hasMoreTokens())
+      {
+        final String line = lineTokenizer.nextToken();
+        if (line.equals("\r") || line.equals("\n"))
+        {
+          // It's an end-of-line character, so append it as-is.
+          buffer.append(line);
+        }
+        else if (line.length() <= width)
+        {
+          // The line fits in the specified width, so append it as-is.
+          buffer.append(padding);
+          buffer.append(line);
+        }
+        else
+        {
+          // The line doesn't fit in the specified width, so it needs to
+          // be
+          // wrapped. Do so at space boundaries.
+          StringBuilder lineBuffer = new StringBuilder();
+          StringBuilder delimBuffer = new StringBuilder();
+          final StringTokenizer wordTokenizer = new StringTokenizer(line, " ",
+              true);
+          while (wordTokenizer.hasMoreTokens())
+          {
+            final String word = wordTokenizer.nextToken();
+            if (word.equals(" "))
+            {
+              // It's a space, so add it to the delim buffer only if the
+              // line
+              // buffer is not empty.
+              if (lineBuffer.length() > 0)
+              {
+                delimBuffer.append(word);
+              }
+            }
+            else if (word.length() > width)
+            {
+              // This is a long word that can't be wrapped, so we'll
+              // just have
+              // to make do.
+              if (lineBuffer.length() > 0)
+              {
+                buffer.append(padding);
+                buffer.append(lineBuffer);
+                buffer.append(EOL);
+                lineBuffer = new StringBuilder();
+              }
+              buffer.append(padding);
+              buffer.append(word);
+
+              if (wordTokenizer.hasMoreTokens())
+              {
+                // The next token must be a space, so remove it. If
+                // there are
+                // still more tokens after that, then append an EOL.
+                wordTokenizer.nextToken();
+                if (wordTokenizer.hasMoreTokens())
+                {
+                  buffer.append(EOL);
+                }
+              }
+
+              if (delimBuffer.length() > 0)
+              {
+                delimBuffer = new StringBuilder();
+              }
+            }
+            else
+            {
+              // It's not a space, so see if we can fit it on the curent
+              // line.
+              final int newLineLength = lineBuffer.length()
+                  + delimBuffer.length() + word.length();
+              if (newLineLength < width)
+              {
+                // It does fit on the line, so add it.
+                lineBuffer.append(delimBuffer).append(word);
+
+                if (delimBuffer.length() > 0)
+                {
+                  delimBuffer = new StringBuilder();
+                }
+              }
+              else
+              {
+                // It doesn't fit on the line, so end the current line
+                // and start
+                // a new one.
+                buffer.append(padding);
+                buffer.append(lineBuffer);
+                buffer.append(EOL);
+
+                lineBuffer = new StringBuilder();
+                lineBuffer.append(word);
+
+                if (delimBuffer.length() > 0)
+                {
+                  delimBuffer = new StringBuilder();
+                }
+              }
+            }
+          }
+
+          // If there's anything left in the line buffer, then add it to
+          // the
+          // final buffer.
+          buffer.append(padding);
+          buffer.append(lineBuffer);
+        }
+      }
+    }
+    return buffer.toString();
+  }
+
+
+
+  // Prevent instantiation.
+  private Utils()
+  {
+    // Do nothing.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/package-info.java b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/package-info.java
new file mode 100755
index 0000000..227eb18
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/main/java/com/sun/opends/sdk/tools/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes implementing the OpenDS SDK client tools.
+ */
+package com.sun.opends.sdk.tools;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactoryTestCase.java b/opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactoryTestCase.java
new file mode 100644
index 0000000..a008ccd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/PerfToolTCPNIOTransportFactoryTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import static org.testng.Assert.assertTrue;
+
+import java.net.Socket;
+import java.util.Random;
+
+import org.glassfish.grizzly.TransportFactory;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests PerfToolTCPNIOTransportFactoryTestCase class.
+ */
+public class PerfToolTCPNIOTransportFactoryTestCase extends ToolsTestCase
+{
+  /**
+   * Tests the transport factory.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test()
+  public void testGetInstance() throws Exception
+  {
+    // Create a transport.
+    final TransportFactory factory = new PerfToolTCPNIOTransportFactory();
+    final TCPNIOTransport transport = factory.createTCPTransport();
+    final Random r = new Random();
+    int port = r.nextInt(10000);
+    if (port < 1000)
+    {
+      port += 1000;
+    }
+    transport.bind(port);
+    // Establish a socket connection to see if the transport factory works.
+    final Socket socket = new Socket("localhost", port);
+    // Successfully connected if there is no exception.
+    assertTrue(socket.isConnected());
+    // Don't stop the transport because it is shared with the ldap server.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/ToolsTestCase.java b/opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/ToolsTestCase.java
new file mode 100644
index 0000000..eb8134c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-client-tools/src/test/java/com/sun/opends/sdk/tools/ToolsTestCase.java
@@ -0,0 +1,45 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.tools;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all tools unit tests should extend. A tool represents
+ * the classes found directly under the package com.sun.opends.sdk.tools.
+ */
+
+@Test(groups = { "precommit", "tools", "sdk" }, sequential = true)
+public abstract class ToolsTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControl.java
new file mode 100644
index 0000000..75797d9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ACCTUSABLEREQ_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_ACCTUSABLEREQ_CONTROL_HAS_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The Sun-defined account usability request control. The OID for this control
+ * is 1.3.6.1.4.1.42.2.27.9.5.8, and it does not have a value.
+ *
+ * @see AccountUsabilityResponseControl
+ */
+public final class AccountUsabilityRequestControl implements Control
+{
+  /**
+   * The OID for the account usability request control.
+   */
+  public static final String OID = "1.3.6.1.4.1.42.2.27.9.5.8";
+
+  private final boolean isCritical;
+
+  private static final AccountUsabilityRequestControl CRITICAL_INSTANCE =
+    new AccountUsabilityRequestControl(true);
+  private static final AccountUsabilityRequestControl NONCRITICAL_INSTANCE =
+    new AccountUsabilityRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the account usability request
+   * control.
+   */
+  public static final ControlDecoder<AccountUsabilityRequestControl> DECODER =
+    new ControlDecoder<AccountUsabilityRequestControl>()
+  {
+
+    public AccountUsabilityRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof AccountUsabilityRequestControl)
+      {
+        return (AccountUsabilityRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_ACCTUSABLEREQ_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_ACCTUSABLEREQ_CONTROL_HAS_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new account usability request control having the provided
+   * criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static AccountUsabilityRequestControl newControl(
+      final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  // Prevent direct instantiation.
+  private AccountUsabilityRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AccountUsableRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControl.java
new file mode 100644
index 0000000..6a4f776
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControl.java
@@ -0,0 +1,570 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ACCTUSABLERES_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_ACCTUSABLERES_DECODE_ERROR;
+import static com.sun.opends.sdk.messages.Messages.ERR_ACCTUSABLERES_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE;
+import static com.sun.opends.sdk.util.StaticUtils.byteToHex;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The Sun-defined account usability response control. The OID for this control
+ * is 1.3.6.1.4.1.42.2.27.9.5.8, and it has a value encoded according to the
+ * following BNF:
+ *
+ * <pre>
+ * ACCOUNT_USABLE_RESPONSE ::= CHOICE {
+ *      is_available           [0] INTEGER, -- Seconds before expiration --
+ *      is_not_available       [1] MORE_INFO }
+ *
+ * MORE_INFO ::= SEQUENCE {
+ *      inactive               [0] BOOLEAN DEFAULT FALSE,
+ *      reset                  [1] BOOLEAN DEFAULT FALSE,
+ *      expired                [2] BOOLEAN DEFAULT_FALSE,
+ *      remaining_grace        [3] INTEGER OPTIONAL,
+ *      seconds_before_unlock  [4] INTEGER OPTIONAL }
+ * </pre>
+ *
+ * @see AccountUsabilityRequestControl
+ */
+public final class AccountUsabilityResponseControl implements Control
+{
+  /**
+   * The OID for the account usability response control.
+   */
+  public static final String OID = AccountUsabilityRequestControl.OID;
+
+  /**
+   * A decoder which can be used for decoding the account usability response
+   * control.
+   */
+  public static final ControlDecoder<AccountUsabilityResponseControl> DECODER =
+    new ControlDecoder<AccountUsabilityResponseControl>()
+  {
+
+    public AccountUsabilityResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof AccountUsabilityResponseControl)
+      {
+        return (AccountUsabilityResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_ACCTUSABLERES_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_ACCTUSABLERES_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      try
+      {
+        final ASN1Reader reader = ASN1.getReader(control.getValue());
+        switch (reader.peekType())
+        {
+        case TYPE_SECONDS_BEFORE_EXPIRATION:
+          final int secondsBeforeExpiration = (int) reader.readInteger();
+          return new AccountUsabilityResponseControl(control.isCritical(),
+              true, false, false, false, -1, false, 0, secondsBeforeExpiration);
+        case TYPE_MORE_INFO:
+          boolean isInactive = false;
+          boolean isReset = false;
+          boolean isExpired = false;
+          boolean isLocked = false;
+          int remainingGraceLogins = -1;
+          int secondsBeforeUnlock = 0;
+
+          reader.readStartSequence();
+          if (reader.hasNextElement() && (reader.peekType() == TYPE_INACTIVE))
+          {
+            isInactive = reader.readBoolean();
+          }
+          if (reader.hasNextElement() && (reader.peekType() == TYPE_RESET))
+          {
+            isReset = reader.readBoolean();
+          }
+          if (reader.hasNextElement() && (reader.peekType() == TYPE_EXPIRED))
+          {
+            isExpired = reader.readBoolean();
+          }
+          if (reader.hasNextElement()
+              && (reader.peekType() == TYPE_REMAINING_GRACE_LOGINS))
+          {
+            remainingGraceLogins = (int) reader.readInteger();
+          }
+          if (reader.hasNextElement()
+              && (reader.peekType() == TYPE_SECONDS_BEFORE_UNLOCK))
+          {
+            isLocked = true;
+            secondsBeforeUnlock = (int) reader.readInteger();
+          }
+          reader.readEndSequence();
+
+          return new AccountUsabilityResponseControl(control.isCritical(),
+              false, isInactive, isReset, isExpired, remainingGraceLogins,
+              isLocked, secondsBeforeUnlock, -1);
+
+        default:
+          final LocalizableMessage message = ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE
+              .get(byteToHex(reader.peekType()));
+          throw DecodeException.error(message);
+        }
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.throwing(
+            "AccountUsabilityResponseControl.decodeControl", "decode", e);
+
+        final LocalizableMessage message = ERR_ACCTUSABLERES_DECODE_ERROR
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+  /**
+   * The BER type to use for the seconds before expiration when the account is
+   * available.
+   */
+  private static final byte TYPE_SECONDS_BEFORE_EXPIRATION = (byte) 0x80;
+
+  /**
+   * The BER type to use for the MORE_INFO sequence when the account is not
+   * available.
+   */
+  private static final byte TYPE_MORE_INFO = (byte) 0xA1;
+
+  /**
+   * The BER type to use for the MORE_INFO element that indicates that the
+   * account has been inactivated.
+   */
+  private static final byte TYPE_INACTIVE = (byte) 0x80;
+
+  /**
+   * The BER type to use for the MORE_INFO element that indicates that the
+   * password has been administratively reset.
+   */
+  private static final byte TYPE_RESET = (byte) 0x81;
+
+  /**
+   * The BER type to use for the MORE_INFO element that indicates that the
+   * user's password is expired.
+   */
+  private static final byte TYPE_EXPIRED = (byte) 0x82;
+
+  /**
+   * The BER type to use for the MORE_INFO element that provides the number of
+   * remaining grace logins.
+   */
+  private static final byte TYPE_REMAINING_GRACE_LOGINS = (byte) 0x83;
+
+  /**
+   * The BER type to use for the MORE_INFO element that indicates that the
+   * password has been administratively reset.
+   */
+  private static final byte TYPE_SECONDS_BEFORE_UNLOCK = (byte) 0x84;
+
+
+
+  /**
+   * Creates a new account usability response control that may be used to
+   * indicate that the account is not available and provide information about
+   * the underlying reason.
+   *
+   * @param isInactive
+   *          Indicates whether the user's account has been inactivated by an
+   *          administrator.
+   * @param isReset
+   *          Indicates whether the user's password has been reset by an
+   *          administrator.
+   * @param isExpired
+   *          Indicates whether the user's password has expired.
+   * @param remainingGraceLogins
+   *          The number of grace logins remaining. A value of {@code 0}
+   *          indicates that there are none remaining. A value of {@code -1}
+   *          indicates that grace login functionality is not enabled.
+   * @param isLocked
+   *          Indicates whether the user's account is currently locked out.
+   * @param secondsBeforeUnlock
+   *          The length of time in seconds until the account is unlocked. A
+   *          value of {@code -1} indicates that the account will not be
+   *          automatically unlocked and must be reset by an administrator.
+   * @return The new control.
+   */
+  public static AccountUsabilityResponseControl newControl(
+      final boolean isInactive, final boolean isReset, final boolean isExpired,
+      final int remainingGraceLogins, final boolean isLocked,
+      final int secondsBeforeUnlock)
+  {
+    return new AccountUsabilityResponseControl(false, false, isInactive,
+        isReset, isExpired, remainingGraceLogins, isLocked,
+        secondsBeforeUnlock, -1);
+  }
+
+
+
+  /**
+   * Creates a new account usability response control that may be used to
+   * indicate that the account is available and provide the number of seconds
+   * until expiration.
+   *
+   * @param secondsBeforeExpiration
+   *          The length of time in seconds until the user's password expires,
+   *          or {@code -1} if the user's password will not expire or the
+   *          expiration time is unknown.
+   * @return The new control.
+   */
+  public static AccountUsabilityResponseControl newControl(
+      final int secondsBeforeExpiration)
+  {
+    return new AccountUsabilityResponseControl(false, true, false, false,
+        false, -1, false, 0, secondsBeforeExpiration);
+  }
+
+
+
+  // Indicates whether the user's account is usable.
+  private final boolean isUsable;
+
+  // Indicates whether the user's password is expired.
+  private final boolean isExpired;
+
+  // Indicates whether the user's account is inactive.
+  private final boolean isInactive;
+
+  // Indicates whether the user's account is currently locked.
+  private final boolean isLocked;
+
+  // Indicates whether the user's password has been reset and must be
+  // changed before anything else can be done.
+  private final boolean isReset;
+
+  // The number of remaining grace logins, if available.
+  private final int remainingGraceLogins;
+
+  // The length of time in seconds before the user's password expires,
+  // if available.
+  private final int secondsBeforeExpiration;
+
+  // The length of time before the user's account is unlocked, if
+  // available.
+  private final int secondsBeforeUnlock;
+
+  private final boolean isCritical;
+
+
+
+  // Prevent direct instantiation.
+  private AccountUsabilityResponseControl(final boolean isCritical,
+      final boolean isUsable, final boolean isInactive, final boolean isReset,
+      final boolean isExpired, final int remainingGraceLogins,
+      final boolean isLocked, final int secondsBeforeUnlock,
+      final int secondsBeforeExpiration)
+  {
+    this.isCritical = isCritical;
+    this.isUsable = isUsable;
+    this.isInactive = isInactive;
+    this.isReset = isReset;
+    this.isExpired = isExpired;
+    this.remainingGraceLogins = remainingGraceLogins;
+    this.isLocked = isLocked;
+    this.secondsBeforeUnlock = secondsBeforeUnlock;
+    this.secondsBeforeExpiration = secondsBeforeExpiration;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns the number of remaining grace logins for the user. This value is
+   * unreliable if the user's password has not expired.
+   *
+   * @return The number of remaining grace logins for the user, or {@code -1} if
+   *         the grace logins feature is not enabled for the user.
+   */
+  public int getRemainingGraceLogins()
+  {
+    return remainingGraceLogins;
+  }
+
+
+
+  /**
+   * Returns the length of time in seconds before the user's password expires.
+   * This value is unreliable if the account is not available.
+   *
+   * @return The length of time in seconds before the user's password expires,
+   *         or {@code -1} if it is unknown or password expiration is not
+   *         enabled for the user.
+   */
+  public int getSecondsBeforeExpiration()
+  {
+    return secondsBeforeExpiration;
+  }
+
+
+
+  /**
+   * Returns the length of time in seconds before the user's account is
+   * automatically unlocked. This value is unreliable is the user's account is
+   * not locked.
+   *
+   * @return The length of time in seconds before the user's account is
+   *         automatically unlocked, or {@code -1} if it requires administrative
+   *         action to unlock the account.
+   */
+  public int getSecondsBeforeUnlock()
+  {
+    return secondsBeforeUnlock;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      if (secondsBeforeExpiration < 0)
+      {
+        writer.writeInteger(TYPE_SECONDS_BEFORE_EXPIRATION,
+            secondsBeforeExpiration);
+      }
+      else
+      {
+        writer.writeStartSequence(TYPE_MORE_INFO);
+        if (isInactive)
+        {
+          writer.writeBoolean(TYPE_INACTIVE, true);
+        }
+
+        if (isReset)
+        {
+          writer.writeBoolean(TYPE_RESET, true);
+        }
+
+        if (isExpired)
+        {
+          writer.writeBoolean(TYPE_EXPIRED, true);
+
+          if (remainingGraceLogins >= 0)
+          {
+            writer.writeInteger(TYPE_REMAINING_GRACE_LOGINS,
+                remainingGraceLogins);
+          }
+        }
+
+        if (isLocked)
+        {
+          writer.writeInteger(TYPE_SECONDS_BEFORE_UNLOCK, secondsBeforeUnlock);
+        }
+        writer.writeEndSequence();
+      }
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * Returns {@code true} if the user's password has expired.
+   *
+   * @return <CODE>true</CODE> if the user's password has expired, or
+   *         <CODE>false</CODE> if not.
+   */
+  public boolean isExpired()
+  {
+    return isExpired;
+  }
+
+
+
+  /**
+   * Returns {@code true} if the user's account has been inactivated by an
+   * administrator.
+   *
+   * @return <CODE>true</CODE> if the user's account has been inactivated by an
+   *         administrator, or <CODE>false</CODE> if not.
+   */
+  public boolean isInactive()
+  {
+    return isInactive;
+  }
+
+
+
+  /**
+   * Returns {@code true} if the user's account is locked for some reason.
+   *
+   * @return <CODE>true</CODE> if the user's account is locked, or
+   *         <CODE>false</CODE> if it is not.
+   */
+  public boolean isLocked()
+  {
+    return isLocked;
+  }
+
+
+
+  /**
+   * Returns {@code true} if the user's password has been administratively reset
+   * and the user must change that password before any other operations will be
+   * allowed.
+   *
+   * @return <CODE>true</CODE> if the user's password has been administratively
+   *         reset, or <CODE>false</CODE> if not.
+   */
+  public boolean isReset()
+  {
+    return isReset;
+  }
+
+
+
+  /**
+   * Returns {@code true} if the associated user account is available for use.
+   *
+   * @return <CODE>true</CODE> if the associated user account is available, or
+   *         <CODE>false</CODE> if not.
+   */
+  public boolean isUsable()
+  {
+    return isUsable;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AccountUsableResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", isUsable=");
+    builder.append(isUsable);
+    if (isUsable)
+    {
+      builder.append(",secondsBeforeExpiration=");
+      builder.append(secondsBeforeExpiration);
+    }
+    else
+    {
+      builder.append(",isInactive=");
+      builder.append(isInactive);
+      builder.append(",isReset=");
+      builder.append(isReset);
+      builder.append(",isExpired=");
+      builder.append(isExpired);
+      builder.append(",remainingGraceLogins=");
+      builder.append(remainingGraceLogins);
+      builder.append(",isLocked=");
+      builder.append(isLocked);
+      builder.append(",secondsBeforeUnlock=");
+      builder.append(secondsBeforeUnlock);
+    }
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/RealAttributesOnlyRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/RealAttributesOnlyRequestControl.java
new file mode 100644
index 0000000..3fa3e46
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/RealAttributesOnlyRequestControl.java
@@ -0,0 +1,192 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_REAL_ATTRS_ONLY_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_REAL_ATTRS_ONLY_INVALID_CONTROL_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The Sun-defined real attributes only request control. The OID for this
+ * control is 2.16.840.1.113730.3.4.17, and it does not have a value.
+ */
+public final class RealAttributesOnlyRequestControl implements Control
+{
+  /**
+   * The OID for the real attributes only request control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.17";
+
+  private static final RealAttributesOnlyRequestControl CRITICAL_INSTANCE =
+    new RealAttributesOnlyRequestControl(true);
+
+  private static final RealAttributesOnlyRequestControl NONCRITICAL_INSTANCE =
+    new RealAttributesOnlyRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the real attributes only request
+   * control.
+   */
+  public static final ControlDecoder<RealAttributesOnlyRequestControl> DECODER =
+    new ControlDecoder<RealAttributesOnlyRequestControl>()
+  {
+
+    public RealAttributesOnlyRequestControl decodeControl(
+        final Control control, final DecodeOptions options)
+        throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof RealAttributesOnlyRequestControl)
+      {
+        return (RealAttributesOnlyRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_REAL_ATTRS_ONLY_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_REAL_ATTRS_ONLY_INVALID_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new real attributes only request control having the provided
+   * criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static RealAttributesOnlyRequestControl newControl(
+      final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private final boolean isCritical;
+
+
+
+  private RealAttributesOnlyRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("RealAttributesOnlyRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/VirtualAttributesOnlyRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/VirtualAttributesOnlyRequestControl.java
new file mode 100644
index 0000000..023348f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/VirtualAttributesOnlyRequestControl.java
@@ -0,0 +1,192 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_VIRTUAL_ATTRS_ONLY_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_VIRTUAL_ATTRS_ONLY_INVALID_CONTROL_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The Sun-defined virtual attributes only request control. The OID for this
+ * control is 2.16.840.1.113730.3.4.19, and it does not have a value.
+ */
+public final class VirtualAttributesOnlyRequestControl implements Control
+{
+  /**
+   * The OID for the virtual attributes only request control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.19";
+
+  private static final VirtualAttributesOnlyRequestControl CRITICAL_INSTANCE =
+    new VirtualAttributesOnlyRequestControl(true);
+
+  private static final VirtualAttributesOnlyRequestControl NONCRITICAL_INSTANCE =
+    new VirtualAttributesOnlyRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the virtual attributes only
+   * request control.
+   */
+  public static final ControlDecoder<VirtualAttributesOnlyRequestControl>
+    DECODER = new ControlDecoder<VirtualAttributesOnlyRequestControl>()
+  {
+
+    public VirtualAttributesOnlyRequestControl decodeControl(
+        final Control control, final DecodeOptions options)
+        throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof VirtualAttributesOnlyRequestControl)
+      {
+        return (VirtualAttributesOnlyRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_VIRTUAL_ATTRS_ONLY_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_VIRTUAL_ATTRS_ONLY_INVALID_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new virtual attributes only request control having the provided
+   * criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static VirtualAttributesOnlyRequestControl newControl(
+      final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private final boolean isCritical;
+
+
+
+  private VirtualAttributesOnlyRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("VirtualAttributesOnlyRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/package-info.java
new file mode 100644
index 0000000..d35f771
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/controls/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes implementing Sun proprietary LDAP controls.
+ */
+package com.sun.opends.sdk.controls;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedRequest.java
new file mode 100644
index 0000000..6b185e3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedRequest.java
@@ -0,0 +1,249 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.requests.AbstractExtendedRequest;
+import org.opends.sdk.requests.ExtendedRequest;
+import org.opends.sdk.requests.ExtendedRequestDecoder;
+import org.opends.sdk.responses.AbstractExtendedResultDecoder;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+
+
+/**
+ * Get connection ID extended request. This operation can be used to retrieve
+ * the client connection ID.
+ *
+ * @see GetConnectionIDExtendedResult
+ */
+public final class GetConnectionIDExtendedRequest
+    extends
+    AbstractExtendedRequest<GetConnectionIDExtendedRequest, GetConnectionIDExtendedResult>
+{
+  private static final class RequestDecoder
+      implements
+      ExtendedRequestDecoder<GetConnectionIDExtendedRequest, GetConnectionIDExtendedResult>
+  {
+
+    public GetConnectionIDExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      // TODO: Check the OID and that the value is not present.
+      final GetConnectionIDExtendedRequest newRequest = new GetConnectionIDExtendedRequest();
+      for (final Control control : request.getControls())
+      {
+        newRequest.addControl(control);
+      }
+      return newRequest;
+
+    }
+  }
+
+
+
+  private static final class ResultDecoder extends
+      AbstractExtendedResultDecoder<GetConnectionIDExtendedResult>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public GetConnectionIDExtendedResult newExtendedErrorResult(
+        final ResultCode resultCode, final String matchedDN,
+        final String diagnosticMessage)
+    {
+      if (!resultCode.isExceptional())
+      {
+        // A successful response must contain a response name and
+        // value.
+        throw new IllegalArgumentException(
+            "No response name and value for result code "
+                + resultCode.intValue());
+      }
+      return GetConnectionIDExtendedResult.newResult(resultCode, -1)
+          .setMatchedDN(matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public GetConnectionIDExtendedResult decodeExtendedResult(
+        final ExtendedResult result, final DecodeOptions options)
+        throws DecodeException
+    {
+      if (result instanceof GetConnectionIDExtendedResult)
+      {
+        return (GetConnectionIDExtendedResult) result;
+      }
+      else
+      {
+        final ResultCode resultCode = result.getResultCode();
+        final ByteString responseValue = result.getValue();
+
+        if (!resultCode.isExceptional()
+            && ((responseValue == null) || (responseValue.length() <= 0)))
+        {
+          throw DecodeException.error(LocalizableMessage
+              .raw("Empty response value"));
+        }
+
+        try
+        {
+          final ASN1Reader reader = ASN1.getReader(responseValue);
+          final int connectionID = (int) reader.readInteger();
+          final GetConnectionIDExtendedResult newResult = GetConnectionIDExtendedResult
+              .newResult(resultCode, connectionID).setMatchedDN(
+                  result.getMatchedDN()).setDiagnosticMessage(
+                  result.getDiagnosticMessage());
+
+          for (final Control control : result.getControls())
+          {
+            newResult.addControl(control);
+          }
+
+          return newResult;
+        }
+        catch (final IOException e)
+        {
+          throw DecodeException.error(LocalizableMessage
+              .raw("Error decoding response value"), e);
+        }
+      }
+    }
+  }
+
+
+
+  /**
+   * The OID for the extended operation that can be used to get the client
+   * connection ID. It will be both the request and response OID.
+   */
+  public static final String OID = "1.3.6.1.4.1.26027.1.6.2";
+
+  // Singleton.
+  private static final GetConnectionIDExtendedRequest INSTANCE =
+    new GetConnectionIDExtendedRequest();
+
+  /**
+   * A decoder which can be used to decode get connection ID extended operation
+   * requests.
+   */
+  public static final RequestDecoder REQUEST_DECODER = new RequestDecoder();
+
+  // No need to expose this.
+  private static final ResultDecoder RESULT_DECODER = new ResultDecoder();
+
+
+
+  /**
+   * Creates a new get connection ID extended request.
+   *
+   * @return The new get connection ID extended request.
+   */
+  public static GetConnectionIDExtendedRequest newRequest()
+  {
+    return INSTANCE;
+  }
+
+
+
+  // Prevent instantiation.
+  private GetConnectionIDExtendedRequest()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<GetConnectionIDExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GetConnectionIDExtendedRequest(requestName=");
+    builder.append(getOID());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.java
new file mode 100644
index 0000000..7ed2385
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetConnectionIDExtendedResult.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.responses.AbstractExtendedResult;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+/**
+ * Get connection ID extended result.
+ *
+ * @see GetConnectionIDExtendedRequest
+ */
+public final class GetConnectionIDExtendedResult extends
+    AbstractExtendedResult<GetConnectionIDExtendedResult>
+{
+  /**
+   * Creates a new get connection ID extended result.
+   *
+   * @param resultCode
+   *          The result code.
+   * @param connectionID
+   *          The client connection ID.
+   * @return The new get connection ID extended result.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static GetConnectionIDExtendedResult newResult(
+      final ResultCode resultCode, final int connectionID)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+    return new GetConnectionIDExtendedResult(resultCode, connectionID);
+  }
+
+
+
+  private int connectionID;
+
+
+
+  private GetConnectionIDExtendedResult(final ResultCode resultCode,
+      final int connectionID)
+  {
+    super(resultCode);
+    this.connectionID = connectionID;
+  }
+
+
+
+  /**
+   * Returns the client connection ID.
+   *
+   * @return The client connection ID.
+   */
+  public int getConnectionID()
+  {
+    return connectionID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return GetConnectionIDExtendedRequest.OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder(6);
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+
+    try
+    {
+      writer.writeInteger(connectionID);
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+
+    return buffer.toByteString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Sets the client connection ID.
+   *
+   * @param connectionID
+   *          The client connection ID.
+   * @return This get connection ID result.
+   */
+  public GetConnectionIDExtendedResult setConnectionID(final int connectionID)
+  {
+    this.connectionID = connectionID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GetConnectionIDExtendedResponse(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", responseName=");
+    builder.append(getOID());
+    builder.append(", connectionID=");
+    builder.append(connectionID);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetSymmetricKeyExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetSymmetricKeyExtendedRequest.java
new file mode 100644
index 0000000..30ad68f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/GetSymmetricKeyExtendedRequest.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_GET_SYMMETRIC_KEY_ASN1_DECODE_EXCEPTION;
+import static com.sun.opends.sdk.messages.Messages.ERR_GET_SYMMETRIC_KEY_NO_VALUE;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.requests.AbstractExtendedRequest;
+import org.opends.sdk.requests.ExtendedRequest;
+import org.opends.sdk.requests.ExtendedRequestDecoder;
+import org.opends.sdk.responses.AbstractExtendedResultDecoder;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+import org.opends.sdk.responses.Responses;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Get symmetric key extended request.
+ */
+public final class GetSymmetricKeyExtendedRequest extends
+    AbstractExtendedRequest<GetSymmetricKeyExtendedRequest, ExtendedResult>
+{
+  private static final class RequestDecoder implements
+      ExtendedRequestDecoder<GetSymmetricKeyExtendedRequest, ExtendedResult>
+  {
+
+    public GetSymmetricKeyExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      final ByteString requestValue = request.getValue();
+      if (requestValue == null)
+      {
+        // The request must always have a value.
+        final LocalizableMessage message = ERR_GET_SYMMETRIC_KEY_NO_VALUE.get();
+        throw DecodeException.error(message);
+      }
+
+      String requestSymmetricKey = null;
+      String instanceKeyID = null;
+
+      try
+      {
+        final ASN1Reader reader = ASN1.getReader(requestValue);
+        reader.readStartSequence();
+        if (reader.hasNextElement()
+            && (reader.peekType() == TYPE_SYMMETRIC_KEY_ELEMENT))
+        {
+          requestSymmetricKey = reader.readOctetStringAsString();
+        }
+        if (reader.hasNextElement()
+            && (reader.peekType() == TYPE_INSTANCE_KEY_ID_ELEMENT))
+        {
+          instanceKeyID = reader.readOctetStringAsString();
+        }
+        reader.readEndSequence();
+
+        final GetSymmetricKeyExtendedRequest newRequest = new GetSymmetricKeyExtendedRequest()
+            .setRequestSymmetricKey(requestSymmetricKey).setInstanceKeyID(
+                instanceKeyID);
+
+        for (final Control control : request.getControls())
+        {
+          newRequest.addControl(control);
+        }
+
+        return newRequest;
+      }
+      catch (final IOException ae)
+      {
+        StaticUtils.DEBUG_LOG.throwing("GetSymmetricKeyRequest.Operation",
+            "decodeRequest", ae);
+
+        final LocalizableMessage message = ERR_GET_SYMMETRIC_KEY_ASN1_DECODE_EXCEPTION
+            .get(ae.getMessage());
+        throw DecodeException.error(message, ae);
+      }
+    }
+  }
+
+
+
+  private static final class ResultDecoder extends
+      AbstractExtendedResultDecoder<ExtendedResult>
+  {
+
+    public ExtendedResult newExtendedErrorResult(final ResultCode resultCode,
+        final String matchedDN, final String diagnosticMessage)
+    {
+      return Responses.newGenericExtendedResult(resultCode).setMatchedDN(
+          matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public ExtendedResult decodeExtendedResult(final ExtendedResult result,
+        final DecodeOptions options) throws DecodeException
+    {
+      return result;
+    }
+  }
+
+
+
+  /**
+   * The request OID for the get symmetric key extended operation.
+   */
+  public static final String OID = "1.3.6.1.4.1.26027.1.6.3";
+
+  /**
+   * The BER type value for the symmetric key element of the operation value.
+   */
+  private static final byte TYPE_SYMMETRIC_KEY_ELEMENT = (byte) 0x80;
+
+  /**
+   * The BER type value for the instance key ID element of the operation value.
+   */
+  private static final byte TYPE_INSTANCE_KEY_ID_ELEMENT = (byte) 0x81;
+
+  /**
+   * A decoder which can be used to decode get symmetric key extended operation
+   * requests.
+   */
+  public static final RequestDecoder REQUEST_DECODER = new RequestDecoder();
+
+  // No need to expose this.
+  private static final ResultDecoder RESULT_DECODER = new ResultDecoder();
+
+
+
+  /**
+   * Creates a new get symmetric key extended request.
+   *
+   * @return The new get symmetric key extended request.
+   */
+  public static GetSymmetricKeyExtendedRequest newRequest()
+  {
+    return new GetSymmetricKeyExtendedRequest();
+  }
+
+
+
+  private String requestSymmetricKey = null;
+
+  private String instanceKeyID = null;
+
+
+
+  // Instantiation via factory.
+  private GetSymmetricKeyExtendedRequest()
+  {
+
+  }
+
+
+
+  /**
+   * Returns the instance key ID.
+   *
+   * @return The instance key ID.
+   */
+  public String getInstanceKeyID()
+  {
+    return instanceKeyID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns the request symmetric key.
+   *
+   * @return The request symmetric key.
+   */
+  public String getRequestSymmetricKey()
+  {
+    return requestSymmetricKey;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<ExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+
+    try
+    {
+      writer.writeStartSequence();
+      if (requestSymmetricKey != null)
+      {
+        writer
+            .writeOctetString(TYPE_SYMMETRIC_KEY_ELEMENT, requestSymmetricKey);
+      }
+      if (instanceKeyID != null)
+      {
+        writer.writeOctetString(TYPE_INSTANCE_KEY_ID_ELEMENT, instanceKeyID);
+      }
+      writer.writeEndSequence();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+
+    return buffer.toByteString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Sets the instance key ID.
+   *
+   * @param instanceKeyID
+   *          The instance key ID.
+   * @return This get symmetric key request.
+   */
+  public GetSymmetricKeyExtendedRequest setInstanceKeyID(
+      final String instanceKeyID)
+  {
+    this.instanceKeyID = instanceKeyID;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the request symmetric key.
+   *
+   * @param requestSymmetricKey
+   *          The request symmetric key.
+   * @return This get symmetric key request.
+   */
+  public GetSymmetricKeyExtendedRequest setRequestSymmetricKey(
+      final String requestSymmetricKey)
+  {
+    this.requestSymmetricKey = requestSymmetricKey;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GetSymmetricKeyExtendedRequest(requestName=");
+    builder.append(getOID());
+    builder.append(", requestSymmetricKey=");
+    builder.append(requestSymmetricKey);
+    builder.append(", instanceKeyID=");
+    builder.append(instanceKeyID);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedRequest.java
new file mode 100644
index 0000000..c73adab
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedRequest.java
@@ -0,0 +1,1140 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_PWPSTATE_EXTOP_DECODE_FAILURE;
+import static com.sun.opends.sdk.messages.Messages.ERR_PWPSTATE_EXTOP_NO_REQUEST_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_PWPSTATE_EXTOP_UNKNOWN_OP_TYPE;
+import static com.sun.opends.sdk.util.StaticUtils.formatAsGeneralizedTime;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.requests.AbstractExtendedRequest;
+import org.opends.sdk.requests.ExtendedRequest;
+import org.opends.sdk.requests.ExtendedRequestDecoder;
+import org.opends.sdk.responses.AbstractExtendedResultDecoder;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class implements an LDAP extended operation that can be used to query
+ * and update elements of the Directory Server password policy state for a given
+ * user. The ASN.1 definition for the value of the extended request is: <BR>
+ *
+ * <PRE>
+ * PasswordPolicyStateValue ::= SEQUENCE {
+ *      targetUser     LDAPDN
+ *      operations     SEQUENCE OF PasswordPolicyStateOperation OPTIONAL }
+ * PasswordPolicyStateOperation ::= SEQUENCE {
+ *      opType       ENUMERATED {
+ *           getPasswordPolicyDN                          (0),
+ *           getAccountDisabledState                      (1),
+ *           setAccountDisabledState                      (2),
+ *           clearAccountDisabledState                    (3),
+ *           getAccountExpirationTime                     (4),
+ *           setAccountExpirationTime                     (5),
+ *           clearAccountExpirationTime                   (6),
+ *           getSecondsUntilAccountExpiration             (7),
+ *           getPasswordChangedTime                       (8),
+ *           setPasswordChangedTime                       (9),
+ *           clearPasswordChangedTime                     (10),
+ *           getPasswordExpirationWarnedTime              (11),
+ *           setPasswordExpirationWarnedTime              (12),
+ *           clearPasswordExpirationWarnedTime            (13),
+ *           getSecondsUntilPasswordExpiration            (14),
+ *           getSecondsUntilPasswordExpirationWarning     (15),
+ *           getAuthenticationFailureTimes                (16),
+ *           addAuthenticationFailureTime                 (17),
+ *           setAuthenticationFailureTimes                (18),
+ *           clearAuthenticationFailureTimes              (19),
+ *           getSecondsUntilAuthenticationFailureUnlock   (20),
+ *           getRemainingAuthenticationFailureCount       (21),
+ *           getLastLoginTime                             (22),
+ *           setLastLoginTime                             (23),
+ *           clearLastLoginTime                           (24),
+ *           getSecondsUntilIdleLockout                   (25),
+ *           getPasswordResetState                        (26),
+ *           setPasswordResetState                        (27),
+ *           clearPasswordResetState                      (28),
+ *           getSecondsUntilPasswordResetLockout          (29),
+ *           getGraceLoginUseTimes                        (30),
+ *           addGraceLoginUseTime                         (31),
+ *           setGraceLoginUseTimes                        (32),
+ *           clearGraceLoginUseTimes                      (33),
+ *           getRemainingGraceLoginCount                  (34),
+ *           getPasswordChangedByRequiredTime             (35),
+ *           setPasswordChangedByRequiredTime             (36),
+ *           clearPasswordChangedByRequiredTime           (37),
+ *           getSecondsUntilRequiredChangeTime            (38),
+ *           getPasswordHistory                           (39),
+ *           clearPasswordHistory                         (40),
+ *           ... },
+ *      opValues     SEQUENCE OF OCTET STRING OPTIONAL }
+ * </PRE>
+ *
+ * <BR>
+ * Both the request and response values use the same encoded form, and they both
+ * use the same OID of "1.3.6.1.4.1.26027.1.6.1". The response value will only
+ * include get* elements. If the request did not include any operations, then
+ * the response will include all get* elements; otherwise, the response will
+ * only include the get* elements that correspond to the state fields referenced
+ * in the request (regardless of whether that operation was included in a get*,
+ * set*, add*, remove*, or clear* operation).
+ */
+public final class PasswordPolicyStateExtendedRequest
+    extends
+    AbstractExtendedRequest<PasswordPolicyStateExtendedRequest, PasswordPolicyStateExtendedResult>
+    implements PasswordPolicyStateOperationContainer
+{
+  private static final class MultiValueOperation implements
+      PasswordPolicyStateOperation
+  {
+    private final PasswordPolicyStateOperationType property;
+
+    private final List<ByteString> values;
+
+
+
+    private MultiValueOperation(
+        final PasswordPolicyStateOperationType property, final ByteString value)
+    {
+      this.property = property;
+      this.values = Collections.singletonList(value);
+    }
+
+
+
+    private MultiValueOperation(
+        final PasswordPolicyStateOperationType property,
+        final List<ByteString> values)
+    {
+      this.property = property;
+      this.values = values;
+    }
+
+
+
+    public PasswordPolicyStateOperationType getOperationType()
+    {
+      return property;
+    }
+
+
+
+    public Iterable<ByteString> getValues()
+    {
+      return values;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+      return property.toString() + ": " + values;
+    }
+  }
+
+
+
+  private static final class RequestDecoder
+      implements
+      ExtendedRequestDecoder<PasswordPolicyStateExtendedRequest, PasswordPolicyStateExtendedResult>
+  {
+
+    public PasswordPolicyStateExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      final ByteString requestValue = request.getValue();
+
+      if ((requestValue == null) || (requestValue.length() <= 0))
+      {
+        throw DecodeException.error(ERR_PWPSTATE_EXTOP_NO_REQUEST_VALUE.get());
+      }
+
+      try
+      {
+        final ASN1Reader reader = ASN1.getReader(requestValue);
+        reader.readStartSequence();
+
+        // Read the target user DN
+        final PasswordPolicyStateExtendedRequest newRequest =
+          new PasswordPolicyStateExtendedRequest(
+              reader.readOctetStringAsString());
+
+        decodeOperations(reader, newRequest);
+        reader.readEndSequence();
+
+        for (final Control control : request.getControls())
+        {
+          newRequest.addControl(control);
+        }
+
+        return newRequest;
+      }
+      catch (final IOException ioe)
+      {
+        final LocalizableMessage message = ERR_PWPSTATE_EXTOP_DECODE_FAILURE
+            .get(getExceptionMessage(ioe));
+        throw DecodeException.error(message, ioe);
+      }
+    }
+  }
+
+
+
+  private static final class ResultDecoder extends
+      AbstractExtendedResultDecoder<PasswordPolicyStateExtendedResult>
+  {
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordPolicyStateExtendedResult newExtendedErrorResult(
+        final ResultCode resultCode, final String matchedDN,
+        final String diagnosticMessage)
+    {
+      if (!resultCode.isExceptional())
+      {
+        // A successful response must contain a response name and
+        // value.
+        throw new IllegalArgumentException(
+            "No response name and value for result code "
+                + resultCode.intValue());
+      }
+
+      return new PasswordPolicyStateExtendedResult(resultCode, (String) null)
+          .setMatchedDN(matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public PasswordPolicyStateExtendedResult decodeExtendedResult(
+        final ExtendedResult result, final DecodeOptions options)
+        throws DecodeException
+    {
+      final ResultCode resultCode = result.getResultCode();
+      final ByteString responseValue = result.getValue();
+
+      if (!resultCode.isExceptional()
+          && ((responseValue == null) || (responseValue.length() <= 0)))
+      {
+        throw DecodeException.error(ERR_PWPSTATE_EXTOP_NO_REQUEST_VALUE.get());
+      }
+
+      try
+      {
+        final ASN1Reader reader = ASN1.getReader(responseValue);
+        reader.readStartSequence();
+
+        // Read the target user DN
+        final PasswordPolicyStateExtendedResult newResult = new PasswordPolicyStateExtendedResult(
+            resultCode, reader.readOctetStringAsString()).setMatchedDN(
+            result.getMatchedDN()).setDiagnosticMessage(
+            result.getDiagnosticMessage());
+
+        decodeOperations(reader, newResult);
+        reader.readEndSequence();
+
+        for (final Control control : result.getControls())
+        {
+          newResult.addControl(control);
+        }
+
+        return newResult;
+      }
+      catch (final IOException ioe)
+      {
+        final LocalizableMessage message = ERR_PWPSTATE_EXTOP_DECODE_FAILURE
+            .get(getExceptionMessage(ioe));
+        throw DecodeException.error(message, ioe);
+      }
+    }
+  }
+
+
+
+  /**
+   * The OID for the password policy state extended operation (both the request
+   * and response types).
+   */
+  public static final String OID = "1.3.6.1.4.1.26027.1.6.1";
+
+  private final String targetUser;
+
+  private final List<PasswordPolicyStateOperation> operations =
+    new ArrayList<PasswordPolicyStateOperation>();
+
+  static final String PASSWORD_POLICY_DN_NAME = "Password Policy DN";
+
+  static final String ACCOUNT_DISABLED_STATE_NAME = "Account Disabled State";
+
+  static final String ACCOUNT_EXPIRATION_TIME_NAME = "Account Expiration Time";
+
+  static final String SECONDS_UNTIL_ACCOUNT_EXPIRATION_NAME =
+    "Seconds Until Account Expiration";
+
+  static final String PASSWORD_CHANGED_TIME_NAME = "Password Changed Time";
+
+  static final String PASSWORD_EXPIRATION_WARNED_TIME_NAME =
+    "Password Expiration Warned Time";
+
+  static final String SECONDS_UNTIL_PASSWORD_EXPIRATION_NAME =
+    "Seconds Until Password Expiration";
+
+  static final String SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING_NAME =
+    "Seconds Until Password Expiration Warning";
+
+  static final String AUTHENTICATION_FAILURE_TIMES_NAME =
+    "Authentication Failure Times";
+
+  static final String SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK_NAME =
+    "Seconds Until Authentication Failure Unlock";
+
+  static final String REMAINING_AUTHENTICATION_FAILURE_COUNT_NAME =
+    "Remaining Authentication Failure Count";
+
+  static final String LAST_LOGIN_TIME_NAME = "Last Login Time";
+
+  static final String SECONDS_UNTIL_IDLE_LOCKOUT_NAME =
+    "Seconds Until Idle Lockout";
+
+  static final String PASSWORD_RESET_STATE_NAME = "Password Reset State";
+
+  static final String SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT_NAME =
+    "Seconds Until Password Reset Lockout";
+
+  static final String GRACE_LOGIN_USE_TIMES_NAME = "Grace Login Use Times";
+
+  static final String REMAINING_GRACE_LOGIN_COUNT_NAME =
+    "Remaining Grace Login Count";
+
+  static final String PASSWORD_CHANGED_BY_REQUIRED_TIME_NAME =
+    "Password Changed By Required Time";
+
+  static final String SECONDS_UNTIL_REQUIRED_CHANGE_TIME_NAME =
+    "Seconds Until Required Change Time";
+
+  static final String PASSWORD_HISTORY_NAME = "Password History";
+
+  /**
+   * A decoder which can be used to decode password policy state extended
+   * operation requests.
+   */
+  public static final RequestDecoder REQUEST_DECODER = new RequestDecoder();
+
+  // No need to expose this.
+  private static final ResultDecoder RESULT_DECODER = new ResultDecoder();
+
+
+
+  static ByteString encode(final String targetUser,
+      final List<PasswordPolicyStateOperation> operations)
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder(6);
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeOctetString(targetUser);
+      if (!operations.isEmpty())
+      {
+        writer.writeStartSequence();
+        for (final PasswordPolicyStateOperation operation : operations)
+        {
+          writer.writeStartSequence();
+          writer.writeEnumerated(operation.getOperationType().ordinal());
+          if (operation.getValues() != null)
+          {
+            writer.writeStartSequence();
+            for (final ByteString value : operation.getValues())
+            {
+              writer.writeOctetString(value);
+            }
+            writer.writeEndSequence();
+          }
+          writer.writeEndSequence();
+        }
+        writer.writeEndSequence();
+      }
+      writer.writeEndSequence();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+
+    return buffer.toByteString();
+  }
+
+
+
+  private static void decodeOperations(final ASN1Reader reader,
+      final PasswordPolicyStateOperationContainer container)
+      throws IOException, DecodeException
+  {
+    // See if we have operations
+    if (reader.hasNextElement())
+    {
+      reader.readStartSequence();
+      int opType;
+      PasswordPolicyStateOperationType type;
+      while (reader.hasNextElement())
+      {
+        reader.readStartSequence();
+        // Read the opType
+        opType = reader.readEnumerated();
+        try
+        {
+          type = PasswordPolicyStateOperationType.values()[opType];
+        }
+        catch (final IndexOutOfBoundsException iobe)
+        {
+          throw DecodeException.error(ERR_PWPSTATE_EXTOP_UNKNOWN_OP_TYPE
+              .get(String.valueOf(opType)), iobe);
+        }
+
+        // See if we have any values
+        if (reader.hasNextElement())
+        {
+          reader.readStartSequence();
+          final ArrayList<ByteString> values = new ArrayList<ByteString>();
+          while (reader.hasNextElement())
+          {
+            values.add(reader.readOctetString());
+          }
+          reader.readEndSequence();
+          container.addOperation(new MultiValueOperation(type, values));
+        }
+        else
+        {
+          container.addOperation(type);
+        }
+        reader.readEndSequence();
+      }
+      reader.readEndSequence();
+    }
+  }
+
+
+
+  /**
+   * Creates a new password policy state extended request using the provided
+   * user name.
+   *
+   * @param targetUser
+   *          The name of the user.
+   */
+  public PasswordPolicyStateExtendedRequest(final DN targetUser)
+  {
+    Validator.ensureNotNull(targetUser);
+    this.targetUser = targetUser.toString();
+  }
+
+
+
+  /**
+   * Creates a new password policy state extended request using the provided
+   * user name.
+   *
+   * @param targetUser
+   *          The name of the user.
+   */
+  public PasswordPolicyStateExtendedRequest(final String targetUser)
+  {
+    Validator.ensureNotNull(targetUser);
+    this.targetUser = targetUser;
+  }
+
+
+
+  /**
+   * Adds the provided authentication failure time to this request.
+   *
+   * @param date
+   *          The authentication failure time.
+   */
+  public void addAuthenticationFailureTime(final Date date)
+  {
+    if (date == null)
+    {
+      operations
+          .add(PasswordPolicyStateOperationType.ADD_AUTHENTICATION_FAILURE_TIMES);
+    }
+    else
+    {
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.ADD_AUTHENTICATION_FAILURE_TIMES,
+          ByteString.valueOf(formatAsGeneralizedTime(date))));
+    }
+  }
+
+
+
+  /**
+   * Adds the provided grace login use time to this request.
+   *
+   * @param date
+   *          The grace login use time.
+   */
+  public void addGraceLoginUseTime(final Date date)
+  {
+    if (date == null)
+    {
+      operations.add(PasswordPolicyStateOperationType.ADD_GRACE_LOGIN_USE_TIME);
+    }
+    else
+    {
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.ADD_GRACE_LOGIN_USE_TIME, ByteString
+              .valueOf(formatAsGeneralizedTime(date))));
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void addOperation(final PasswordPolicyStateOperation operation)
+  {
+    operations.add(operation);
+  }
+
+
+
+  /**
+   * Clears the account disabled state.
+   */
+  public void clearAccountDisabledState()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.CLEAR_ACCOUNT_DISABLED_STATE);
+  }
+
+
+
+  /**
+   * Clears the account expiration time.
+   */
+  public void clearAccountExpirationTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.CLEAR_ACCOUNT_EXPIRATION_TIME);
+  }
+
+
+
+  /**
+   * Clears the authentication failure times.
+   */
+  public void clearAuthenticationFailureTimes()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.CLEAR_AUTHENTICATION_FAILURE_TIMES);
+  }
+
+
+
+  /**
+   * Clears the grace login use times.
+   */
+  public void clearGraceLoginUseTimes()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.CLEAR_GRACE_LOGIN_USE_TIMES);
+  }
+
+
+
+  /**
+   * Clears the last login time.
+   */
+  public void clearLastLoginTime()
+  {
+    operations.add(PasswordPolicyStateOperationType.CLEAR_LAST_LOGIN_TIME);
+  }
+
+
+
+  /**
+   * Clears the password changed by required time.
+   */
+  public void clearPasswordChangedByRequiredTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME);
+  }
+
+
+
+  /**
+   * Clears the password changed time.
+   */
+  public void clearPasswordChangedTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.CLEAR_PASSWORD_CHANGED_TIME);
+  }
+
+
+
+  /**
+   * Clears the password expiration warned time.
+   */
+  public void clearPasswordExpirationWarnedTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.CLEAR_PASSWORD_EXPIRATION_WARNED_TIME);
+  }
+
+
+
+  /**
+   * Clears the password history.
+   */
+  public void clearPasswordHistory()
+  {
+    operations.add(PasswordPolicyStateOperationType.CLEAR_PASSWORD_HISTORY);
+  }
+
+
+
+  /**
+   * Clears the password reset state.
+   */
+  public void clearPasswordResetState()
+  {
+    operations.add(PasswordPolicyStateOperationType.CLEAR_PASSWORD_RESET_STATE);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<PasswordPolicyStateOperation> getOperations()
+  {
+    return operations;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<PasswordPolicyStateExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return encode(targetUser, operations);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Returns the account disabled state.
+   */
+  public void requestAccountDisabledState()
+  {
+    operations.add(PasswordPolicyStateOperationType.GET_ACCOUNT_DISABLED_STATE);
+  }
+
+
+
+  /**
+   * Returns the account expiration time.
+   */
+  public void requestAccountExpirationTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_ACCOUNT_EXPIRATION_TIME);
+  }
+
+
+
+  /**
+   * Returns the authentication failure times.
+   */
+  public void requestAuthenticationFailureTimes()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_AUTHENTICATION_FAILURE_TIMES);
+  }
+
+
+
+  /**
+   * Returns the grace login use times.
+   */
+  public void requestGraceLoginUseTimes()
+  {
+    operations.add(PasswordPolicyStateOperationType.GET_GRACE_LOGIN_USE_TIMES);
+  }
+
+
+
+  /**
+   * Returns the last login time.
+   */
+  public void requestLastLoginTime()
+  {
+    operations.add(PasswordPolicyStateOperationType.GET_LAST_LOGIN_TIME);
+  }
+
+
+
+  /**
+   * Returns the password changed by required time.
+   */
+  public void requestPasswordChangedByRequiredTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_PASSWORD_CHANGED_BY_REQUIRED_TIME);
+  }
+
+
+
+  /**
+   * Returns the password changed time.
+   */
+  public void requestPasswordChangedTime()
+  {
+    operations.add(PasswordPolicyStateOperationType.GET_PASSWORD_CHANGED_TIME);
+  }
+
+
+
+  /**
+   * Returns the password expiration warned time.
+   */
+  public void requestPasswordExpirationWarnedTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_PASSWORD_EXPIRATION_WARNED_TIME);
+  }
+
+
+
+  /**
+   * Returns the password history.
+   */
+  public void requestPasswordHistory()
+  {
+    operations.add(PasswordPolicyStateOperationType.GET_PASSWORD_HISTORY);
+  }
+
+
+
+  /**
+   * Returns the password policy DN.
+   */
+  public void requestPasswordPolicyDN()
+  {
+    operations.add(PasswordPolicyStateOperationType.GET_PASSWORD_POLICY_DN);
+  }
+
+
+
+  /**
+   * Returns the password reset state.
+   */
+  public void requestPasswordResetState()
+  {
+    operations.add(PasswordPolicyStateOperationType.GET_PASSWORD_RESET_STATE);
+  }
+
+
+
+  /**
+   * Returns the remaining authentication failure count.
+   */
+  public void requestRemainingAuthenticationFailureCount()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_REMAINING_AUTHENTICATION_FAILURE_COUNT);
+  }
+
+
+
+  /**
+   * Returns the remaining grace login count.
+   */
+  public void requestRemainingGraceLoginCount()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_REMAINING_GRACE_LOGIN_COUNT);
+  }
+
+
+
+  /**
+   * Returns the seconds until account expiration.
+   */
+  public void requestSecondsUntilAccountExpiration()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION);
+  }
+
+
+
+  /**
+   * Returns the seconds until authentication failure unlock.
+   */
+  public void requestSecondsUntilAuthenticationFailureUnlock()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK);
+  }
+
+
+
+  /**
+   * Returns the seconds until idle lockout.
+   */
+  public void requestSecondsUntilIdleLockout()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_SECONDS_UNTIL_IDLE_LOCKOUT);
+  }
+
+
+
+  /**
+   * Returns the seconds until password expiration.
+   */
+  public void requestSecondsUntilPasswordExpiration()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_SECONDS_UNTIL_PASSWORD_EXPIRATION);
+  }
+
+
+
+  /**
+   * Returns the seconds until password expiration warning.
+   */
+  public void requestSecondsUntilPasswordExpirationWarning()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING);
+  }
+
+
+
+  /**
+   * Returns the seconds until password reset lockout.
+   */
+  public void requestSecondsUntilPasswordResetLockout()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT);
+  }
+
+
+
+  /**
+   * Returns the seconds until required change time.
+   */
+  public void requestSecondsUntilRequiredChangeTime()
+  {
+    operations
+        .add(PasswordPolicyStateOperationType.GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME);
+  }
+
+
+
+  /**
+   * Sets the account disabled state.
+   *
+   * @param state
+   *          The account disabled state.
+   */
+  public void setAccountDisabledState(final boolean state)
+  {
+    operations.add(new MultiValueOperation(
+        PasswordPolicyStateOperationType.SET_ACCOUNT_DISABLED_STATE, ByteString
+            .valueOf(String.valueOf(state))));
+  }
+
+
+
+  /**
+   * Sets the account expiration time.
+   *
+   * @param date
+   *          The account expiration time.
+   */
+  public void setAccountExpirationTime(final Date date)
+  {
+    if (date == null)
+    {
+      operations
+          .add(PasswordPolicyStateOperationType.SET_ACCOUNT_EXPIRATION_TIME);
+    }
+    else
+    {
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.SET_ACCOUNT_EXPIRATION_TIME,
+          ByteString.valueOf(formatAsGeneralizedTime(date))));
+    }
+  }
+
+
+
+  /**
+   * Sets the authentication failure times.
+   *
+   * @param dates
+   *          The authentication failure times.
+   */
+  public void setAuthenticationFailureTimes(final Date... dates)
+  {
+    if (dates == null)
+    {
+      operations
+          .add(PasswordPolicyStateOperationType.SET_AUTHENTICATION_FAILURE_TIMES);
+    }
+    else
+    {
+      final ArrayList<ByteString> times = new ArrayList<ByteString>(
+          dates.length);
+      for (final Date date : dates)
+      {
+        times.add(ByteString.valueOf(formatAsGeneralizedTime(date)));
+      }
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.SET_AUTHENTICATION_FAILURE_TIMES,
+          times));
+    }
+  }
+
+
+
+  /**
+   * Sets the grace login use times.
+   *
+   * @param dates
+   *          The grace login use times.
+   */
+  public void setGraceLoginUseTimes(final Date... dates)
+  {
+    if (dates == null)
+    {
+      operations
+          .add(PasswordPolicyStateOperationType.SET_GRACE_LOGIN_USE_TIMES);
+    }
+    else
+    {
+      final ArrayList<ByteString> times = new ArrayList<ByteString>(
+          dates.length);
+      for (final Date date : dates)
+      {
+        times.add(ByteString.valueOf(formatAsGeneralizedTime(date)));
+      }
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.SET_GRACE_LOGIN_USE_TIMES, times));
+    }
+  }
+
+
+
+  /**
+   * Sets the last login time.
+   *
+   * @param date
+   *          The last login time.
+   */
+  public void setLastLoginTime(final Date date)
+  {
+    if (date == null)
+    {
+      operations.add(PasswordPolicyStateOperationType.SET_LAST_LOGIN_TIME);
+
+    }
+    else
+    {
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.SET_LAST_LOGIN_TIME, ByteString
+              .valueOf(formatAsGeneralizedTime(date))));
+    }
+  }
+
+
+
+  /**
+   * Sets the password changed by required time.
+   *
+   * @param state
+   *          The password changed by required time.
+   */
+  public void setPasswordChangedByRequiredTime(final boolean state)
+  {
+    operations.add(new MultiValueOperation(
+        PasswordPolicyStateOperationType.SET_PASSWORD_CHANGED_BY_REQUIRED_TIME,
+        ByteString.valueOf(String.valueOf(state))));
+  }
+
+
+
+  /**
+   * Sets the password changed time.
+   *
+   * @param date
+   *          The password changed time.
+   */
+  public void setPasswordChangedTime(final Date date)
+  {
+    if (date == null)
+    {
+      operations
+          .add(PasswordPolicyStateOperationType.SET_PASSWORD_CHANGED_TIME);
+    }
+    else
+    {
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.SET_PASSWORD_CHANGED_TIME,
+          ByteString.valueOf(formatAsGeneralizedTime(date))));
+    }
+  }
+
+
+
+  /**
+   * Sets the password expiration warned time.
+   *
+   * @param date
+   *          The password expiration warned time.
+   */
+  public void setPasswordExpirationWarnedTime(final Date date)
+  {
+    if (date == null)
+    {
+      operations
+          .add(PasswordPolicyStateOperationType.SET_PASSWORD_EXPIRATION_WARNED_TIME);
+
+    }
+    else
+    {
+      operations.add(new MultiValueOperation(
+          PasswordPolicyStateOperationType.SET_PASSWORD_EXPIRATION_WARNED_TIME,
+          ByteString.valueOf(formatAsGeneralizedTime(date))));
+    }
+  }
+
+
+
+  /**
+   * Sets the password reset state.
+   *
+   * @param state
+   *          The password reset state.
+   */
+  public void setPasswordResetState(final boolean state)
+  {
+    operations.add(new MultiValueOperation(
+        PasswordPolicyStateOperationType.SET_LAST_LOGIN_TIME, ByteString
+            .valueOf(String.valueOf(state))));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordPolicyStateExtendedRequest(requestName=");
+    builder.append(getOID());
+    builder.append(", targetUser=");
+    builder.append(targetUser);
+    builder.append(", operations=");
+    builder.append(operations);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java
new file mode 100644
index 0000000..2bb5f5f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateExtendedResult.java
@@ -0,0 +1,171 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DN;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.responses.AbstractExtendedResult;
+
+
+
+/**
+ * The password policy state extended result.
+ */
+public final class PasswordPolicyStateExtendedResult extends
+    AbstractExtendedResult<PasswordPolicyStateExtendedResult> implements
+    PasswordPolicyStateOperationContainer
+{
+  private final String targetUser;
+
+  private final List<PasswordPolicyStateOperation> operations =
+    new ArrayList<PasswordPolicyStateOperation>();
+
+
+
+  /**
+   * Creates a new password policy state extended result with the provided
+   * result code and target user.
+   *
+   * @param resultCode
+   *          The result code.
+   * @param targetUser
+   *          The user name.
+   */
+  public PasswordPolicyStateExtendedResult(final ResultCode resultCode,
+      final DN targetUser)
+  {
+    this(resultCode, String.valueOf(targetUser));
+  }
+
+
+
+  /**
+   * Creates a new password policy state extended result with the provided
+   * result code and target user.
+   *
+   * @param resultCode
+   *          The result code.
+   * @param targetUser
+   *          The user name.
+   */
+  public PasswordPolicyStateExtendedResult(final ResultCode resultCode,
+      final String targetUser)
+  {
+    super(resultCode);
+    this.targetUser = targetUser;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void addOperation(final PasswordPolicyStateOperation operation)
+  {
+    operations.add(operation);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    // No response name defined.
+    return PasswordPolicyStateExtendedRequest.OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<PasswordPolicyStateOperation> getOperations()
+  {
+    return operations;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return PasswordPolicyStateExtendedRequest.encode(targetUser, operations);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordPolicyStateExtendedResponse(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", responseName=");
+    builder.append(getOID());
+    builder.append(", targetUser=");
+    builder.append(targetUser);
+    builder.append(", operations=");
+    builder.append(operations);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperation.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperation.java
new file mode 100644
index 0000000..0330aae
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperation.java
@@ -0,0 +1,56 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * Password policy state operation.
+ */
+public interface PasswordPolicyStateOperation
+{
+  /**
+   * Returns the type of operation.
+   *
+   * @return The type of operation.
+   */
+  PasswordPolicyStateOperationType getOperationType();
+
+
+
+  /**
+   * Returns the operation values.
+   *
+   * @return The operation values.
+   */
+  Iterable<ByteString> getValues();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationContainer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationContainer.java
new file mode 100644
index 0000000..ddf8680
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationContainer.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+/**
+ * Password policy state operation container.
+ */
+interface PasswordPolicyStateOperationContainer
+{
+  /**
+   * Adds an operation to this container.
+   *
+   * @param operation
+   *          The operation to be added.
+   */
+  void addOperation(PasswordPolicyStateOperation operation);
+
+
+
+  /**
+   * Returns the operations in this container.
+   *
+   * @return The operations in this container.
+   */
+  Iterable<PasswordPolicyStateOperation> getOperations();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationType.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationType.java
new file mode 100644
index 0000000..0e3f17c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/PasswordPolicyStateOperationType.java
@@ -0,0 +1,323 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.extensions;
+
+
+
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * Password policy state operation type.
+ */
+public enum PasswordPolicyStateOperationType implements
+    PasswordPolicyStateOperation
+{
+  /**
+   * Get password policy DN operation.
+   */
+  GET_PASSWORD_POLICY_DN(
+      PasswordPolicyStateExtendedRequest.PASSWORD_POLICY_DN_NAME),
+
+  /**
+   * Get account disabled state operation.
+   */
+  GET_ACCOUNT_DISABLED_STATE(
+      PasswordPolicyStateExtendedRequest.ACCOUNT_DISABLED_STATE_NAME),
+
+  /**
+   * Set account disabled state operation.
+   */
+  SET_ACCOUNT_DISABLED_STATE(
+      PasswordPolicyStateExtendedRequest.ACCOUNT_DISABLED_STATE_NAME),
+
+  /**
+   * Clear account disabled state operation.
+   */
+  CLEAR_ACCOUNT_DISABLED_STATE(
+      PasswordPolicyStateExtendedRequest.ACCOUNT_DISABLED_STATE_NAME),
+
+  /**
+   * Get account expiration time operation.
+   */
+  GET_ACCOUNT_EXPIRATION_TIME(
+      PasswordPolicyStateExtendedRequest.ACCOUNT_EXPIRATION_TIME_NAME),
+
+  /**
+   * Set account expiration time operation.
+   */
+  SET_ACCOUNT_EXPIRATION_TIME(
+      PasswordPolicyStateExtendedRequest.ACCOUNT_EXPIRATION_TIME_NAME),
+
+  /**
+   * Clear account expiration time operation.
+   */
+  CLEAR_ACCOUNT_EXPIRATION_TIME(
+      PasswordPolicyStateExtendedRequest.ACCOUNT_EXPIRATION_TIME_NAME),
+
+  /**
+   * Get seconds until account expiration operation.
+   */
+  GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION(
+      PasswordPolicyStateExtendedRequest.SECONDS_UNTIL_ACCOUNT_EXPIRATION_NAME),
+
+  /**
+   * Get password changed time operation.
+   */
+  GET_PASSWORD_CHANGED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_CHANGED_TIME_NAME),
+
+  /**
+   * Set password changed time operation.
+   */
+  SET_PASSWORD_CHANGED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_CHANGED_TIME_NAME),
+
+  /**
+   * Clear password changed time operation.
+   */
+  CLEAR_PASSWORD_CHANGED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_CHANGED_TIME_NAME),
+
+  /**
+   * Get password expiration warned time operation.
+   */
+  GET_PASSWORD_EXPIRATION_WARNED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_EXPIRATION_WARNED_TIME_NAME),
+
+  /**
+   * Set password expiration warned time operation.
+   */
+  SET_PASSWORD_EXPIRATION_WARNED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_EXPIRATION_WARNED_TIME_NAME),
+
+  /**
+   * Clear password expiration warned time operation.
+   */
+  CLEAR_PASSWORD_EXPIRATION_WARNED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_EXPIRATION_WARNED_TIME_NAME),
+
+  /**
+   * Get seconds until password expiration operation.
+   */
+  GET_SECONDS_UNTIL_PASSWORD_EXPIRATION(
+      PasswordPolicyStateExtendedRequest.SECONDS_UNTIL_PASSWORD_EXPIRATION_NAME),
+
+  /**
+   * Get seconds until password expiration warning operation.
+   */
+  GET_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING(
+      PasswordPolicyStateExtendedRequest.SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING_NAME),
+
+  /**
+   * Get authentication failure times operation.
+   */
+  GET_AUTHENTICATION_FAILURE_TIMES(
+      PasswordPolicyStateExtendedRequest.AUTHENTICATION_FAILURE_TIMES_NAME),
+
+  /**
+   * Add authentication failure times operation.
+   */
+  ADD_AUTHENTICATION_FAILURE_TIMES(
+      PasswordPolicyStateExtendedRequest.AUTHENTICATION_FAILURE_TIMES_NAME),
+
+  /**
+   * Set authentication failure times operation.
+   */
+  SET_AUTHENTICATION_FAILURE_TIMES(
+      PasswordPolicyStateExtendedRequest.AUTHENTICATION_FAILURE_TIMES_NAME),
+
+  /**
+   * Clear authentication failure times operation.
+   */
+  CLEAR_AUTHENTICATION_FAILURE_TIMES(
+      PasswordPolicyStateExtendedRequest.AUTHENTICATION_FAILURE_TIMES_NAME),
+
+  /**
+   * Get seconds until authentication failure unlock operation.
+   */
+  GET_SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK(
+      PasswordPolicyStateExtendedRequest.SECONDS_UNTIL_AUTHENTICATION_FAILURE_UNLOCK_NAME),
+
+  /**
+   * Get remaining authentication failure count operation.
+   */
+  GET_REMAINING_AUTHENTICATION_FAILURE_COUNT(
+      PasswordPolicyStateExtendedRequest.REMAINING_AUTHENTICATION_FAILURE_COUNT_NAME),
+
+  /**
+   * Get last login time operation.
+   */
+  GET_LAST_LOGIN_TIME(PasswordPolicyStateExtendedRequest.LAST_LOGIN_TIME_NAME),
+
+  /**
+   * Set last login time operation.
+   */
+  SET_LAST_LOGIN_TIME(PasswordPolicyStateExtendedRequest.LAST_LOGIN_TIME_NAME),
+
+  /**
+   * Clear last login time operation.
+   */
+  CLEAR_LAST_LOGIN_TIME(PasswordPolicyStateExtendedRequest.LAST_LOGIN_TIME_NAME),
+
+  /**
+   * Get seconds until idle lockout operation.
+   */
+  GET_SECONDS_UNTIL_IDLE_LOCKOUT(
+      PasswordPolicyStateExtendedRequest.SECONDS_UNTIL_IDLE_LOCKOUT_NAME),
+
+  /**
+   * Get password reset state operation.
+   */
+  GET_PASSWORD_RESET_STATE(
+      PasswordPolicyStateExtendedRequest.PASSWORD_RESET_STATE_NAME),
+
+  /**
+   * Set password reset state operation.
+   */
+  SET_PASSWORD_RESET_STATE(
+      PasswordPolicyStateExtendedRequest.PASSWORD_RESET_STATE_NAME),
+
+  /**
+   * Clear password reset state operation.
+   */
+  CLEAR_PASSWORD_RESET_STATE(
+      PasswordPolicyStateExtendedRequest.PASSWORD_RESET_STATE_NAME),
+
+  /**
+   * Get seconds until password reset lockout operation.
+   */
+  GET_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT(
+      PasswordPolicyStateExtendedRequest.SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT_NAME),
+
+  /**
+   * Get grace login use times operation.
+   */
+  GET_GRACE_LOGIN_USE_TIMES(
+      PasswordPolicyStateExtendedRequest.GRACE_LOGIN_USE_TIMES_NAME),
+
+  /**
+   * Add grace login use times operation.
+   */
+  ADD_GRACE_LOGIN_USE_TIME(
+      PasswordPolicyStateExtendedRequest.GRACE_LOGIN_USE_TIMES_NAME),
+
+  /**
+   * Set grace login use times operation.
+   */
+  SET_GRACE_LOGIN_USE_TIMES(
+      PasswordPolicyStateExtendedRequest.GRACE_LOGIN_USE_TIMES_NAME),
+
+  /**
+   * Clear grace login use times operation.
+   */
+  CLEAR_GRACE_LOGIN_USE_TIMES(
+      PasswordPolicyStateExtendedRequest.GRACE_LOGIN_USE_TIMES_NAME),
+
+  /**
+   * Get remaining grace login count operation.
+   */
+  GET_REMAINING_GRACE_LOGIN_COUNT(
+      PasswordPolicyStateExtendedRequest.REMAINING_GRACE_LOGIN_COUNT_NAME),
+
+  /**
+   * Get password changed by required time operation.
+   */
+  GET_PASSWORD_CHANGED_BY_REQUIRED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_CHANGED_BY_REQUIRED_TIME_NAME),
+
+  /**
+   * Set password changed by required time operation.
+   */
+  SET_PASSWORD_CHANGED_BY_REQUIRED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_CHANGED_BY_REQUIRED_TIME_NAME),
+
+  /**
+   * Clear password changed by required time operation.
+   */
+  CLEAR_PASSWORD_CHANGED_BY_REQUIRED_TIME(
+      PasswordPolicyStateExtendedRequest.PASSWORD_CHANGED_BY_REQUIRED_TIME_NAME),
+
+  /**
+   * Get seconds until required change time operation.
+   */
+  GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME(
+      PasswordPolicyStateExtendedRequest.SECONDS_UNTIL_REQUIRED_CHANGE_TIME_NAME),
+
+  /**
+   * Get password history operation.
+   */
+  GET_PASSWORD_HISTORY(PasswordPolicyStateExtendedRequest.PASSWORD_HISTORY_NAME),
+
+  /**
+   * Clear password history operation.
+   */
+  CLEAR_PASSWORD_HISTORY(
+      PasswordPolicyStateExtendedRequest.PASSWORD_HISTORY_NAME);
+
+  private String propertyName;
+
+
+
+  private PasswordPolicyStateOperationType(final String propertyName)
+  {
+    this.propertyName = propertyName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordPolicyStateOperationType getOperationType()
+  {
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<ByteString> getValues()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return propertyName;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/package-info.java
new file mode 100644
index 0000000..750dd41
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/extensions/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes implementing Sun proprietary LDAP extended operations.
+ */
+package com.sun.opends.sdk.extensions;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferReader.java
new file mode 100644
index 0000000..caf2f3f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferReader.java
@@ -0,0 +1,821 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_TYPE;
+import static com.sun.opends.sdk.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.io.IOException;
+import java.util.logging.Level;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.AbstractASN1Reader;
+
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.memory.BuffersBuffer;
+import org.glassfish.grizzly.memory.CompositeBuffer;
+import org.glassfish.grizzly.memory.MemoryManager;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Grizzly ASN1 reader implementation.
+ */
+final class ASN1BufferReader extends AbstractASN1Reader implements ASN1Reader
+{
+  private final class ChildSequenceLimiter implements SequenceLimiter
+  {
+    private SequenceLimiter parent;
+
+    private ChildSequenceLimiter child;
+
+    private int readLimit;
+
+    private int bytesRead;
+
+
+
+    public void checkLimit(final int readSize) throws IOException
+    {
+      if ((readLimit > 0) && (bytesRead + readSize > readLimit))
+      {
+        final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
+        throw DecodeException.fatalError(message);
+      }
+
+      parent.checkLimit(readSize);
+
+      bytesRead += readSize;
+    }
+
+
+
+    public SequenceLimiter endSequence() throws IOException
+    {
+      parent.checkLimit(remaining());
+
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE) && remaining() > 0)
+      {
+        StaticUtils.DEBUG_LOG
+            .fine(String.format(
+                "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE",
+                remaining()));
+      }
+
+      for (int i = 0; i < remaining(); i++)
+      {
+        buffer.get();
+      }
+
+      return parent;
+    }
+
+
+
+    public int remaining()
+    {
+      return readLimit - bytesRead;
+    }
+
+
+
+    public ChildSequenceLimiter startSequence(final int readLimit)
+    {
+      if (child == null)
+      {
+        child = new ChildSequenceLimiter();
+        child.parent = this;
+      }
+
+      child.readLimit = readLimit;
+      child.bytesRead = 0;
+
+      return child;
+    }
+  }
+
+
+
+  private final class RootSequenceLimiter implements SequenceLimiter
+  {
+    private ChildSequenceLimiter child;
+
+
+
+    public void checkLimit(final int readSize) throws IOException
+    {
+      if (buffer.remaining() < readSize)
+      {
+        final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
+        throw DecodeException.fatalError(message);
+      }
+    }
+
+
+
+    public ChildSequenceLimiter endSequence() throws DecodeException
+    {
+      final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED
+          .get();
+      throw new IllegalStateException(message.toString());
+    }
+
+
+
+    public int remaining()
+    {
+      return buffer.remaining();
+    }
+
+
+
+    public ChildSequenceLimiter startSequence(final int readLimit)
+    {
+      if (child == null)
+      {
+        child = new ChildSequenceLimiter();
+        child.parent = this;
+      }
+
+      child.readLimit = readLimit;
+      child.bytesRead = 0;
+
+      return child;
+    }
+  }
+
+
+
+  private interface SequenceLimiter
+  {
+    public void checkLimit(int readSize) throws IOException;
+
+
+
+    public SequenceLimiter endSequence() throws IOException;
+
+
+
+    public int remaining();
+
+
+
+    public SequenceLimiter startSequence(int readLimit);
+  }
+
+
+
+  private static final int MAX_STRING_BUFFER_SIZE = 1024;
+
+  private int state = ELEMENT_READ_STATE_NEED_TYPE;
+
+  private byte peekType = 0;
+
+  private int peekLength = -1;
+
+  private int lengthBytesNeeded = 0;
+
+  private final int maxElementSize;
+
+  private final CompositeBuffer buffer;
+
+  private SequenceLimiter readLimiter;
+
+  private final byte[] stringBuffer;
+
+
+
+  /**
+   * Creates a new ASN1 reader whose source is the provided input stream and
+   * having a user defined maximum BER element size.
+   *
+   * @param maxElementSize
+   *          The maximum BER element size, or <code>0</code> to indicate that
+   *          there is no limit.
+   * @param memoryManager
+   *          The memory manager to use for buffering.
+   */
+  ASN1BufferReader(final int maxElementSize,
+      final MemoryManager<?> memoryManager)
+  {
+    this.readLimiter = new RootSequenceLimiter();
+    this.stringBuffer = new byte[MAX_STRING_BUFFER_SIZE];
+    this.maxElementSize = maxElementSize;
+    this.buffer = BuffersBuffer.create(memoryManager);
+  }
+
+
+
+  /**
+   * Closes this ASN.1 reader and the underlying stream.
+   *
+   * @throws IOException
+   *           if an I/O error occurs
+   */
+  public void close() throws IOException
+  {
+    buffer.dispose();
+  }
+
+
+
+  /**
+   * Determines if a complete ASN.1 element is ready to be read from the stream
+   * reader.
+   *
+   * @return <code>true</code> if another complete element is available or
+   *         <code>false</code> otherwise.
+   * @throws IOException
+   *           If an error occurs while trying to decode an ASN1 element.
+   */
+  public boolean elementAvailable() throws IOException
+  {
+    return !((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(true))
+        && !((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
+            && !needFirstLengthByteState(true))
+        && !((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES)
+            && !needAdditionalLengthBytesState(true))
+        && peekLength <= readLimiter.remaining();
+
+  }
+
+
+
+  /**
+   * Determines if the input stream contains at least one ASN.1 element to be
+   * read.
+   *
+   * @return <code>true</code> if another element is available or
+   *         <code>false</code> otherwise.
+   * @throws IOException
+   *           If an error occurs while trying to decode an ASN1 element.
+   */
+  public boolean hasNextElement() throws IOException
+  {
+    return (state != ELEMENT_READ_STATE_NEED_TYPE) || needTypeState(true);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int peekLength() throws IOException
+  {
+    peekType();
+
+    switch (state)
+    {
+    case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE:
+      needFirstLengthByteState(false);
+      break;
+
+    case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES:
+      needAdditionalLengthBytesState(false);
+    }
+
+    return peekLength;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte peekType() throws IOException
+  {
+    if (state == ELEMENT_READ_STATE_NEED_TYPE)
+    {
+      needTypeState(false);
+    }
+
+    return peekType;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean readBoolean() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength != 1)
+    {
+      final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    readLimiter.checkLimit(peekLength);
+    final byte readByte = buffer.get();
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", peekType,
+          peekLength, String.valueOf(readByte != 0x00)));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return readByte != 0x00;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSequence() throws IOException, IllegalStateException
+  {
+    readLimiter = readLimiter.endSequence();
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 END SEQUENCE"));
+    }
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSet() throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    readEndSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int readEnumerated() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 4))
+    {
+      final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    // From an implementation point of view, an enumerated value is
+    // equivalent to an integer.
+    return (int) readInteger();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public long readInteger() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 8))
+    {
+      final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    readLimiter.checkLimit(peekLength);
+    if (peekLength > 4)
+    {
+      long longValue = 0;
+      for (int i = 0; i < peekLength; i++)
+      {
+        final int readByte = buffer.get();
+        if ((i == 0) && (((byte) readByte) < 0))
+        {
+          longValue = 0xFFFFFFFFFFFFFFFFL;
+        }
+        longValue = (longValue << 8) | (readByte & 0xFF);
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return longValue;
+    }
+    else
+    {
+      int intValue = 0;
+      for (int i = 0; i < peekLength; i++)
+      {
+        final int readByte = buffer.get();
+        if ((i == 0) && (((byte) readByte) < 0))
+        {
+          intValue = 0xFFFFFFFF;
+        }
+        intValue = (intValue << 8) | (readByte & 0xFF);
+      }
+
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "READ ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", peekType,
+            peekLength, intValue));
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return intValue;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readNull() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    // Make sure that the decoded length is exactly zero byte.
+    if (peekLength != 0)
+    {
+      final LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 NULL(type=0x%x, length=%d)", peekType, peekLength));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString readOctetString() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return ByteString.empty();
+    }
+
+    readLimiter.checkLimit(peekLength);
+    // Copy the value and construct the element to return.
+    final byte[] value = new byte[peekLength];
+    buffer.get(value);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG
+          .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+              peekType, peekLength));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return ByteString.wrap(value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteStringBuilder readOctetString(final ByteStringBuilder builder)
+      throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return builder;
+    }
+
+    readLimiter.checkLimit(peekLength);
+    // Copy the value and construct the element to return.
+    // TODO: Is there a more efficient way to do this?
+    for (int i = 0; i < peekLength; i++)
+    {
+      builder.append(buffer.get());
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG
+          .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+              peekType, peekLength));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return "";
+    }
+
+    byte[] readBuffer;
+    if (peekLength <= stringBuffer.length)
+    {
+      readBuffer = stringBuffer;
+    }
+    else
+    {
+      readBuffer = new byte[peekLength];
+    }
+
+    readLimiter.checkLimit(peekLength);
+    buffer.get(readBuffer, 0, peekLength);
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+
+    String str;
+    try
+    {
+      str = new String(readBuffer, 0, peekLength, "UTF-8");
+    }
+    catch (final Exception e)
+    {
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
+      {
+        StaticUtils.DEBUG_LOG
+            .warning("Unable to decode ASN.1 OCTETSTRING bytes as UTF-8 string: "
+                + e.toString());
+      }
+
+      str = new String(stringBuffer, 0, peekLength);
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 OCTETSTRING(type=0x%x, length=%d, value=%s)", peekType,
+          peekLength, str));
+    }
+
+    return str;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSequence() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    readLimiter = readLimiter.startSequence(peekLength);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 START SEQUENCE(type=0x%x, length=%d)", peekType,
+          peekLength));
+    }
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSet() throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    readStartSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Reader skipElement() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    readLimiter.checkLimit(peekLength);
+    for (int i = 0; i < peekLength; i++)
+    {
+      buffer.get();
+    }
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return this;
+  }
+
+
+
+  void appendBytesRead(final Buffer buffer)
+  {
+    this.buffer.append(buffer);
+  }
+
+
+
+  void disposeBytesRead()
+  {
+    this.buffer.shrink();
+  }
+
+
+
+  /**
+   * Internal helper method reading the additional ASN.1 length bytes and
+   * transition to the next state if successful.
+   *
+   * @param ensureRead
+   *          <code>true</code> to check for availability first.
+   * @return <code>true</code> if the length bytes was successfully read.
+   * @throws IOException
+   *           If an error occurs while reading from the stream.
+   */
+  private boolean needAdditionalLengthBytesState(final boolean ensureRead)
+      throws IOException
+  {
+    if (ensureRead && (readLimiter.remaining() < lengthBytesNeeded))
+    {
+      return false;
+    }
+
+    byte readByte;
+    readLimiter.checkLimit(lengthBytesNeeded);
+    while (lengthBytesNeeded > 0)
+    {
+      readByte = buffer.get();
+      peekLength = (peekLength << 8) | (readByte & 0xFF);
+      lengthBytesNeeded--;
+    }
+
+    // Make sure that the element is not larger than the maximum allowed
+    // message size.
+    if ((maxElementSize > 0) && (peekLength > maxElementSize))
+    {
+      final LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
+          .get(peekLength, maxElementSize);
+      throw DecodeException.fatalError(m);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+
+
+  /**
+   * Internal helper method reading the first length bytes and transition to the
+   * next state if successful.
+   *
+   * @param ensureRead
+   *          <code>true</code> to check for availability first.
+   * @return <code>true</code> if the length bytes was successfully read
+   * @throws IOException
+   *           If an error occurs while trying to decode an ASN1 element.
+   */
+  private boolean needFirstLengthByteState(final boolean ensureRead)
+      throws IOException
+  {
+    if (ensureRead && (readLimiter.remaining() <= 0))
+    {
+      return false;
+    }
+
+    readLimiter.checkLimit(1);
+    byte readByte = buffer.get();
+    peekLength = (readByte & 0x7F);
+    if (peekLength != readByte)
+    {
+      lengthBytesNeeded = peekLength;
+      if (lengthBytesNeeded > 4)
+      {
+        final LocalizableMessage message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES
+            .get(lengthBytesNeeded);
+        throw DecodeException.fatalError(message);
+      }
+      peekLength = 0x00;
+
+      if (ensureRead && (readLimiter.remaining() < lengthBytesNeeded))
+      {
+        state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+        return false;
+      }
+
+      readLimiter.checkLimit(lengthBytesNeeded);
+      while (lengthBytesNeeded > 0)
+      {
+        readByte = buffer.get();
+        peekLength = (peekLength << 8) | (readByte & 0xFF);
+        lengthBytesNeeded--;
+      }
+    }
+
+    // Make sure that the element is not larger than the maximum allowed
+    // message size.
+    if ((maxElementSize > 0) && (peekLength > maxElementSize))
+    {
+      final LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
+          .get(peekLength, maxElementSize);
+      throw DecodeException.fatalError(m);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+
+
+  /**
+   * Internal helper method reading the ASN.1 type byte and transition to the
+   * next state if successful.
+   *
+   * @param ensureRead
+   *          <code>true</code> to check for availability first.
+   * @return <code>true</code> if the type byte was successfully read
+   * @throws IOException
+   *           If an error occurs while trying to decode an ASN1 element.
+   */
+  private boolean needTypeState(final boolean ensureRead) throws IOException
+  {
+    // Read just the type.
+    if (ensureRead && (readLimiter.remaining() <= 0))
+    {
+      return false;
+    }
+
+    readLimiter.checkLimit(1);
+    peekType = buffer.get();
+    state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferWriter.java
new file mode 100644
index 0000000..a5b7ab8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/ASN1BufferWriter.java
@@ -0,0 +1,741 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.ldap;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED;
+import static org.opends.sdk.asn1.ASN1Constants.BOOLEAN_VALUE_FALSE;
+import static org.opends.sdk.asn1.ASN1Constants.BOOLEAN_VALUE_TRUE;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.logging.Level;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.asn1.AbstractASN1Writer;
+
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.Cacheable;
+import org.glassfish.grizzly.ThreadCache;
+import org.glassfish.grizzly.memory.ByteBufferWrapper;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Grizzly ASN1 writer implementation.
+ */
+final class ASN1BufferWriter extends AbstractASN1Writer implements ASN1Writer,
+    Cacheable
+{
+  private class ChildSequenceBuffer implements SequenceBuffer
+  {
+    private SequenceBuffer parent;
+
+    private ChildSequenceBuffer child;
+
+    private final ByteStringBuilder buffer = new ByteStringBuilder(
+        BUFFER_INIT_SIZE);
+
+
+
+    public SequenceBuffer endSequence() throws IOException
+    {
+      writeLength(parent, buffer.length());
+      parent.writeByteArray(buffer.getBackingArray(), 0, buffer.length());
+
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 END SEQUENCE(length=%d)", buffer.length()));
+      }
+
+      return parent;
+    }
+
+
+
+    public SequenceBuffer startSequence(final byte type) throws IOException
+    {
+      if (child == null)
+      {
+        child = new ChildSequenceBuffer();
+        child.parent = this;
+      }
+
+      buffer.append(type);
+      child.buffer.clear();
+
+      return child;
+    }
+
+
+
+    public void writeByte(final byte b) throws IOException
+    {
+      buffer.append(b);
+    }
+
+
+
+    public void writeByteArray(final byte[] bs, final int offset,
+        final int length) throws IOException
+    {
+      buffer.append(bs, offset, length);
+    }
+  }
+
+
+
+  private static final class RecyclableBuffer extends ByteBufferWrapper
+  {
+    private volatile boolean usable = true;
+
+
+
+    private RecyclableBuffer()
+    {
+      visible = ByteBuffer.allocate(BUFFER_INIT_SIZE);
+      allowBufferDispose = true;
+    }
+
+
+
+    @Override
+    public void dispose()
+    {
+      usable = true;
+    }
+
+
+
+    /**
+     * Ensures that the specified number of additional bytes will fit in the
+     * buffer and resizes it if necessary.
+     *
+     * @param size
+     *          The number of additional bytes.
+     */
+    public void ensureAdditionalCapacity(final int size)
+    {
+      final int newCount = visible.position() + size;
+      if (newCount > visible.capacity())
+      {
+        final ByteBuffer newByteBuffer = ByteBuffer.allocate(Math.max(visible
+            .capacity() << 1, newCount));
+        visible.flip();
+        visible = newByteBuffer.put(visible);
+      }
+    }
+  }
+
+
+
+  private class RootSequenceBuffer implements SequenceBuffer
+  {
+    private ChildSequenceBuffer child;
+
+
+
+    public SequenceBuffer endSequence() throws IOException
+    {
+      final LocalizableMessage message = ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED
+          .get();
+      throw new IllegalStateException(message.toString());
+    }
+
+
+
+    public SequenceBuffer startSequence(final byte type) throws IOException
+    {
+      if (child == null)
+      {
+        child = new ChildSequenceBuffer();
+        child.parent = this;
+      }
+
+      outBuffer.ensureAdditionalCapacity(1);
+      outBuffer.put(type);
+      child.buffer.clear();
+
+      return child;
+    }
+
+
+
+    public void writeByte(final byte b) throws IOException
+    {
+      outBuffer.ensureAdditionalCapacity(1);
+      outBuffer.put(b);
+    }
+
+
+
+    public void writeByteArray(final byte[] bs, final int offset,
+        final int length) throws IOException
+    {
+      outBuffer.ensureAdditionalCapacity(length);
+      outBuffer.put(bs, offset, length);
+    }
+  }
+
+
+
+  private interface SequenceBuffer
+  {
+    public SequenceBuffer endSequence() throws IOException;
+
+
+
+    public SequenceBuffer startSequence(byte type) throws IOException;
+
+
+
+    public void writeByte(byte b) throws IOException;
+
+
+
+    public void writeByteArray(byte[] bs, int offset, int length)
+        throws IOException;
+  }
+
+
+
+  private static final int BUFFER_INIT_SIZE = 1024;
+  private final static ThreadCache.CachedTypeIndex<ASN1BufferWriter> WRITER_INDEX = ThreadCache
+      .obtainIndex(ASN1BufferWriter.class, 1);
+
+
+
+  static ASN1BufferWriter getWriter()
+  {
+    ASN1BufferWriter asn1Writer = ThreadCache.takeFromCache(WRITER_INDEX);
+    if (asn1Writer == null)
+    {
+      asn1Writer = new ASN1BufferWriter();
+    }
+
+    if (!asn1Writer.outBuffer.usable)
+    {
+      // If the output buffer is unusable, create a new one.
+      asn1Writer.outBuffer = new RecyclableBuffer();
+    }
+    asn1Writer.outBuffer.clear();
+    return asn1Writer;
+  }
+
+
+
+  private SequenceBuffer sequenceBuffer;
+  private RecyclableBuffer outBuffer;
+
+  private final RootSequenceBuffer rootBuffer;
+
+
+
+  /**
+   * Creates a new ASN.1 writer that writes to a StreamWriter.
+   */
+  private ASN1BufferWriter()
+  {
+    this.sequenceBuffer = this.rootBuffer = new RootSequenceBuffer();
+    this.outBuffer = new RecyclableBuffer();
+  }
+
+
+
+  /**
+   * Closes this ASN.1 writer and the underlying outputstream. Any unfinished
+   * sequences will be ended.
+   *
+   * @throws IOException
+   *           if an error occurs while closing the stream.
+   */
+  public void close() throws IOException
+  {
+    outBuffer = null;
+  }
+
+
+
+  /**
+   * Flushes the stream.
+   *
+   * @throws IOException
+   *           If an I/O error occurs
+   */
+  public void flush() throws IOException
+  {
+    // Do nothing
+  }
+
+
+
+  public void recycle()
+  {
+    sequenceBuffer = rootBuffer;
+    outBuffer.clear();
+    ThreadCache.putToCache(WRITER_INDEX, this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeBoolean(final byte type, final boolean booleanValue)
+      throws IOException
+  {
+    sequenceBuffer.writeByte(type);
+    writeLength(sequenceBuffer, 1);
+    sequenceBuffer.writeByte(booleanValue ? BOOLEAN_VALUE_TRUE
+        : BOOLEAN_VALUE_FALSE);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", type, 1,
+          String.valueOf(booleanValue)));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSequence() throws IOException,
+      IllegalStateException
+  {
+    sequenceBuffer = sequenceBuffer.endSequence();
+
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSet() throws IOException
+  {
+    return writeEndSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEnumerated(final byte type, final int intValue)
+      throws IOException
+  {
+    return writeInteger(type, intValue);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(final byte type, final int intValue)
+      throws IOException
+  {
+    sequenceBuffer.writeByte(type);
+    if (((intValue < 0) && ((intValue & 0xFFFFFF80) == 0xFFFFFF80))
+        || ((intValue & 0x0000007F) == intValue))
+    {
+      writeLength(sequenceBuffer, 1);
+      sequenceBuffer.writeByte((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1,
+            intValue));
+      }
+    }
+    else if (((intValue < 0) && ((intValue & 0xFFFF8000) == 0xFFFF8000))
+        || ((intValue & 0x00007FFF) == intValue))
+    {
+      writeLength(sequenceBuffer, 2);
+      sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2,
+            intValue));
+      }
+    }
+    else if (((intValue < 0) && ((intValue & 0xFF800000) == 0xFF800000))
+        || ((intValue & 0x007FFFFF) == intValue))
+    {
+      writeLength(sequenceBuffer, 3);
+      sequenceBuffer.writeByte((byte) ((intValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3,
+            intValue));
+      }
+    }
+    else
+    {
+      writeLength(sequenceBuffer, 4);
+      sequenceBuffer.writeByte((byte) ((intValue >> 24) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((intValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4,
+            intValue));
+      }
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(final byte type, final long longValue)
+      throws IOException
+  {
+    sequenceBuffer.writeByte(type);
+    if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L))
+        || ((longValue & 0x000000000000007FL) == longValue))
+    {
+      writeLength(sequenceBuffer, 1);
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L))
+        || ((longValue & 0x0000000000007FFFL) == longValue))
+    {
+      writeLength(sequenceBuffer, 2);
+      sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L))
+        || ((longValue & 0x00000000007FFFFFL) == longValue))
+    {
+      writeLength(sequenceBuffer, 3);
+      sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L))
+        || ((longValue & 0x000000007FFFFFFFL) == longValue))
+    {
+      writeLength(sequenceBuffer, 4);
+      sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L))
+        || ((longValue & 0x0000007FFFFFFFFFL) == longValue))
+    {
+      writeLength(sequenceBuffer, 5);
+      sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 5,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L))
+        || ((longValue & 0x00007FFFFFFFFFFFL) == longValue))
+    {
+      writeLength(sequenceBuffer, 6);
+      sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 6,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L))
+        || ((longValue & 0x007FFFFFFFFFFFFFL) == longValue))
+    {
+      writeLength(sequenceBuffer, 7);
+      sequenceBuffer.writeByte((byte) ((longValue >> 48) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 7,
+            longValue));
+      }
+    }
+    else
+    {
+      writeLength(sequenceBuffer, 8);
+      sequenceBuffer.writeByte((byte) ((longValue >> 56) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 48) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF));
+      sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF));
+      sequenceBuffer.writeByte((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 8,
+            longValue));
+      }
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeNull(final byte type) throws IOException
+  {
+    sequenceBuffer.writeByte(type);
+    writeLength(sequenceBuffer, 0);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 NULL(type=0x%x, length=%d)", type, 0));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final byte type, final byte[] value,
+      final int offset, final int length) throws IOException
+  {
+    sequenceBuffer.writeByte(type);
+    writeLength(sequenceBuffer, length);
+    sequenceBuffer.writeByteArray(value, offset, length);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, length));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final byte type, final ByteSequence value)
+      throws IOException
+  {
+    sequenceBuffer.writeByte(type);
+    writeLength(sequenceBuffer, value.length());
+    // TODO: Is there a more efficient way to do this?
+    for (int i = 0; i < value.length(); i++)
+    {
+      sequenceBuffer.writeByte(value.byteAt(i));
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String
+          .format("WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, value
+              .length()));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final byte type, final String value)
+      throws IOException
+  {
+    sequenceBuffer.writeByte(type);
+
+    if (value == null)
+    {
+      writeLength(sequenceBuffer, 0);
+      return this;
+    }
+
+    final byte[] bytes = StaticUtils.getBytes(value);
+    writeLength(sequenceBuffer, bytes.length);
+    sequenceBuffer.writeByteArray(bytes, 0, bytes.length);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d, " + "value=%s)", type,
+          bytes.length, value));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSequence(final byte type) throws IOException
+  {
+    // Get a child sequence buffer
+    sequenceBuffer = sequenceBuffer.startSequence(type);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 START SEQUENCE(type=0x%x)", type));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSet(final byte type) throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    return writeStartSequence(type);
+  }
+
+
+
+  Buffer getBuffer()
+  {
+    outBuffer.usable = false;
+    return outBuffer.flip();
+  }
+
+
+
+  /**
+   * Writes the provided value for use as the length of an ASN.1 element.
+   *
+   * @param buffer
+   *          The sequence buffer to write to.
+   * @param length
+   *          The length to encode for use in an ASN.1 element.
+   * @throws IOException
+   *           if an error occurs while writing.
+   */
+  private void writeLength(final SequenceBuffer buffer, final int length)
+      throws IOException
+  {
+    if (length < 128)
+    {
+      buffer.writeByte((byte) length);
+    }
+    else if ((length & 0x000000FF) == length)
+    {
+      buffer.writeByte((byte) 0x81);
+      buffer.writeByte((byte) (length & 0xFF));
+    }
+    else if ((length & 0x0000FFFF) == length)
+    {
+      buffer.writeByte((byte) 0x82);
+      buffer.writeByte((byte) ((length >> 8) & 0xFF));
+      buffer.writeByte((byte) (length & 0xFF));
+    }
+    else if ((length & 0x00FFFFFF) == length)
+    {
+      buffer.writeByte((byte) 0x83);
+      buffer.writeByte((byte) ((length >> 16) & 0xFF));
+      buffer.writeByte((byte) ((length >> 8) & 0xFF));
+      buffer.writeByte((byte) (length & 0xFF));
+    }
+    else
+    {
+      buffer.writeByte((byte) 0x84);
+      buffer.writeByte((byte) ((length >> 24) & 0xFF));
+      buffer.writeByte((byte) ((length >> 16) & 0xFF));
+      buffer.writeByte((byte) ((length >> 8) & 0xFF));
+      buffer.writeByte((byte) (length & 0xFF));
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPFutureResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPFutureResultImpl.java
new file mode 100644
index 0000000..4881524
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPFutureResultImpl.java
@@ -0,0 +1,174 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.responses.IntermediateResponse;
+import org.opends.sdk.responses.Result;
+
+import com.sun.opends.sdk.util.AsynchronousFutureResult;
+
+
+
+/**
+ * Abstract future result implementation.
+ *
+ * @param <S>
+ *          The type of result returned by this future.
+ */
+abstract class AbstractLDAPFutureResultImpl<S extends Result> extends
+    AsynchronousFutureResult<S> implements IntermediateResponseHandler
+{
+  private final AsynchronousConnection connection;
+
+  private final int requestID;
+
+  private IntermediateResponseHandler intermediateResponseHandler;
+
+  private volatile long timestamp;
+
+
+
+  AbstractLDAPFutureResultImpl(final int requestID,
+      final ResultHandler<? super S> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler,
+      final AsynchronousConnection connection)
+  {
+    super(resultHandler);
+    this.requestID = requestID;
+    this.connection = connection;
+    this.intermediateResponseHandler = intermediateResponseHandler;
+    this.timestamp = System.currentTimeMillis();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final int getRequestID()
+  {
+    return requestID;
+  }
+
+
+
+  @Override
+  public final boolean handleIntermediateResponse(
+      final IntermediateResponse response)
+  {
+    // FIXME: there's a potential race condition here - the future could
+    // get cancelled between the isDone() call and the handler
+    // invocation. We'd need to add support for intermediate handlers in
+    // the synchronizer.
+    if (!isDone())
+    {
+      updateTimestamp();
+      if (intermediateResponseHandler != null)
+      {
+        if (!intermediateResponseHandler.handleIntermediateResponse(response))
+        {
+          intermediateResponseHandler = null;
+        }
+      }
+    }
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected final ErrorResultException handleCancelRequest(
+      final boolean mayInterruptIfRunning)
+  {
+    connection.abandon(Requests.newAbandonRequest(requestID));
+    return null;
+  }
+
+
+
+  @Override
+  protected void toString(final StringBuilder sb)
+  {
+    sb.append(" requestID = ");
+    sb.append(requestID);
+    sb.append(" timestamp = ");
+    sb.append(timestamp);
+    super.toString(sb);
+  }
+
+
+
+  final void adaptErrorResult(final Result result)
+  {
+    final S errorResult = newErrorResult(result.getResultCode(),
+        result.getDiagnosticMessage(), result.getCause());
+    setResultOrError(errorResult);
+  }
+
+
+
+  final long getTimestamp()
+  {
+    return timestamp;
+  }
+
+
+
+  abstract S newErrorResult(ResultCode resultCode, String diagnosticMessage,
+      Throwable cause);
+
+
+
+  final void setResultOrError(final S result)
+  {
+    if (result.getResultCode().isExceptional())
+    {
+      handleErrorResult(ErrorResultException.wrap(result));
+    }
+    else
+    {
+      handleResult(result);
+    }
+  }
+
+
+
+  final void updateTimestamp()
+  {
+    timestamp = System.currentTimeMillis();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPMessageHandler.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPMessageHandler.java
new file mode 100644
index 0000000..7112404
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/AbstractLDAPMessageHandler.java
@@ -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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+
+
+/**
+ * Abstract LDAP message handler.
+ *
+ * @param <P>
+ *          A user provided handler parameter.
+ */
+abstract class AbstractLDAPMessageHandler<P> implements LDAPMessageHandler<P>
+{
+  public void abandonRequest(final P param, final int messageID,
+      final AbandonRequest request) throws UnexpectedRequestException,
+      IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void addRequest(final P param, final int messageID,
+      final AddRequest request) throws UnexpectedRequestException, IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void addResult(final P param, final int messageID, final Result result)
+      throws UnexpectedResponseException, IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public void bindRequest(final P param, final int messageID,
+      final int version, final GenericBindRequest request)
+      throws UnexpectedRequestException, IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void bindResult(final P param, final int messageID,
+      final BindResult result) throws UnexpectedResponseException, IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public void compareRequest(final P param, final int messageID,
+      final CompareRequest request) throws UnexpectedRequestException,
+      IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void compareResult(final P param, final int messageID,
+      final CompareResult result) throws UnexpectedResponseException,
+      IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public void deleteRequest(final P param, final int messageID,
+      final DeleteRequest request) throws UnexpectedRequestException,
+      IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void deleteResult(final P param, final int messageID,
+      final Result result) throws UnexpectedResponseException, IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public <R extends ExtendedResult> void extendedRequest(final P param,
+      final int messageID, final ExtendedRequest<R> request)
+      throws UnexpectedRequestException, IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void extendedResult(final P param, final int messageID,
+      final ExtendedResult result) throws UnexpectedResponseException,
+      IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public void intermediateResponse(final P param, final int messageID,
+      final IntermediateResponse response) throws UnexpectedResponseException,
+      IOException
+  {
+    throw new UnexpectedResponseException(messageID, response);
+  }
+
+
+
+  public void modifyDNRequest(final P param, final int messageID,
+      final ModifyDNRequest request) throws UnexpectedRequestException,
+      IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void modifyDNResult(final P param, final int messageID,
+      final Result result) throws UnexpectedResponseException, IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public void modifyRequest(final P param, final int messageID,
+      final ModifyRequest request) throws UnexpectedRequestException,
+      IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void modifyResult(final P param, final int messageID,
+      final Result result) throws UnexpectedResponseException, IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public void searchRequest(final P param, final int messageID,
+      final SearchRequest request) throws UnexpectedRequestException,
+      IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void searchResult(final P param, final int messageID,
+      final Result result) throws UnexpectedResponseException, IOException
+  {
+    throw new UnexpectedResponseException(messageID, result);
+  }
+
+
+
+  public void searchResultEntry(final P param, final int messageID,
+      final SearchResultEntry entry) throws UnexpectedResponseException,
+      IOException
+  {
+    throw new UnexpectedResponseException(messageID, entry);
+  }
+
+
+
+  public void searchResultReference(final P param, final int messageID,
+      final SearchResultReference reference)
+      throws UnexpectedResponseException, IOException
+  {
+    throw new UnexpectedResponseException(messageID, reference);
+  }
+
+
+
+  public void unbindRequest(final P param, final int messageID,
+      final UnbindRequest request) throws UnexpectedRequestException,
+      IOException
+  {
+    throw new UnexpectedRequestException(messageID, request);
+  }
+
+
+
+  public void unrecognizedMessage(final P param, final int messageID,
+      final byte messageTag, final ByteString messageBytes)
+      throws UnsupportedMessageException, IOException
+  {
+    throw new UnsupportedMessageException(messageID, messageTag, messageBytes);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/InternalConnection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/InternalConnection.java
new file mode 100644
index 0000000..99200ef
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/InternalConnection.java
@@ -0,0 +1,361 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+import com.sun.opends.sdk.util.CompletedFutureResult;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a pseudo-connection object that can be used for performing
+ * internal operations directly against a {@code ServerConnection}
+ * implementation.
+ */
+public final class InternalConnection extends AbstractAsynchronousConnection
+{
+  private static final class InternalBindFutureResultImpl extends
+      AbstractLDAPFutureResultImpl<BindResult>
+  {
+    private final BindRequest bindRequest;
+
+
+
+    InternalBindFutureResultImpl(final int messageID,
+        final BindRequest bindRequest,
+        final ResultHandler<? super BindResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler,
+        final AsynchronousConnection connection)
+    {
+      super(messageID, resultHandler, intermediateResponseHandler, connection);
+      this.bindRequest = bindRequest;
+    }
+
+
+
+    @Override
+    public String toString()
+    {
+      final StringBuilder sb = new StringBuilder();
+      sb.append("InternalBindFutureResultImpl(");
+      sb.append("bindRequest = ");
+      sb.append(bindRequest);
+      super.toString(sb);
+      sb.append(")");
+      return sb.toString();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    BindResult newErrorResult(final ResultCode resultCode,
+        final String diagnosticMessage, final Throwable cause)
+    {
+      return Responses.newBindResult(resultCode)
+          .setDiagnosticMessage(diagnosticMessage).setCause(cause);
+    }
+  }
+
+
+
+  private final ServerConnection<Integer> serverConnection;
+  private final List<ConnectionEventListener> listeners =
+    new CopyOnWriteArrayList<ConnectionEventListener>();
+  private final AtomicInteger messageID = new AtomicInteger();
+
+
+
+  /**
+   * Sets the server connection associated with this internal connection.
+   *
+   * @param serverConnection
+   *          The server connection.
+   */
+  public InternalConnection(final ServerConnection<Integer> serverConnection)
+  {
+    this.serverConnection = serverConnection;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<Void> abandon(final AbandonRequest request)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    serverConnection.handleAbandon(i, request);
+    return new CompletedFutureResult<Void>((Void) null, i);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<Result> add(final AddRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
+        resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleAdd(i, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void addConnectionEventListener(final ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException
+  {
+    Validator.ensureNotNull(listener);
+    listeners.add(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<BindResult> bind(final BindRequest request,
+      final ResultHandler<? super BindResult> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final InternalBindFutureResultImpl future = new InternalBindFutureResultImpl(
+        i, request, resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleBind(i, 3, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close(final UnbindRequest request, final String reason)
+  {
+    final int i = messageID.getAndIncrement();
+    serverConnection.handleConnectionClosed(i, request);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<CompareResult> compare(final CompareRequest request,
+      final ResultHandler<? super CompareResult> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final LDAPCompareFutureResultImpl future = new LDAPCompareFutureResultImpl(
+        i, request, resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleCompare(i, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<Result> delete(final DeleteRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
+        resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleDelete(i, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public <R extends ExtendedResult> FutureResult<R> extendedRequest(
+      final ExtendedRequest<R> request,
+      final ResultHandler<? super R> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final LDAPExtendedFutureResultImpl<R> future = new LDAPExtendedFutureResultImpl<R>(
+        i, request, resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleExtendedRequest(i, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isClosed()
+  {
+    // FIXME: this should be true after close has been called.
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isValid()
+  {
+    // FIXME: this should be false if this connection is disconnected.
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<Result> modify(final ModifyRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
+        resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleModify(i, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<Result> modifyDN(final ModifyDNRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request,
+        resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleModifyDN(i, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void removeConnectionEventListener(
+      final ConnectionEventListener listener) throws NullPointerException
+  {
+    Validator.ensureNotNull(listener);
+    listeners.remove(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<Result> search(final SearchRequest request,
+      final SearchResultHandler resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final int i = messageID.getAndIncrement();
+    final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl(i,
+        request, resultHandler, intermediateResponseHandler, this);
+    serverConnection.handleSearch(i, request, future, future);
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    StringBuilder builder = new StringBuilder();
+    builder.append("InternalConnection(");
+    builder.append(String.valueOf(serverConnection));
+    builder.append(')');
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPBindFutureResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPBindFutureResultImpl.java
new file mode 100644
index 0000000..9d8d77e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPBindFutureResultImpl.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.BindClient;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.Responses;
+
+
+
+/**
+ * Bind result future implementation.
+ */
+final class LDAPBindFutureResultImpl extends
+    AbstractLDAPFutureResultImpl<BindResult>
+{
+  private final BindClient bindClient;
+
+
+
+  LDAPBindFutureResultImpl(final int requestID, final BindClient bindClient,
+      final ResultHandler<? super BindResult> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler,
+      final AsynchronousConnection connection)
+  {
+    super(requestID, resultHandler, intermediateResponseHandler, connection);
+    this.bindClient = bindClient;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected boolean isCancelable() {
+    return false;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder sb = new StringBuilder();
+    sb.append("LDAPBindFutureResultImpl(");
+    sb.append("bindClient = ");
+    sb.append(bindClient);
+    super.toString(sb);
+    sb.append(")");
+    return sb.toString();
+  }
+
+
+
+  BindClient getBindClient()
+  {
+    return bindClient;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  BindResult newErrorResult(final ResultCode resultCode,
+      final String diagnosticMessage, final Throwable cause)
+  {
+    return Responses.newBindResult(resultCode).setDiagnosticMessage(
+        diagnosticMessage).setCause(cause);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPClientFilter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPClientFilter.java
new file mode 100644
index 0000000..47b22bd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPClientFilter.java
@@ -0,0 +1,644 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.OID_NOTICE_OF_DISCONNECTION;
+
+import java.io.EOFException;
+import java.io.IOException;
+
+import javax.net.ssl.SSLEngine;
+
+import org.opends.sdk.ConnectionSecurityLayer;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.Connection;
+import org.glassfish.grizzly.EmptyCompletionHandler;
+import org.glassfish.grizzly.Grizzly;
+import org.glassfish.grizzly.attributes.Attribute;
+import org.glassfish.grizzly.filterchain.BaseFilter;
+import org.glassfish.grizzly.filterchain.FilterChainContext;
+import org.glassfish.grizzly.filterchain.NextAction;
+
+
+
+/**
+ * Grizzly filter implementation for decoding LDAP responses and handling client
+ * side logic for SSL and SASL operations over LDAP.
+ */
+final class LDAPClientFilter extends BaseFilter
+{
+  private static final Attribute<LDAPConnection> LDAP_CONNECTION_ATTR =
+    Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPClientConnection");
+  private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR =
+    Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader");
+
+  private final int maxASN1ElementSize;
+  private final LDAPReader ldapReader;
+
+  private static final AbstractLDAPMessageHandler<FilterChainContext>
+    CLIENT_RESPONSE_HANDLER = new AbstractLDAPMessageHandler<FilterChainContext>()
+  {
+    @Override
+    public void addResult(final FilterChainContext ctx, final int messageID,
+        final Result result) throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPFutureResultImpl)
+          {
+            final LDAPFutureResultImpl future =
+                (LDAPFutureResultImpl) pendingRequest;
+            if (future.getRequest() instanceof AddRequest)
+            {
+              future.setResultOrError(result);
+              return;
+            }
+          }
+          throw new UnexpectedResponseException(messageID, result);
+        }
+      }
+    }
+
+
+
+    @Override
+    public void bindResult(final FilterChainContext ctx, final int messageID,
+        final BindResult result) throws UnexpectedResponseException,
+        IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPBindFutureResultImpl)
+          {
+            final LDAPBindFutureResultImpl future =
+                ((LDAPBindFutureResultImpl) pendingRequest);
+            final BindClient bindClient = future.getBindClient();
+
+            try
+            {
+              if (!bindClient.evaluateResult(result))
+              {
+                // The server is expecting a multi stage bind response.
+                final int msgID = ldapConnection
+                    .addPendingRequest(pendingRequest);
+
+                final ASN1BufferWriter asn1Writer =
+                    ASN1BufferWriter.getWriter();
+                try
+                {
+                  final GenericBindRequest nextRequest = bindClient
+                      .nextBindRequest();
+                  new LDAPWriter().bindRequest(asn1Writer, msgID, 3,
+                      nextRequest);
+                  ctx.write(asn1Writer.getBuffer(), null);
+                }
+                finally
+                {
+                  asn1Writer.close();
+                }
+                return;
+              }
+            }
+            catch (final ErrorResultException e)
+            {
+              future.adaptErrorResult(e.getResult());
+              return;
+            }
+            catch (final IOException e)
+            {
+              // FIXME: I18N need to have a better error message.
+              // FIXME: Is this the best result code?
+              final Result errorResult = Responses.newResult(
+                  ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
+                  "An error occurred during multi-stage authentication")
+                  .setCause(e);
+              future.adaptErrorResult(errorResult);
+              return;
+            }
+
+            if (result.getResultCode() == ResultCode.SUCCESS)
+            {
+              final ConnectionSecurityLayer l = bindClient
+                  .getConnectionSecurityLayer();
+              if (l != null)
+              {
+                // The connection needs to be secured by the SASL
+                // mechanism.
+                ldapConnection.installFilter(new SASLFilter(l, ctx
+                    .getConnection().getTransport().getMemoryManager()));
+              }
+            }
+
+            ldapConnection.setBindOrStartTLSInProgress(false);
+            future.setResultOrError(result);
+            return;
+          }
+          throw new UnexpectedResponseException(messageID, result);
+        }
+      }
+    }
+
+
+
+    @Override
+    public void compareResult(final FilterChainContext ctx,
+        final int messageID, final CompareResult result)
+        throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPCompareFutureResultImpl)
+          {
+            final LDAPCompareFutureResultImpl future =
+                (LDAPCompareFutureResultImpl) pendingRequest;
+            future.setResultOrError(result);
+            return;
+          }
+          throw new UnexpectedResponseException(messageID, result);
+        }
+      }
+    }
+
+
+
+    @Override
+    public void deleteResult(final FilterChainContext ctx, final int messageID,
+        final Result result) throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPFutureResultImpl)
+          {
+            final LDAPFutureResultImpl future =
+                (LDAPFutureResultImpl) pendingRequest;
+            if (future.getRequest() instanceof DeleteRequest)
+            {
+              future.setResultOrError(result);
+              return;
+            }
+          }
+          throw new UnexpectedResponseException(messageID, result);
+        }
+      }
+    }
+
+
+
+    @Override
+    public void extendedResult(final FilterChainContext ctx,
+        final int messageID, final ExtendedResult result)
+        throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        if (messageID == 0)
+        {
+          if ((result.getOID() != null)
+              && result.getOID().equals(OID_NOTICE_OF_DISCONNECTION))
+          {
+
+            final Result errorResult = Responses
+                .newResult(result.getResultCode()).setDiagnosticMessage(
+                    result.getDiagnosticMessage());
+            ldapConnection.close(null, true, errorResult);
+            return;
+          }
+          else
+          {
+            // Unsolicited notification received.
+            ldapConnection.handleUnsolicitedNotification(result);
+          }
+        }
+
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if(pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPExtendedFutureResultImpl<?>)
+          {
+            final LDAPExtendedFutureResultImpl<?> extendedFuture =
+              ((LDAPExtendedFutureResultImpl<?>) pendingRequest);
+            try
+            {
+              handleExtendedResult0(ldapConnection, extendedFuture, result);
+            }
+            catch (final DecodeException de)
+            {
+              // FIXME: should the connection be closed as well?
+              final Result errorResult = Responses.newResult(
+                  ResultCode.CLIENT_SIDE_DECODING_ERROR).setDiagnosticMessage(
+                  de.getLocalizedMessage()).setCause(de);
+              extendedFuture.adaptErrorResult(errorResult);
+            }
+          }
+          else
+          {
+            throw new UnexpectedResponseException(messageID, result);
+          }
+        }
+      }
+    }
+
+
+
+    @Override
+    public void intermediateResponse(final FilterChainContext ctx,
+        final int messageID, final IntermediateResponse response)
+        throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .getPendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          pendingRequest.handleIntermediateResponse(response);
+        }
+      }
+    }
+
+
+
+    @Override
+    public void modifyDNResult(final FilterChainContext ctx,
+        final int messageID, final Result result)
+        throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPFutureResultImpl)
+          {
+            final LDAPFutureResultImpl future =
+                (LDAPFutureResultImpl) pendingRequest;
+            if (future.getRequest() instanceof ModifyDNRequest)
+            {
+              future.setResultOrError(result);
+              return;
+            }
+          }
+          throw new UnexpectedResponseException(messageID, result);
+        }
+      }
+    }
+
+
+
+    @Override
+    public void modifyResult(final FilterChainContext ctx, final int messageID,
+        final Result result) throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPFutureResultImpl)
+          {
+            final LDAPFutureResultImpl future =
+                (LDAPFutureResultImpl) pendingRequest;
+            if (future.getRequest() instanceof ModifyRequest)
+            {
+              future.setResultOrError(result);
+              return;
+            }
+          }
+          throw new UnexpectedResponseException(messageID, result);
+        }
+      }
+    }
+
+
+
+    @Override
+    public void searchResult(final FilterChainContext ctx, final int messageID,
+        final Result result) throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .removePendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPSearchFutureResultImpl)
+          {
+            ((LDAPSearchFutureResultImpl) pendingRequest)
+                .setResultOrError(result);
+          }
+          else
+          {
+            throw new UnexpectedResponseException(messageID, result);
+          }
+        }
+      }
+    }
+
+
+
+    @Override
+    public void searchResultEntry(final FilterChainContext ctx,
+        final int messageID, final SearchResultEntry entry)
+        throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .getPendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPSearchFutureResultImpl)
+          {
+            ((LDAPSearchFutureResultImpl) pendingRequest).handleEntry(entry);
+          }
+          else
+          {
+            throw new UnexpectedResponseException(messageID, entry);
+          }
+        }
+      }
+    }
+
+
+
+    @Override
+    public void searchResultReference(final FilterChainContext ctx,
+        final int messageID, final SearchResultReference reference)
+        throws UnexpectedResponseException, IOException
+    {
+      final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if(ldapConnection != null)
+      {
+        final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection
+            .getPendingRequest(messageID);
+
+        if (pendingRequest != null)
+        {
+          if (pendingRequest instanceof LDAPSearchFutureResultImpl)
+          {
+            ((LDAPSearchFutureResultImpl) pendingRequest)
+                .handleReference(reference);
+          }
+          else
+          {
+            throw new UnexpectedResponseException(messageID, reference);
+          }
+        }
+      }
+    }
+
+
+
+    // Needed in order to expose type information.
+    private <R extends ExtendedResult> void handleExtendedResult0(
+        final LDAPConnection conn,
+        final LDAPExtendedFutureResultImpl<R> future,
+        final ExtendedResult result) throws DecodeException
+    {
+      final R decodedResponse = future.decodeResult(result, conn
+          .getLDAPOptions().getDecodeOptions());
+
+      if (future.getRequest() instanceof StartTLSExtendedRequest)
+      {
+        if (result.getResultCode() == ResultCode.SUCCESS)
+        {
+          try
+          {
+            final StartTLSExtendedRequest request = (StartTLSExtendedRequest) future
+                .getRequest();
+            conn.startTLS(request.getSSLContext(),
+                request.getEnabledProtocols(), request.getEnabledCipherSuites(),
+                new EmptyCompletionHandler<SSLEngine>()
+                {
+                  @Override
+                  public void completed(final SSLEngine result)
+                  {
+                    conn.setBindOrStartTLSInProgress(false);
+                    future.setResultOrError(decodedResponse);
+                  }
+
+
+
+                  @Override
+                  public void failed(final Throwable throwable)
+                  {
+                    final Result errorResult = Responses.newResult(
+                        ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(throwable)
+                        .setDiagnosticMessage("SSL handshake failed");
+                    conn.setBindOrStartTLSInProgress(false);
+                    conn.close(null, false, errorResult);
+                    future.adaptErrorResult(errorResult);
+                  }
+                });
+            return;
+          }
+          catch (final IOException e)
+          {
+            final Result errorResult = Responses.newResult(
+                ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)
+                .setDiagnosticMessage(e.getMessage());
+            future.adaptErrorResult(errorResult);
+            conn.close(null, false, errorResult);
+            return;
+          }
+        }
+      }
+
+      future.setResultOrError(decodedResponse);
+    }
+  };
+
+
+
+  LDAPClientFilter(final LDAPReader ldapReader, final int maxASN1ElementSize)
+  {
+    this.ldapReader = ldapReader;
+    this.maxASN1ElementSize = maxASN1ElementSize;
+  }
+
+
+
+  @Override
+  public void exceptionOccurred(final FilterChainContext ctx,
+      final Throwable error)
+  {
+    final Connection<?> connection = ctx.getConnection();
+    if (!connection.isOpen())
+    {
+      // Grizzly doens't not deregister the read interest from the
+      // selector so closing the connection results in an
+      // EOFException.
+      // Just ignore errors on closed connections.
+      return;
+    }
+    final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(connection);
+
+    Result errorResult;
+    if (error instanceof EOFException)
+    {
+      // FIXME: Is this the best result code?
+      errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN)
+          .setCause(error);
+    }
+    else
+    {
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+          .setCause(error);
+    }
+    ldapConnection.close(null, false, errorResult);
+  }
+
+
+
+  @Override
+  public NextAction handleClose(final FilterChainContext ctx)
+      throws IOException
+  {
+    final Connection<?> connection = ctx.getConnection();
+    final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR
+        .remove(connection);
+    if (ldapConnection != null)
+    {
+      TimeoutChecker.INSTANCE.removeConnection(ldapConnection);
+      final Result errorResult = Responses
+          .newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN);
+      ldapConnection.close(null, false, errorResult);
+    }
+    return ctx.getInvokeAction();
+  }
+
+
+
+  @Override
+  public NextAction handleRead(final FilterChainContext ctx) throws IOException
+  {
+    final Buffer buffer = (Buffer) ctx.getMessage();
+    ASN1BufferReader asn1Reader = LDAP_ASN1_READER_ATTR
+        .get(ctx.getConnection());
+    if (asn1Reader == null)
+    {
+      asn1Reader = new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection()
+          .getTransport().getMemoryManager());
+      LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader);
+    }
+    asn1Reader.appendBytesRead(buffer);
+
+    try
+    {
+      while (asn1Reader.elementAvailable())
+      {
+        ldapReader.decode(asn1Reader, CLIENT_RESPONSE_HANDLER, ctx);
+      }
+    }
+    catch(IOException ioe)
+    {
+      final LDAPConnection ldapConnection =
+          LDAP_CONNECTION_ATTR.get(ctx.getConnection());
+      final Result errorResult =
+          Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR)
+              .setCause(ioe).setDiagnosticMessage(ioe.getMessage());
+      ldapConnection.close(null, false, errorResult);
+      throw ioe;
+    }
+    finally
+    {
+      asn1Reader.disposeBytesRead();
+    }
+
+    return ctx.getStopAction();
+  }
+
+
+
+  void registerConnection(final Connection<?> connection,
+      final LDAPConnection ldapConnection)
+  {
+    TimeoutChecker.INSTANCE.addConnection(ldapConnection);
+    LDAP_CONNECTION_ATTR.set(connection, ldapConnection);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPCompareFutureResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPCompareFutureResultImpl.java
new file mode 100644
index 0000000..193ddc8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPCompareFutureResultImpl.java
@@ -0,0 +1,92 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.CompareRequest;
+import org.opends.sdk.responses.CompareResult;
+import org.opends.sdk.responses.Responses;
+
+
+
+/**
+ * Compare result future implementation.
+ */
+final class LDAPCompareFutureResultImpl extends
+    AbstractLDAPFutureResultImpl<CompareResult>
+{
+  private final CompareRequest request;
+
+
+
+  LDAPCompareFutureResultImpl(final int requestID,
+      final CompareRequest request,
+      final ResultHandler<? super CompareResult> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler,
+      final AsynchronousConnection connection)
+  {
+    super(requestID, resultHandler, intermediateResponseHandler, connection);
+    this.request = request;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder sb = new StringBuilder();
+    sb.append("LDAPCompareFutureResultImpl(");
+    sb.append("request = ");
+    sb.append(request);
+    super.toString(sb);
+    sb.append(")");
+    return sb.toString();
+  }
+
+
+
+  CompareRequest getRequest()
+  {
+    return request;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  CompareResult newErrorResult(final ResultCode resultCode,
+      final String diagnosticMessage, final Throwable cause)
+  {
+    return Responses.newCompareResult(resultCode).setDiagnosticMessage(
+        diagnosticMessage).setCause(cause);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnection.java
new file mode 100644
index 0000000..79a1eb9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnection.java
@@ -0,0 +1,1033 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+import org.glassfish.grizzly.CompletionHandler;
+import org.glassfish.grizzly.filterchain.DefaultFilterChain;
+import org.glassfish.grizzly.filterchain.Filter;
+import org.glassfish.grizzly.filterchain.FilterChain;
+import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
+import org.glassfish.grizzly.ssl.SSLFilter;
+import com.sun.opends.sdk.util.CompletedFutureResult;
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * LDAP connection implementation.
+ * <p>
+ * TODO: handle illegal state exceptions.
+ */
+final class LDAPConnection extends AbstractAsynchronousConnection implements
+    AsynchronousConnection
+{
+  private final org.glassfish.grizzly.Connection<?> connection;
+
+  private Result connectionInvalidReason;
+
+  private FilterChain customFilterChain;
+
+  private boolean isClosed = false;
+
+  private final List<ConnectionEventListener> listeners =
+    new CopyOnWriteArrayList<ConnectionEventListener>();
+
+  private final AtomicInteger nextMsgID = new AtomicInteger(1);
+
+  private final AtomicBoolean bindOrStartTLSInProgress =
+      new AtomicBoolean(false);
+
+  private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests =
+    new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>();
+
+  private final Object stateLock = new Object();
+
+  private final LDAPWriter ldapWriter = new LDAPWriter();
+
+  private final LDAPOptions options;
+
+
+
+  /**
+   * Creates a new LDAP connection.
+   *
+   * @param connection
+   *          The Grizzly connection.
+   * @param options
+   *          The LDAP client options.
+   */
+  LDAPConnection(final org.glassfish.grizzly.Connection<?> connection,
+      final LDAPOptions options)
+  {
+    this.connection = connection;
+    this.options = options;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Void> abandon(final AbandonRequest request)
+  {
+    final AbstractLDAPFutureResultImpl<?> pendingRequest;
+    final int messageID = nextMsgID.getAndIncrement();
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        return new CompletedFutureResult<Void>(
+            ErrorResultException.wrap(connectionInvalidReason), messageID);
+      }
+      if (bindOrStartTLSInProgress.get())
+      {
+        final Result errorResult = Responses.newResult(
+            ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+            "Bind or Start TLS operation in progress");
+        return new CompletedFutureResult<Void>(
+            ErrorResultException.wrap(errorResult), messageID);
+      }
+
+      // First remove the future associated with the request to be abandoned.
+      pendingRequest = pendingRequests.remove(request.getRequestID());
+    }
+
+    if (pendingRequest == null)
+    {
+      // There has never been a request with the specified message ID or the
+      // response has already been received and handled. We can ignore this
+      // abandon request.
+
+      // Message ID will be -1 since no request was sent.
+      return new CompletedFutureResult<Void>((Void) null);
+    }
+
+    pendingRequest.cancel(false);
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.abandonRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+        return new CompletedFutureResult<Void>((Void) null, messageID);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      return new CompletedFutureResult<Void>(
+          ErrorResultException.wrap(errorResult), messageID);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> add(final AddRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID,
+        request, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (bindOrStartTLSInProgress.get())
+      {
+        future.setResultOrError(Responses
+            .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+                "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.addRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void addConnectionEventListener(final ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException
+  {
+    Validator.ensureNotNull(listener);
+    listeners.add(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<BindResult> bind(final BindRequest request,
+      final ResultHandler<? super BindResult> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+
+    BindClient context;
+    try
+    {
+      context = request
+          .createBindClient(connection.getPeerAddress() instanceof InetSocketAddress ?
+              ((InetSocketAddress) connection
+              .getPeerAddress()).getHostName() : connection.getPeerAddress()
+              .toString());
+    }
+    catch (final Exception e)
+    {
+      // FIXME: I18N need to have a better error message.
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses
+          .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+          .setDiagnosticMessage(
+              "An error occurred while creating a bind context").setCause(e);
+      final ErrorResultException error = ErrorResultException.wrap(errorResult);
+      if (resultHandler != null)
+      {
+        resultHandler.handleErrorResult(error);
+      }
+      return new CompletedFutureResult<BindResult>(error, messageID);
+    }
+
+    final LDAPBindFutureResultImpl future = new LDAPBindFutureResultImpl(
+        messageID, context, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (!bindOrStartTLSInProgress.compareAndSet(false, true))
+      {
+        future.setResultOrError(Responses.newBindResult(
+            ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+            "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      if (!pendingRequests.isEmpty())
+      {
+        future.setResultOrError(Responses.newBindResult(
+            ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+            "There are other operations pending on this connection"));
+        return future;
+      }
+
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        // Use the bind client to get the initial request instead of using the
+        // bind request passed to this method.
+        final GenericBindRequest initialRequest = context.nextBindRequest();
+        ldapWriter.bindRequest(asn1Writer, messageID, 3, initialRequest);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close(final UnbindRequest request, final String reason)
+      throws NullPointerException
+  {
+    // FIXME: I18N need to internationalize this message.
+    Validator.ensureNotNull(request);
+
+    close(
+        request,
+        false,
+        Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED)
+            .setDiagnosticMessage(
+                "Connection closed by client"
+                    + (reason != null ? ": " + reason : "")));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<CompareResult> compare(final CompareRequest request,
+      final ResultHandler<? super CompareResult> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+    final LDAPCompareFutureResultImpl future = new LDAPCompareFutureResultImpl(
+        messageID, request, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (bindOrStartTLSInProgress.get())
+      {
+        future.setResultOrError(Responses.newCompareResult(
+            ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+            "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.compareRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> delete(final DeleteRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID,
+        request, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (bindOrStartTLSInProgress.get())
+      {
+        future.setResultOrError(Responses
+            .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+                "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.deleteRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R extends ExtendedResult> FutureResult<R> extendedRequest(
+      final ExtendedRequest<R> request,
+      final ResultHandler<? super R> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+    final LDAPExtendedFutureResultImpl<R> future = new LDAPExtendedFutureResultImpl<R>(
+        messageID, request, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (!bindOrStartTLSInProgress.compareAndSet(false, true))
+      {
+        future.setResultOrError(request.getResultDecoder()
+            .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "",
+                "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      if (request.getOID().equals(StartTLSExtendedRequest.OID))
+      {
+        if (!pendingRequests.isEmpty())
+        {
+          future.setResultOrError(request.getResultDecoder()
+              .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "",
+                  "There are pending operations on this connection"));
+          return future;
+        }
+        if (isTLSEnabled())
+        {
+          future.setResultOrError(request.getResultDecoder()
+              .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "",
+                  "This connection is already TLS enabled"));
+        }
+      }
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.extendedRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isClosed()
+  {
+    return isClosed;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isValid()
+  {
+    return connectionInvalidReason == null && !isClosed;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> modify(final ModifyRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID,
+        request, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (bindOrStartTLSInProgress.get())
+      {
+        future.setResultOrError(Responses
+            .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+                "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.modifyRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> modifyDN(final ModifyDNRequest request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+    final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID,
+        request, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (bindOrStartTLSInProgress.get())
+      {
+        future.setResultOrError(Responses
+            .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+                "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.modifyDNRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void removeConnectionEventListener(
+      final ConnectionEventListener listener) throws NullPointerException
+  {
+    Validator.ensureNotNull(listener);
+    listeners.remove(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> search(final SearchRequest request,
+      final SearchResultHandler resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler)
+  {
+    final int messageID = nextMsgID.getAndIncrement();
+    final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl(
+        messageID, request, resultHandler, intermediateResponseHandler, this);
+
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        future.adaptErrorResult(connectionInvalidReason);
+        return future;
+      }
+      if (bindOrStartTLSInProgress.get())
+      {
+        future.setResultOrError(Responses
+            .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+                "Bind or Start TLS operation in progress"));
+        return future;
+      }
+      pendingRequests.put(messageID, future);
+    }
+
+    try
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        ldapWriter.searchRequest(asn1Writer, messageID, request);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+    catch (final IOException e)
+    {
+      pendingRequests.remove(messageID);
+
+      // FIXME: what other sort of IOExceptions can be thrown?
+      // FIXME: Is this the best result code?
+      final Result errorResult = Responses.newResult(
+          ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+      connectionErrorOccurred(errorResult);
+      future.adaptErrorResult(errorResult);
+    }
+
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    StringBuilder builder = new StringBuilder();
+    builder.append("LDAPConnection(");
+    builder.append(connection.getLocalAddress());
+    builder.append(',');
+    builder.append(connection.getPeerAddress());
+    builder.append(')');
+    return builder.toString();
+  }
+
+
+
+  int addPendingRequest(final AbstractLDAPFutureResultImpl<?> request)
+      throws ErrorResultException
+  {
+    final int newMsgID = nextMsgID.getAndIncrement();
+    synchronized (stateLock)
+    {
+      if (connectionInvalidReason != null)
+      {
+        throw ErrorResultException.wrap(connectionInvalidReason);
+      }
+      pendingRequests.put(newMsgID, request);
+    }
+    return newMsgID;
+  }
+
+
+
+  long cancelExpiredRequests(final long currentTime)
+  {
+    final long timeout = options.getTimeout(TimeUnit.MILLISECONDS);
+    long delay = timeout;
+    if (timeout > 0)
+    {
+      for (int requestID : pendingRequests.keySet())
+      {
+        final AbstractLDAPFutureResultImpl<?> future = pendingRequests
+            .get(requestID);
+        if (future != null)
+        {
+          final long diff = (future.getTimestamp() + timeout) - currentTime;
+          if (diff <= 0 && pendingRequests.remove(requestID) != null)
+          {
+            StaticUtils.DEBUG_LOG.fine("Cancelling expired future result: "
+                + future);
+            final Result result = Responses
+                .newResult(ResultCode.CLIENT_SIDE_TIMEOUT);
+            future.adaptErrorResult(result);
+
+            abandon(Requests.newAbandonRequest(future.getRequestID()));
+          }
+          else
+          {
+            delay = Math.min(delay, diff);
+          }
+        }
+      }
+    }
+    return delay;
+  }
+
+
+
+  void close(final UnbindRequest unbindRequest,
+      final boolean isDisconnectNotification, final Result reason)
+  {
+    boolean notifyClose = false;
+    boolean notifyErrorOccurred = false;
+
+    synchronized (stateLock)
+    {
+      if (isClosed) {
+        // Already closed.
+        return;
+      }
+
+      if (connectionInvalidReason != null)
+      {
+        // Already closed.
+        isClosed = true;
+        return;
+      }
+
+      if (unbindRequest != null)
+      {
+        // User closed.
+        isClosed = true;
+        notifyClose = true;
+      }
+      else
+      {
+        notifyErrorOccurred = true;
+      }
+
+      // Mark the connection as invalid.
+      connectionInvalidReason = reason;
+    }
+
+    // First abort all outstanding requests.
+    for (int requestID : pendingRequests.keySet())
+    {
+      final AbstractLDAPFutureResultImpl<?> future = pendingRequests
+          .remove(requestID);
+      if (future != null)
+      {
+        future.adaptErrorResult(reason);
+      }
+    }
+
+    // Now try cleanly closing the connection if possible.
+    // Only send unbind if specified.
+    if (unbindRequest != null && !isDisconnectNotification)
+    {
+      try
+      {
+        final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+        try
+        {
+          ldapWriter.unbindRequest(asn1Writer, nextMsgID.getAndIncrement(),
+              unbindRequest);
+          connection.write(asn1Writer.getBuffer(), null);
+        }
+        finally
+        {
+          asn1Writer.recycle();
+        }
+      }
+      catch (final IOException e)
+      {
+        // Underlying channel prob blown up. Just ignore.
+      }
+    }
+
+    try
+    {
+      connection.close();
+    }
+    catch (final IOException e)
+    {
+      // Ignore.
+    }
+
+    // Notify listeners.
+    if (notifyClose)
+    {
+      for (final ConnectionEventListener listener : listeners)
+      {
+        listener.handleConnectionClosed();
+      }
+    }
+
+    if (notifyErrorOccurred)
+    {
+      for (final ConnectionEventListener listener : listeners)
+      {
+        listener.handleConnectionError(isDisconnectNotification,
+            ErrorResultException.wrap(reason));
+      }
+    }
+  }
+
+
+
+  LDAPOptions getLDAPOptions()
+  {
+    return options;
+  }
+
+
+
+  AbstractLDAPFutureResultImpl<?> getPendingRequest(final Integer messageID)
+  {
+    return pendingRequests.get(messageID);
+  }
+
+
+
+  synchronized void handleUnsolicitedNotification(final ExtendedResult result)
+  {
+    if (isClosed)
+    {
+      // Don't notify after connection is closed.
+      return;
+    }
+
+    for (final ConnectionEventListener listener : listeners)
+    {
+      listener.handleUnsolicitedNotification(result);
+    }
+  }
+
+
+
+  void installFilter(final Filter filter)
+  {
+    if (customFilterChain == null)
+    {
+      customFilterChain = new DefaultFilterChain(
+          (FilterChain) connection.getProcessor());
+      connection.setProcessor(customFilterChain);
+    }
+
+    // Install the SSLFilter in the custom filter chain
+    customFilterChain.add(customFilterChain.size() - 1, filter);
+  }
+
+
+
+  /**
+   * Indicates whether or not TLS is enabled on this connection.
+   *
+   * @return {@code true} if TLS is enabled on this connection, otherwise
+   *         {@code false}.
+   */
+  boolean isTLSEnabled()
+  {
+    final FilterChain currentFilterChain = (FilterChain) connection
+        .getProcessor();
+    return currentFilterChain.get(currentFilterChain.size() - 2) instanceof SSLFilter;
+  }
+
+
+
+  AbstractLDAPFutureResultImpl<?> removePendingRequest(final Integer messageID)
+  {
+    return pendingRequests.remove(messageID);
+  }
+
+
+
+  void setBindOrStartTLSInProgress(final boolean state)
+  {
+    bindOrStartTLSInProgress.set(state);
+  }
+
+
+
+  synchronized void startTLS(final SSLContext sslContext,
+      final List<String> protocols, final List<String> cipherSuites,
+      final CompletionHandler<SSLEngine> completionHandler) throws IOException
+  {
+    if (isTLSEnabled())
+    {
+      return;
+    }
+
+    SSLFilter sslFilter;
+    SSLEngineConfigurator sslEngineConfigurator;
+
+    sslEngineConfigurator = new SSLEngineConfigurator(sslContext, true, false,
+        false);
+    sslEngineConfigurator.setEnabledProtocols(protocols.isEmpty() ?
+        null : protocols.toArray(new String[protocols.size()]));
+    sslEngineConfigurator.setEnabledCipherSuites(cipherSuites.isEmpty() ?
+        null : cipherSuites.toArray(new String[cipherSuites.size()]));
+    sslFilter = new SSLFilter(null, sslEngineConfigurator);
+    installFilter(sslFilter);
+    sslFilter.handshake(connection, completionHandler);
+  }
+
+
+
+  private void connectionErrorOccurred(final Result reason)
+  {
+    close(null, false, reason);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.java
new file mode 100644
index 0000000..699a24a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConnectionFactoryImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.util.concurrent.ExecutionException;
+
+import javax.net.ssl.SSLEngine;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.StartTLSExtendedRequest;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+
+import org.glassfish.grizzly.CompletionHandler;
+import org.glassfish.grizzly.Connection;
+import org.glassfish.grizzly.EmptyCompletionHandler;
+import org.glassfish.grizzly.filterchain.DefaultFilterChain;
+import org.glassfish.grizzly.filterchain.FilterChain;
+import org.glassfish.grizzly.filterchain.TransportFilter;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+import com.sun.opends.sdk.util.CompletedFutureResult;
+import com.sun.opends.sdk.util.FutureResultTransformer;
+import com.sun.opends.sdk.util.RecursiveFutureResult;
+
+
+
+/**
+ * LDAP connection factory implementation.
+ */
+public final class LDAPConnectionFactoryImpl extends AbstractConnectionFactory
+    implements ConnectionFactory
+{
+
+  @SuppressWarnings("rawtypes")
+  private final class FutureResultImpl implements CompletionHandler<Connection>
+  {
+    private final FutureResultTransformer<Result, AsynchronousConnection> futureStartTLSResult;
+
+    private final RecursiveFutureResult<LDAPConnection, ExtendedResult> futureConnectionResult;
+
+    private LDAPConnection connection;
+
+
+
+    private FutureResultImpl(
+        final ResultHandler<? super AsynchronousConnection> handler)
+    {
+      this.futureStartTLSResult = new FutureResultTransformer<Result, AsynchronousConnection>(
+          handler)
+      {
+
+        @Override
+        protected ErrorResultException transformErrorResult(
+            final ErrorResultException errorResult)
+        {
+          // Ensure that the connection is closed.
+          try
+          {
+            if (connection != null)
+            {
+              connection.close();
+            }
+          }
+          catch (final Exception e)
+          {
+            // Ignore.
+          }
+          return errorResult;
+        }
+
+
+
+        @Override
+        protected LDAPConnection transformResult(final Result result)
+            throws ErrorResultException
+        {
+          return connection;
+        }
+
+      };
+
+      this.futureConnectionResult = new RecursiveFutureResult<LDAPConnection, ExtendedResult>(
+          futureStartTLSResult)
+      {
+
+        @Override
+        protected FutureResult<? extends ExtendedResult> chainResult(
+            final LDAPConnection innerResult,
+            final ResultHandler<? super ExtendedResult> handler)
+            throws ErrorResultException
+        {
+          connection = innerResult;
+
+          if (options.getSSLContext() != null && options.useStartTLS())
+          {
+            final StartTLSExtendedRequest startTLS = Requests
+                .newStartTLSExtendedRequest(options.getSSLContext());
+            startTLS.addEnabledCipherSuite(
+                options.getEnabledCipherSuites().toArray(
+                    new String[options.getEnabledCipherSuites().size()]));
+            startTLS.addEnabledProtocol(
+                options.getEnabledProtocols().toArray(
+                    new String[options.getEnabledProtocols().size()]));
+            return connection.extendedRequest(startTLS, handler);
+          }
+
+          if (options.getSSLContext() != null)
+          {
+            try
+            {
+              connection.startTLS(options.getSSLContext(),
+                  options.getEnabledProtocols(),
+                  options.getEnabledCipherSuites(),
+                  new EmptyCompletionHandler<SSLEngine>()
+                  {
+                    @Override
+                    public void completed(final SSLEngine result)
+                    {
+                      handler.handleResult(null);
+                    }
+
+
+
+                    @Override
+                    public void failed(final Throwable throwable)
+                    {
+                      final Result errorResult = Responses
+                          .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR)
+                          .setCause(throwable)
+                          .setDiagnosticMessage(throwable.getMessage());
+                      handler.handleErrorResult(ErrorResultException
+                          .wrap(errorResult));
+                    }
+                  });
+              return null;
+            }
+            catch (final IOException ioe)
+            {
+              final Result errorResult = Responses
+                  .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR)
+                  .setCause(ioe).setDiagnosticMessage(ioe.getMessage());
+              throw ErrorResultException.wrap(errorResult);
+            }
+          }
+          handler.handleResult(null);
+          return new CompletedFutureResult<ExtendedResult>(
+              (ExtendedResult) null);
+        }
+
+      };
+
+      futureStartTLSResult.setFutureResult(futureConnectionResult);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void cancelled()
+    {
+      // Ignore this.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void completed(final Connection connection)
+    {
+      futureConnectionResult.handleResult(adaptConnection(connection));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void failed(final Throwable throwable)
+    {
+      futureConnectionResult
+          .handleErrorResult(adaptConnectionException(throwable));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void updated(final Connection connection)
+    {
+      // Ignore this.
+    }
+
+  }
+
+
+
+  private final SocketAddress socketAddress;
+
+  private final TCPNIOTransport transport;
+
+  private final FilterChain defaultFilterChain;
+
+  private final LDAPClientFilter clientFilter;
+
+  private final LDAPOptions options;
+
+
+
+  /**
+   * Creates a new LDAP connection factory implementation which can be used to
+   * create connections to the Directory Server at the provided host and port
+   * address using provided connection options.
+   *
+   * @param address
+   *          The address of the Directory Server to connect to.
+   * @param options
+   *          The LDAP connection options to use when creating connections.
+   */
+  public LDAPConnectionFactoryImpl(final SocketAddress address,
+      final LDAPOptions options)
+  {
+    if (options.getTCPNIOTransport() == null)
+    {
+      this.transport = LDAPDefaultTCPNIOTransport.getInstance();
+    }
+    else
+    {
+      this.transport = options.getTCPNIOTransport();
+    }
+    this.socketAddress = address;
+    this.options = new LDAPOptions(options);
+    this.clientFilter = new LDAPClientFilter(new LDAPReader(
+        this.options.getDecodeOptions()), 0);
+    this.defaultFilterChain = new DefaultFilterChain();
+    this.defaultFilterChain.add(new TransportFilter());
+    this.defaultFilterChain.add(clientFilter);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> handler)
+  {
+    final FutureResultImpl future = new FutureResultImpl(handler);
+
+    try
+    {
+      future.futureConnectionResult.setFutureResult(transport.connect(
+          socketAddress, future));
+      return future.futureStartTLSResult;
+    }
+    catch (final IOException e)
+    {
+      final ErrorResultException result = adaptConnectionException(e);
+      return new CompletedFutureResult<AsynchronousConnection>(result);
+    }
+  }
+
+
+
+  /**
+   * Returns the address of the Directory Server.
+   *
+   * @return The address of the Directory Server.
+   */
+  public SocketAddress getSocketAddress()
+  {
+    return socketAddress;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("LDAPConnectionFactory(");
+    builder.append(getSocketAddress().toString());
+    builder.append(')');
+    return builder.toString();
+  }
+
+
+
+  private LDAPConnection adaptConnection(final Connection<?> connection)
+  {
+    // Test shows that its much faster with non block writes but risk
+    // running out of memory if the server is slow.
+    connection.configureBlocking(true);
+    connection.setProcessor(defaultFilterChain);
+
+    final LDAPConnection ldapConnection = new LDAPConnection(connection,
+        options);
+    clientFilter.registerConnection(connection, ldapConnection);
+    return ldapConnection;
+  }
+
+
+
+  private ErrorResultException adaptConnectionException(Throwable t)
+  {
+    if (t instanceof ExecutionException)
+    {
+      t = t.getCause();
+    }
+
+    final Result result = Responses
+        .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR).setCause(t)
+        .setDiagnosticMessage(t.getMessage());
+    return ErrorResultException.wrap(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConstants.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConstants.java
new file mode 100644
index 0000000..a79b8fb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPConstants.java
@@ -0,0 +1,332 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.ldap;
+
+
+
+/**
+ * This class defines a number of constants used in the LDAP protocol.
+ */
+public final class LDAPConstants
+{
+
+  /**
+   * The protocol op type for bind requests.
+   */
+  public static final byte OP_TYPE_BIND_REQUEST = 0x60;
+
+  /**
+   * The protocol op type for bind responses.
+   */
+  public static final byte OP_TYPE_BIND_RESPONSE = 0x61;
+
+  /**
+   * The protocol op type for unbind requests.
+   */
+  public static final byte OP_TYPE_UNBIND_REQUEST = 0x42;
+
+  /**
+   * The protocol op type for search requests.
+   */
+  public static final byte OP_TYPE_SEARCH_REQUEST = 0x63;
+
+  /**
+   * The protocol op type for search result entries.
+   */
+  public static final byte OP_TYPE_SEARCH_RESULT_ENTRY = 0x64;
+
+  /**
+   * The protocol op type for search result references.
+   */
+  public static final byte OP_TYPE_SEARCH_RESULT_REFERENCE = 0x73;
+
+  /**
+   * The protocol op type for search result done elements.
+   */
+  public static final byte OP_TYPE_SEARCH_RESULT_DONE = 0x65;
+
+  /**
+   * The protocol op type for modify requests.
+   */
+  public static final byte OP_TYPE_MODIFY_REQUEST = 0x66;
+
+  /**
+   * The protocol op type for modify responses.
+   */
+  public static final byte OP_TYPE_MODIFY_RESPONSE = 0x67;
+
+  /**
+   * The protocol op type for add requests.
+   */
+  public static final byte OP_TYPE_ADD_REQUEST = 0x68;
+
+  /**
+   * The protocol op type for add responses.
+   */
+  public static final byte OP_TYPE_ADD_RESPONSE = 0x69;
+
+  /**
+   * The protocol op type for delete requests.
+   */
+  public static final byte OP_TYPE_DELETE_REQUEST = 0x4A;
+
+  /**
+   * The protocol op type for delete responses.
+   */
+  public static final byte OP_TYPE_DELETE_RESPONSE = 0x6B;
+
+  /**
+   * The protocol op type for modify DN requests.
+   */
+  public static final byte OP_TYPE_MODIFY_DN_REQUEST = 0x6C;
+
+  /**
+   * The protocol op type for modify DN responses.
+   */
+  public static final byte OP_TYPE_MODIFY_DN_RESPONSE = 0x6D;
+
+  /**
+   * The protocol op type for compare requests.
+   */
+  public static final byte OP_TYPE_COMPARE_REQUEST = 0x6E;
+
+  /**
+   * The protocol op type for compare responses.
+   */
+  public static final byte OP_TYPE_COMPARE_RESPONSE = 0x6F;
+
+  /**
+   * The protocol op type for abandon requests.
+   */
+  public static final byte OP_TYPE_ABANDON_REQUEST = 0x50;
+
+  /**
+   * The protocol op type for extended requests.
+   */
+  public static final byte OP_TYPE_EXTENDED_REQUEST = 0x77;
+
+  /**
+   * The protocol op type for extended responses.
+   */
+  public static final byte OP_TYPE_EXTENDED_RESPONSE = 0x78;
+
+  /**
+   * The protocol op type for intermediate responses.
+   */
+  public static final byte OP_TYPE_INTERMEDIATE_RESPONSE = 0x79;
+
+  /**
+   * The BER type to use for encoding the sequence of controls in an LDAP
+   * message.
+   */
+  public static final byte TYPE_CONTROL_SEQUENCE = (byte) 0xA0;
+
+  /**
+   * The BER type to use for encoding the sequence of referral URLs in an
+   * LDAPResult element.
+   */
+  public static final byte TYPE_REFERRAL_SEQUENCE = (byte) 0xA3;
+
+  /**
+   * The BER type to use for the AuthenticationChoice element in a bind request
+   * when simple authentication is to be used.
+   */
+  public static final byte TYPE_AUTHENTICATION_SIMPLE = (byte) 0x80;
+
+  /**
+   * The BER type to use for the AuthenticationChoice element in a bind request
+   * when SASL authentication is to be used.
+   */
+  public static final byte TYPE_AUTHENTICATION_SASL = (byte) 0xA3;
+
+  /**
+   * The BER type to use for the server SASL credentials in a bind response.
+   */
+  public static final byte TYPE_SERVER_SASL_CREDENTIALS = (byte) 0x87;
+
+  /**
+   * The BER type to use for AND filter components.
+   */
+  public static final byte TYPE_FILTER_AND = (byte) 0xA0;
+
+  /**
+   * The BER type to use for OR filter components.
+   */
+  public static final byte TYPE_FILTER_OR = (byte) 0xA1;
+
+  /**
+   * The BER type to use for NOT filter components.
+   */
+  public static final byte TYPE_FILTER_NOT = (byte) 0xA2;
+
+  /**
+   * The BER type to use for equality filter components.
+   */
+  public static final byte TYPE_FILTER_EQUALITY = (byte) 0xA3;
+
+  /**
+   * The BER type to use for substring filter components.
+   */
+  public static final byte TYPE_FILTER_SUBSTRING = (byte) 0xA4;
+
+  /**
+   * The BER type to use for greater than or equal to filter components.
+   */
+  public static final byte TYPE_FILTER_GREATER_OR_EQUAL = (byte) 0xA5;
+
+  /**
+   * The BER type to use for less than or equal to filter components.
+   */
+  public static final byte TYPE_FILTER_LESS_OR_EQUAL = (byte) 0xA6;
+
+  /**
+   * The BER type to use for presence filter components.
+   */
+  public static final byte TYPE_FILTER_PRESENCE = (byte) 0x87;
+
+  /**
+   * The BER type to use for approximate filter components.
+   */
+  public static final byte TYPE_FILTER_APPROXIMATE = (byte) 0xA8;
+
+  /**
+   * The BER type to use for extensible matching filter components.
+   */
+  public static final byte TYPE_FILTER_EXTENSIBLE_MATCH = (byte) 0xA9;
+
+  /**
+   * The BER type to use for the subInitial component of a substring filter.
+   */
+  public static final byte TYPE_SUBINITIAL = (byte) 0x80;
+
+  /**
+   * The BER type to use for the subAny component(s) of a substring filter.
+   */
+  public static final byte TYPE_SUBANY = (byte) 0x81;
+
+  /**
+   * The BER type to use for the subFinal components of a substring filter.
+   */
+  public static final byte TYPE_SUBFINAL = (byte) 0x82;
+
+  /**
+   * The BER type to use for the matching rule OID in a matching rule assertion.
+   */
+  public static final byte TYPE_MATCHING_RULE_ID = (byte) 0x81;
+
+  /**
+   * The BER type to use for the attribute type in a matching rule assertion.
+   */
+  public static final byte TYPE_MATCHING_RULE_TYPE = (byte) 0x82;
+
+  /**
+   * The BER type to use for the assertion value in a matching rule assertion.
+   */
+  public static final byte TYPE_MATCHING_RULE_VALUE = (byte) 0x83;
+
+  /**
+   * The BER type to use for the DN attributes flag in a matching rule
+   * assertion.
+   */
+  public static final byte TYPE_MATCHING_RULE_DN_ATTRIBUTES = (byte) 0x84;
+
+  /**
+   * The BER type to use for the newSuperior component of a modify DN request.
+   */
+  public static final byte TYPE_MODIFY_DN_NEW_SUPERIOR = (byte) 0x80;
+
+  /**
+   * The BER type to use for the OID of an extended request.
+   */
+  public static final byte TYPE_EXTENDED_REQUEST_OID = (byte) 0x80;
+
+  /**
+   * The BER type to use for the value of an extended request.
+   */
+  public static final byte TYPE_EXTENDED_REQUEST_VALUE = (byte) 0x81;
+
+  /**
+   * The BER type to use for the OID of an extended response.
+   */
+  public static final byte TYPE_EXTENDED_RESPONSE_OID = (byte) 0x8A;
+
+  /**
+   * The BER type to use for the value of an extended response.
+   */
+  public static final byte TYPE_EXTENDED_RESPONSE_VALUE = (byte) 0x8B;
+
+  /**
+   * The BER type to use for the OID of an intermediate response message.
+   */
+  public static final byte TYPE_INTERMEDIATE_RESPONSE_OID = (byte) 0x80;
+
+  /**
+   * The BER type to use for the value of an intermediate response message.
+   */
+  public static final byte TYPE_INTERMEDIATE_RESPONSE_VALUE = (byte) 0x81;
+
+  /**
+   * The OID for the Kerberos V GSSAPI mechanism.
+   */
+  public static final String OID_GSSAPI_KERBEROS_V = "1.2.840.113554.1.2.2";
+
+  /**
+   * The OID for the LDAP notice of disconnection extended operation.
+   */
+  public static final String OID_NOTICE_OF_DISCONNECTION = "1.3.6.1.4.1.1466.20036";
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be the BER type for a new element.
+   */
+  public static final int ELEMENT_READ_STATE_NEED_TYPE = 0;
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be the first byte for the element length.
+   */
+  public static final int ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE = 1;
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be additional bytes of a multi-byte length.
+   */
+  public static final int ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES = 2;
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be applied to the value of the element.
+   */
+  public static final int ELEMENT_READ_STATE_NEED_VALUE_BYTES = 3;
+
+
+
+  private LDAPConstants()
+  {
+    // Prevent instantiation.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransport.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransport.java
new file mode 100644
index 0000000..5a6502c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransport.java
@@ -0,0 +1,80 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+
+import org.glassfish.grizzly.TransportFactory;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+
+
+
+/**
+ * The default TCPNIOTransport which all LDAPConnectionFactories and
+ * LDAPListeners will use unless otherwise specified in their options.
+ */
+final class LDAPDefaultTCPNIOTransport
+{
+  private static final TCPNIOTransport DEFAULT_TRANSPORT = TransportFactory
+      .getInstance().createTCPTransport();
+
+  static
+  {
+    try
+    {
+      DEFAULT_TRANSPORT.start();
+    }
+    catch (final IOException e)
+    {
+      throw new RuntimeException(e);
+    }
+  }
+
+
+
+  /**
+   * Returns the default TCPNIOTransport which all LDAPConnectionFactories and
+   * LDAPListeners will use unless otherwise specified in their options.
+   *
+   * @return The default TCPNIOTransport.
+   */
+  public static TCPNIOTransport getInstance()
+  {
+    return DEFAULT_TRANSPORT;
+  }
+
+
+
+  private LDAPDefaultTCPNIOTransport()
+  {
+    // Prevent instantiation.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPExtendedFutureResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPExtendedFutureResultImpl.java
new file mode 100644
index 0000000..6005fa4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPExtendedFutureResultImpl.java
@@ -0,0 +1,113 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.ExtendedRequest;
+import org.opends.sdk.requests.StartTLSExtendedRequest;
+import org.opends.sdk.responses.ExtendedResult;
+
+
+
+/**
+ * Extended result future implementation.
+ *
+ * @param <R>
+ *          The type of result returned by this future.
+ */
+final class LDAPExtendedFutureResultImpl<R extends ExtendedResult> extends
+    AbstractLDAPFutureResultImpl<R>
+{
+  private final ExtendedRequest<R> request;
+
+
+
+  LDAPExtendedFutureResultImpl(final int requestID,
+      final ExtendedRequest<R> request,
+      final ResultHandler<? super R> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler,
+      final AsynchronousConnection connection)
+  {
+    super(requestID, resultHandler, intermediateResponseHandler, connection);
+    this.request = request;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder sb = new StringBuilder();
+    sb.append("LDAPExtendedFutureResultImpl(");
+    sb.append("request = ");
+    sb.append(request);
+    super.toString(sb);
+    sb.append(")");
+    return sb.toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected boolean isCancelable() {
+    return !request.getOID().equals(StartTLSExtendedRequest.OID);
+  }
+
+
+
+  R decodeResult(final ExtendedResult result, final DecodeOptions options)
+      throws DecodeException
+  {
+    return request.getResultDecoder().decodeExtendedResult(result, options);
+  }
+
+
+
+  ExtendedRequest<R> getRequest()
+  {
+    return request;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  R newErrorResult(final ResultCode resultCode, final String diagnosticMessage,
+      final Throwable cause)
+  {
+    return request.getResultDecoder().newExtendedErrorResult(resultCode, "",
+        diagnosticMessage);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPFutureResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPFutureResultImpl.java
new file mode 100644
index 0000000..bcf8052
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPFutureResultImpl.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.AsynchronousConnection;
+import org.opends.sdk.IntermediateResponseHandler;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.ResultHandler;
+import org.opends.sdk.requests.Request;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Result future implementation.
+ */
+final class LDAPFutureResultImpl extends AbstractLDAPFutureResultImpl<Result>
+{
+  private final Request request;
+
+
+
+  LDAPFutureResultImpl(final int requestID, final Request request,
+      final ResultHandler<? super Result> resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler,
+      final AsynchronousConnection connection)
+  {
+    super(requestID, resultHandler, intermediateResponseHandler, connection);
+    this.request = request;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder sb = new StringBuilder();
+    sb.append("LDAPFutureResultImpl(");
+    sb.append("request = ");
+    sb.append(request);
+    super.toString(sb);
+    sb.append(")");
+    return sb.toString();
+  }
+
+
+
+  Request getRequest()
+  {
+    return request;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  Result newErrorResult(final ResultCode resultCode,
+      final String diagnosticMessage, final Throwable cause)
+  {
+    return Responses.newResult(resultCode)
+        .setDiagnosticMessage(diagnosticMessage).setCause(cause);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPListenerImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPListenerImpl.java
new file mode 100644
index 0000000..abbfea1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPListenerImpl.java
@@ -0,0 +1,182 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.util.logging.Level;
+
+import javax.net.ssl.SSLContext;
+
+import org.glassfish.grizzly.filterchain.DefaultFilterChain;
+import org.glassfish.grizzly.filterchain.FilterChain;
+import org.glassfish.grizzly.filterchain.TransportFilter;
+import org.glassfish.grizzly.nio.transport.TCPNIOServerConnection;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
+import org.glassfish.grizzly.ssl.SSLFilter;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LDAPClientContext;
+import org.opends.sdk.LDAPListenerOptions;
+import org.opends.sdk.ServerConnectionFactory;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * LDAP listener implementation.
+ */
+public final class LDAPListenerImpl implements Closeable
+{
+  private final TCPNIOTransport transport;
+  private final FilterChain defaultFilterChain;
+  private final ServerConnectionFactory<LDAPClientContext, Integer> connectionFactory;
+  private final TCPNIOServerConnection serverConnection;
+
+
+
+  /**
+   * Creates a new LDAP listener implementation which will listen for LDAP
+   * client connections using the provided address and connection options.
+   *
+   * @param address
+   *          The address to listen on.
+   * @param factory
+   *          The server connection factory which will be used to create server
+   *          connections.
+   * @param options
+   *          The LDAP listener options.
+   * @throws IOException
+   *           If an error occurred while trying to listen on the provided
+   *           address.
+   */
+  public LDAPListenerImpl(final SocketAddress address,
+      final ServerConnectionFactory<LDAPClientContext, Integer> factory,
+      final LDAPListenerOptions options) throws IOException
+  {
+    if (options.getTCPNIOTransport() == null)
+    {
+      this.transport = LDAPDefaultTCPNIOTransport.getInstance();
+    }
+    else
+    {
+      this.transport = options.getTCPNIOTransport();
+    }
+    this.connectionFactory = factory;
+    this.defaultFilterChain = new DefaultFilterChain();
+    this.defaultFilterChain.add(new TransportFilter());
+
+    if (options.getSSLContext() != null)
+    {
+      final SSLContext sslContext = options.getSSLContext();
+      SSLEngineConfigurator sslEngineConfigurator;
+
+      sslEngineConfigurator = new SSLEngineConfigurator(sslContext, false,
+          false, false);
+      this.defaultFilterChain.add(new SSLFilter(sslEngineConfigurator, null));
+    }
+
+    this.defaultFilterChain.add(new LDAPServerFilter(this, new LDAPReader(
+        new DecodeOptions(options.getDecodeOptions())), 0));
+
+    this.serverConnection = transport.bind(address, options.getBacklog());
+    this.serverConnection.setProcessor(defaultFilterChain);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close()
+  {
+    try
+    {
+      serverConnection.close().get();
+    }
+    catch (final InterruptedException e)
+    {
+      // Cannot handle here.
+      Thread.currentThread().interrupt();
+    }
+    catch (final Exception e)
+    {
+      // Ignore the exception.
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
+      {
+        StaticUtils.DEBUG_LOG.log(Level.WARNING,
+            "Exception occurred while closing listener:" + e.getMessage(), e);
+      }
+    }
+  }
+
+
+
+  /**
+   * Returns the address that this LDAP listener is listening on.
+   *
+   * @return The address that this LDAP listener is listening on.
+   */
+  public SocketAddress getSocketAddress()
+  {
+    return serverConnection.getLocalAddress();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("LDAPListener(");
+    builder.append(getSocketAddress().toString());
+    builder.append(')');
+    return builder.toString();
+  }
+
+
+
+  ServerConnectionFactory<LDAPClientContext, Integer> getConnectionFactory()
+  {
+    return connectionFactory;
+  }
+
+
+
+  FilterChain getDefaultFilterChain()
+  {
+    return defaultFilterChain;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPMessageHandler.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPMessageHandler.java
new file mode 100644
index 0000000..44dcc29
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPMessageHandler.java
@@ -0,0 +1,159 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+
+
+/**
+ * LDAP message handler interface.
+ *
+ * @param <P>
+ *          A user provided handler parameter.
+ */
+interface LDAPMessageHandler<P>
+{
+  void abandonRequest(P param, int messageID, AbandonRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void addRequest(P param, int messageID, AddRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void addResult(P param, int messageID, Result result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void bindRequest(P param, int messageID, int version,
+      GenericBindRequest request) throws UnexpectedRequestException,
+      IOException;
+
+
+
+  void bindResult(P param, int messageID, BindResult result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void compareRequest(P param, int messageID, CompareRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void compareResult(P param, int messageID, CompareResult result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void deleteRequest(P param, int messageID, DeleteRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void deleteResult(P param, int messageID, Result result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  <R extends ExtendedResult> void extendedRequest(P param, int messageID,
+      ExtendedRequest<R> request) throws UnexpectedRequestException,
+      IOException;
+
+
+
+  void extendedResult(P param, int messageID, ExtendedResult result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void intermediateResponse(P param, int messageID,
+      IntermediateResponse response) throws UnexpectedResponseException,
+      IOException;
+
+
+
+  void modifyDNRequest(P param, int messageID, ModifyDNRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void modifyDNResult(P param, int messageID, Result result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void modifyRequest(P param, int messageID, ModifyRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void modifyResult(P param, int messageID, Result result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void searchRequest(P param, int messageID, SearchRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void searchResult(P param, int messageID, Result result)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void searchResultEntry(P param, int messageID, SearchResultEntry entry)
+      throws UnexpectedResponseException, IOException;
+
+
+
+  void searchResultReference(P param, int messageID,
+      SearchResultReference reference) throws UnexpectedResponseException,
+      IOException;
+
+
+
+  void unbindRequest(P param, int messageID, UnbindRequest request)
+      throws UnexpectedRequestException, IOException;
+
+
+
+  void unrecognizedMessage(P param, int messageID, byte messageTag,
+      ByteString messageBytes) throws UnsupportedMessageException, IOException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPReader.java
new file mode 100644
index 0000000..905ce7e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPReader.java
@@ -0,0 +1,1817 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.*;
+import static com.sun.opends.sdk.messages.Messages.ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE;
+import static com.sun.opends.sdk.messages.Messages.ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF;
+import static com.sun.opends.sdk.messages.Messages.ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE;
+import static org.opends.sdk.asn1.ASN1Constants.UNIVERSAL_BOOLEAN_TYPE;
+import static org.opends.sdk.asn1.ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE;
+
+import java.io.IOException;
+import java.util.logging.Level;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.GenericControl;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Static methods for decoding LDAP messages.
+ */
+final class LDAPReader
+{
+  static SearchResultEntry decodeEntry(final ASN1Reader reader,
+      final DecodeOptions options) throws IOException
+  {
+    Entry entry;
+
+    reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY);
+    try
+    {
+      final String dnString = reader.readOctetStringAsString();
+      final Schema schema = options.getSchemaResolver().resolveSchema(dnString);
+      DN dn;
+      try
+      {
+        dn = DN.valueOf(dnString, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        throw DecodeException.error(e.getMessageObject());
+      }
+
+      entry = options.getEntryFactory().newEntry(dn);
+      reader.readStartSequence();
+      try
+      {
+        while (reader.hasNextElement())
+        {
+          reader.readStartSequence();
+          try
+          {
+            final String ads = reader.readOctetStringAsString();
+            AttributeDescription ad;
+            try
+            {
+              ad = AttributeDescription.valueOf(ads, schema);
+            }
+            catch (final LocalizedIllegalArgumentException e)
+            {
+              throw DecodeException.error(e.getMessageObject());
+            }
+
+            final Attribute attribute = options.getAttributeFactory()
+                .newAttribute(ad);
+
+            reader.readStartSet();
+            try
+            {
+              while (reader.hasNextElement())
+              {
+                attribute.add(reader.readOctetString());
+              }
+              entry.addAttribute(attribute);
+            }
+            finally
+            {
+              reader.readEndSet();
+            }
+          }
+          finally
+          {
+            reader.readEndSequence();
+          }
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return Responses.newSearchResultEntry(entry);
+  }
+
+
+
+  private final DecodeOptions options;
+
+
+
+  LDAPReader(final DecodeOptions options)
+  {
+    this.options = options;
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP message.
+   *
+   * @param <P>
+   *          The type of {@code param}.
+   * @param reader
+   *          The ASN.1 reader.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle a decoded
+   *          message.
+   * @param param
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  <P> void decode(final ASN1Reader reader, final LDAPMessageHandler<P> handler,
+      final P param) throws IOException
+  {
+    reader.readStartSequence();
+    try
+    {
+      final int messageID = (int) reader.readInteger();
+      decodeProtocolOp(reader, messageID, handler, param);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 read as an LDAP abandon
+   * request protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeAbandonRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    final int msgToAbandon = (int) reader.readInteger(OP_TYPE_ABANDON_REQUEST);
+    final AbandonRequest message = Requests.newAbandonRequest(msgToAbandon);
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP ABANDON REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.abandonRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP add request
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeAddRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    Entry entry;
+
+    reader.readStartSequence(OP_TYPE_ADD_REQUEST);
+    try
+    {
+      final String dnString = reader.readOctetStringAsString();
+      final Schema schema = options.getSchemaResolver().resolveSchema(dnString);
+      final DN dn = decodeDN(dnString, schema);
+      entry = options.getEntryFactory().newEntry(dn);
+
+      reader.readStartSequence();
+      try
+      {
+        while (reader.hasNextElement())
+        {
+          reader.readStartSequence();
+          try
+          {
+            final String ads = reader.readOctetStringAsString();
+            final AttributeDescription ad = decodeAttributeDescription(ads,
+                schema);
+            final Attribute attribute = options.getAttributeFactory()
+                .newAttribute(ad);
+
+            reader.readStartSet();
+            try
+            {
+              while (reader.hasNextElement())
+              {
+                attribute.add(reader.readOctetString());
+              }
+              entry.addAttribute(attribute);
+            }
+            finally
+            {
+              reader.readEndSet();
+            }
+          }
+          finally
+          {
+            reader.readEndSequence();
+          }
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    final AddRequest message = Requests.newAddRequest(entry);
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.addRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an add response
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeAddResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    Result message;
+
+    reader.readStartSequence(OP_TYPE_ADD_RESPONSE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newResult(resultCode).setMatchedDN(matchedDN)
+          .setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String
+          .format("DECODE LDAP ADD RESULT(messageID=%d, result=%s)", messageID,
+              message));
+    }
+
+    handler.addResult(p, messageID, message);
+  }
+
+
+
+  private AttributeDescription decodeAttributeDescription(
+      final String attributeDescription, final Schema schema)
+      throws DecodeException
+  {
+    try
+    {
+      return AttributeDescription.valueOf(attributeDescription, schema);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      throw DecodeException.error(e.getMessageObject());
+    }
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 read as an LDAP bind request
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeBindRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    reader.readStartSequence(OP_TYPE_BIND_REQUEST);
+    try
+    {
+      final int protocolVersion = (int) reader.readInteger();
+      final String authName = reader.readOctetStringAsString();
+      final byte authType = reader.peekType();
+      final ByteString authBytes = reader.readOctetString(authType);
+
+      final GenericBindRequest request = Requests.newGenericBindRequest(
+          authName, authType, authBytes);
+
+      decodeControls(reader, request);
+
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+      {
+        StaticUtils.DEBUG_LOG.finer(String.format(
+            "DECODE LDAP BIND REQUEST(messageID=%d, auth=0x%x, request=%s)",
+            messageID, request.getAuthenticationType(), request));
+      }
+
+      handler.bindRequest(p, messageID, protocolVersion, request);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a bind response
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeBindResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    BindResult message;
+
+    reader.readStartSequence(OP_TYPE_BIND_RESPONSE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newBindResult(resultCode).setMatchedDN(matchedDN)
+          .setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_SERVER_SASL_CREDENTIALS))
+      {
+        message.setServerSASLCredentials(reader
+            .readOctetString(TYPE_SERVER_SASL_CREDENTIALS));
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP BIND RESULT(messageID=%d, result=%s)", messageID,
+          message));
+    }
+
+    handler.bindResult(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP compare
+   * request protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeCompareRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    CompareRequest message;
+
+    reader.readStartSequence(OP_TYPE_COMPARE_REQUEST);
+    try
+    {
+      final String dnString = reader.readOctetStringAsString();
+      final Schema schema = options.getSchemaResolver().resolveSchema(dnString);
+      final DN dn = decodeDN(dnString, schema);
+
+      reader.readStartSequence();
+      try
+      {
+        final String ads = reader.readOctetStringAsString();
+        final AttributeDescription ad = decodeAttributeDescription(ads, schema);
+        final ByteString assertionValue = reader.readOctetString();
+        message = Requests.newCompareRequest(dn, ad, assertionValue);
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP COMPARE REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.compareRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a compare response
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeCompareResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    CompareResult message;
+
+    reader.readStartSequence(OP_TYPE_COMPARE_RESPONSE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newCompareResult(resultCode).setMatchedDN(matchedDN)
+          .setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP COMPARE RESULT(messageID=%d, result=%s)", messageID,
+          message));
+    }
+
+    handler.compareResult(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP control.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param request
+   *          The decoded request to decode controls for.
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private void decodeControl(final ASN1Reader reader, final Request request)
+      throws IOException
+  {
+    String oid;
+    boolean isCritical;
+    ByteString value;
+
+    reader.readStartSequence();
+    try
+    {
+      oid = reader.readOctetStringAsString();
+      isCritical = false;
+      value = null;
+      if (reader.hasNextElement()
+          && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE))
+      {
+        isCritical = reader.readBoolean();
+      }
+      if (reader.hasNextElement()
+          && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE))
+      {
+        value = reader.readOctetString();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    final Control c = GenericControl.newControl(oid, isCritical, value);
+    request.addControl(c);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP control.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param response
+   *          The decoded message to decode controls for.
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private void decodeControl(final ASN1Reader reader, final Response response)
+      throws IOException
+  {
+    String oid;
+    boolean isCritical;
+    ByteString value;
+
+    reader.readStartSequence();
+    try
+    {
+      oid = reader.readOctetStringAsString();
+      isCritical = false;
+      value = null;
+      if (reader.hasNextElement()
+          && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE))
+      {
+        isCritical = reader.readBoolean();
+      }
+      if (reader.hasNextElement()
+          && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE))
+      {
+        value = reader.readOctetString();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    final Control c = GenericControl.newControl(oid, isCritical, value);
+    response.addControl(c);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a set of controls.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param request
+   *          The decoded message to decode controls for.
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private void decodeControls(final ASN1Reader reader, final Request request)
+      throws IOException
+  {
+    if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE))
+    {
+      reader.readStartSequence(TYPE_CONTROL_SEQUENCE);
+      try
+      {
+        while (reader.hasNextElement())
+        {
+          decodeControl(reader, request);
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a set of controls.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param response
+   *          The decoded message to decode controls for.
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private void decodeControls(final ASN1Reader reader, final Response response)
+      throws IOException
+  {
+    if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE))
+    {
+      reader.readStartSequence(TYPE_CONTROL_SEQUENCE);
+      try
+      {
+        while (reader.hasNextElement())
+        {
+          decodeControl(reader, response);
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP delete
+   * request protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeDeleteRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    final String dnString = reader
+        .readOctetStringAsString(OP_TYPE_DELETE_REQUEST);
+    final Schema schema = options.getSchemaResolver().resolveSchema(dnString);
+    final DN dn = decodeDN(dnString, schema);
+    final DeleteRequest message = Requests.newDeleteRequest(dn);
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP DELETE REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.deleteRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a delete response
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeDeleteResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    Result message;
+
+    reader.readStartSequence(OP_TYPE_DELETE_RESPONSE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newResult(resultCode).setMatchedDN(matchedDN)
+          .setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP DELETE RESULT(messageID=%d, result=%s)", messageID,
+          message));
+    }
+
+    handler.deleteResult(p, messageID, message);
+  }
+
+
+
+  private DN decodeDN(final String dn, final Schema schema)
+      throws DecodeException
+  {
+    try
+    {
+      return DN.valueOf(dn, schema);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      throw DecodeException.error(e.getMessageObject());
+    }
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP extended
+   * request protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeExtendedRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    String oid;
+    ByteString value;
+
+    reader.readStartSequence(OP_TYPE_EXTENDED_REQUEST);
+    try
+    {
+      oid = reader.readOctetStringAsString(TYPE_EXTENDED_REQUEST_OID);
+      value = null;
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_EXTENDED_REQUEST_VALUE))
+      {
+        value = reader.readOctetString(TYPE_EXTENDED_REQUEST_VALUE);
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    final GenericExtendedRequest message = Requests.newGenericExtendedRequest(
+        oid, value);
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP EXTENDED REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.extendedRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a extended response
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeExtendedResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+
+    GenericExtendedResult message;
+
+    reader.readStartSequence(OP_TYPE_EXTENDED_RESPONSE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newGenericExtendedResult(resultCode).setMatchedDN(
+          matchedDN).setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_EXTENDED_RESPONSE_OID))
+      {
+        message.setOID(reader
+            .readOctetStringAsString(TYPE_EXTENDED_RESPONSE_OID));
+      }
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_EXTENDED_RESPONSE_VALUE))
+      {
+        message.setValue(reader.readOctetString(TYPE_EXTENDED_RESPONSE_VALUE));
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP EXTENDED RESULT(messageID=%d, result=%s)", messageID,
+          message));
+    }
+
+    handler.extendedResult(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP intermediate
+   * response protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeIntermediateResponse(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    GenericIntermediateResponse message;
+
+    reader.readStartSequence(OP_TYPE_INTERMEDIATE_RESPONSE);
+    try
+    {
+      message = Responses.newGenericIntermediateResponse();
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_OID))
+      {
+        message.setOID(reader
+            .readOctetStringAsString(TYPE_INTERMEDIATE_RESPONSE_OID));
+      }
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_VALUE))
+      {
+        message.setValue(reader
+            .readOctetString(TYPE_INTERMEDIATE_RESPONSE_VALUE));
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP INTERMEDIATE RESPONSE(messageID=%d, response=%s)",
+          messageID, message));
+    }
+
+    handler.intermediateResponse(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a modify DN request
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeModifyDNRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    ModifyDNRequest message;
+
+    reader.readStartSequence(OP_TYPE_MODIFY_DN_REQUEST);
+    try
+    {
+      final String dnString = reader.readOctetStringAsString();
+      final Schema schema = options.getSchemaResolver().resolveSchema(dnString);
+      final DN dn = decodeDN(dnString, schema);
+
+      final String newRDNString = reader.readOctetStringAsString();
+      final RDN newRDN = decodeRDN(newRDNString, schema);
+
+      message = Requests.newModifyDNRequest(dn, newRDN);
+
+      message.setDeleteOldRDN(reader.readBoolean());
+
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_MODIFY_DN_NEW_SUPERIOR))
+      {
+        final String newSuperiorString = reader
+            .readOctetStringAsString(TYPE_MODIFY_DN_NEW_SUPERIOR);
+        final DN newSuperior = decodeDN(newSuperiorString, schema);
+        message.setNewSuperior(newSuperior);
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP MODIFY DN REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.modifyDNRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a modify DN response
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeModifyDNResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    Result message;
+
+    reader.readStartSequence(OP_TYPE_MODIFY_DN_RESPONSE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newResult(resultCode).setMatchedDN(matchedDN)
+          .setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP MODIFY DN RESULT(messageID=%d, result=%s)", messageID,
+          message));
+    }
+
+    handler.modifyDNResult(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP modify
+   * request protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeModifyRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    ModifyRequest message;
+
+    reader.readStartSequence(OP_TYPE_MODIFY_REQUEST);
+    try
+    {
+      final String dnString = reader.readOctetStringAsString();
+      final Schema schema = options.getSchemaResolver().resolveSchema(dnString);
+      final DN dn = decodeDN(dnString, schema);
+      message = Requests.newModifyRequest(dn);
+
+      reader.readStartSequence();
+      try
+      {
+        while (reader.hasNextElement())
+        {
+          reader.readStartSequence();
+          try
+          {
+            final int typeIntValue = reader.readEnumerated();
+            final ModificationType type = ModificationType
+                .valueOf(typeIntValue);
+            if (type == null)
+            {
+              throw DecodeException
+                  .error(ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE
+                      .get(typeIntValue));
+            }
+            reader.readStartSequence();
+            try
+            {
+              final String ads = reader.readOctetStringAsString();
+              final AttributeDescription ad = decodeAttributeDescription(ads,
+                  schema);
+              final Attribute attribute = options.getAttributeFactory()
+                  .newAttribute(ad);
+
+              reader.readStartSet();
+              try
+              {
+                while (reader.hasNextElement())
+                {
+                  attribute.add(reader.readOctetString());
+                }
+                message.addModification(new Modification(type, attribute));
+              }
+              finally
+              {
+                reader.readEndSet();
+              }
+            }
+            finally
+            {
+              reader.readEndSequence();
+            }
+          }
+          finally
+          {
+            reader.readEndSequence();
+          }
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP MODIFY REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.modifyRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a modify response
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeModifyResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    Result message;
+
+    reader.readStartSequence(OP_TYPE_MODIFY_RESPONSE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newResult(resultCode).setMatchedDN(matchedDN)
+          .setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP MODIFY RESULT(messageID=%d, result=%s)", messageID,
+          message));
+    }
+
+    handler.modifyResult(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeProtocolOp(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    final byte type = reader.peekType();
+
+    switch (type)
+    {
+    case OP_TYPE_UNBIND_REQUEST: // 0x42
+      decodeUnbindRequest(reader, messageID, handler, p);
+      break;
+    case 0x43: // 0x43
+    case 0x44: // 0x44
+    case 0x45: // 0x45
+    case 0x46: // 0x46
+    case 0x47: // 0x47
+    case 0x48: // 0x48
+    case 0x49: // 0x49
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    case OP_TYPE_DELETE_REQUEST: // 0x4A
+      decodeDeleteRequest(reader, messageID, handler, p);
+      break;
+    case 0x4B: // 0x4B
+    case 0x4C: // 0x4C
+    case 0x4D: // 0x4D
+    case 0x4E: // 0x4E
+    case 0x4F: // 0x4F
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    case OP_TYPE_ABANDON_REQUEST: // 0x50
+      decodeAbandonRequest(reader, messageID, handler, p);
+      break;
+    case 0x51: // 0x51
+    case 0x52: // 0x52
+    case 0x53: // 0x53
+    case 0x54: // 0x54
+    case 0x55: // 0x55
+    case 0x56: // 0x56
+    case 0x57: // 0x57
+    case 0x58: // 0x58
+    case 0x59: // 0x59
+    case 0x5A: // 0x5A
+    case 0x5B: // 0x5B
+    case 0x5C: // 0x5C
+    case 0x5D: // 0x5D
+    case 0x5E: // 0x5E
+    case 0x5F: // 0x5F
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    case OP_TYPE_BIND_REQUEST: // 0x60
+      decodeBindRequest(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_BIND_RESPONSE: // 0x61
+      decodeBindResult(reader, messageID, handler, p);
+      break;
+    case 0x62: // 0x62
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    case OP_TYPE_SEARCH_REQUEST: // 0x63
+      decodeSearchRequest(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_SEARCH_RESULT_ENTRY: // 0x64
+      decodeSearchResultEntry(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_SEARCH_RESULT_DONE: // 0x65
+      decodeSearchResult(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_MODIFY_REQUEST: // 0x66
+      decodeModifyRequest(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_MODIFY_RESPONSE: // 0x67
+      decodeModifyResult(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_ADD_REQUEST: // 0x68
+      decodeAddRequest(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_ADD_RESPONSE: // 0x69
+      decodeAddResult(reader, messageID, handler, p);
+      break;
+    case 0x6A: // 0x6A
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    case OP_TYPE_DELETE_RESPONSE: // 0x6B
+      decodeDeleteResult(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_MODIFY_DN_REQUEST: // 0x6C
+      decodeModifyDNRequest(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_MODIFY_DN_RESPONSE: // 0x6D
+      decodeModifyDNResult(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_COMPARE_REQUEST: // 0x6E
+      decodeCompareRequest(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_COMPARE_RESPONSE: // 0x6F
+      decodeCompareResult(reader, messageID, handler, p);
+      break;
+    case 0x70: // 0x70
+    case 0x71: // 0x71
+    case 0x72: // 0x72
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    case OP_TYPE_SEARCH_RESULT_REFERENCE: // 0x73
+      decodeSearchResultReference(reader, messageID, handler, p);
+      break;
+    case 0x74: // 0x74
+    case 0x75: // 0x75
+    case 0x76: // 0x76
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    case OP_TYPE_EXTENDED_REQUEST: // 0x77
+      decodeExtendedRequest(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_EXTENDED_RESPONSE: // 0x78
+      decodeExtendedResult(reader, messageID, handler, p);
+      break;
+    case OP_TYPE_INTERMEDIATE_RESPONSE: // 0x79
+      decodeIntermediateResponse(reader, messageID, handler, p);
+      break;
+    default:
+      handler.unrecognizedMessage(p, messageID, type, reader
+          .readOctetString(type));
+      break;
+    }
+  }
+
+
+
+  private RDN decodeRDN(final String rdn, final Schema schema)
+      throws DecodeException
+  {
+    try
+    {
+      return RDN.valueOf(rdn, schema);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      throw DecodeException.error(e.getMessageObject());
+    }
+  }
+
+
+
+  private void decodeResponseReferrals(final ASN1Reader reader,
+      final Result message) throws IOException
+  {
+    if (reader.hasNextElement()
+        && (reader.peekType() == TYPE_REFERRAL_SEQUENCE))
+    {
+      reader.readStartSequence(TYPE_REFERRAL_SEQUENCE);
+      try
+      {
+        // Should have at least 1.
+        do
+        {
+          message.addReferralURI((reader.readOctetStringAsString()));
+        }
+        while (reader.hasNextElement());
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP search
+   * request protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeSearchRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    SearchRequest message;
+
+    reader.readStartSequence(OP_TYPE_SEARCH_REQUEST);
+    try
+    {
+      final String baseDNString = reader.readOctetStringAsString();
+      final Schema schema = options.getSchemaResolver().resolveSchema(
+          baseDNString);
+      final DN baseDN = decodeDN(baseDNString, schema);
+
+      final int scopeIntValue = reader.readEnumerated();
+      final SearchScope scope = SearchScope.valueOf(scopeIntValue);
+      if (scope == null)
+      {
+        throw DecodeException
+            .error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE
+                .get(scopeIntValue));
+      }
+
+      final int dereferencePolicyIntValue = reader.readEnumerated();
+      final DereferenceAliasesPolicy dereferencePolicy = DereferenceAliasesPolicy
+          .valueOf(dereferencePolicyIntValue);
+      if (dereferencePolicy == null)
+      {
+        throw DecodeException
+            .error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF
+                .get(dereferencePolicyIntValue));
+      }
+
+      final int sizeLimit = (int) reader.readInteger();
+      final int timeLimit = (int) reader.readInteger();
+      final boolean typesOnly = reader.readBoolean();
+      final Filter filter = LDAPUtils.decodeFilter(reader);
+
+      message = Requests.newSearchRequest(baseDN, scope, filter);
+      message.setDereferenceAliasesPolicy(dereferencePolicy);
+      try
+      {
+        message.setTimeLimit(timeLimit);
+        message.setSizeLimit(sizeLimit);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        throw DecodeException.error(e.getMessageObject());
+      }
+      message.setTypesOnly(typesOnly);
+
+      reader.readStartSequence();
+      try
+      {
+        while (reader.hasNextElement())
+        {
+          message.addAttribute(reader.readOctetStringAsString());
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP SEARCH REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.searchRequest(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a search result done
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeSearchResult(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+
+    Result message;
+
+    reader.readStartSequence(OP_TYPE_SEARCH_RESULT_DONE);
+    try
+    {
+      final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
+      final String matchedDN = reader.readOctetStringAsString();
+      final String diagnosticMessage = reader.readOctetStringAsString();
+      message = Responses.newResult(resultCode).setMatchedDN(matchedDN)
+          .setDiagnosticMessage(diagnosticMessage);
+      decodeResponseReferrals(reader, message);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP SEARCH RESULT(messageID=%d, result=%s)", messageID,
+          message));
+    }
+
+    handler.searchResult(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as an LDAP search
+   * result entry protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeSearchResultEntry(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    Entry entry;
+
+    reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY);
+    try
+    {
+      final String dnString = reader.readOctetStringAsString();
+      final Schema schema = options.getSchemaResolver().resolveSchema(dnString);
+      final DN dn = decodeDN(dnString, schema);
+      entry = options.getEntryFactory().newEntry(dn);
+
+      reader.readStartSequence();
+      try
+      {
+        while (reader.hasNextElement())
+        {
+          reader.readStartSequence();
+          try
+          {
+            final String ads = reader.readOctetStringAsString();
+            final AttributeDescription ad = decodeAttributeDescription(ads,
+                schema);
+            final Attribute attribute = options.getAttributeFactory()
+                .newAttribute(ad);
+
+            reader.readStartSet();
+            try
+            {
+              while (reader.hasNextElement())
+              {
+                attribute.add(reader.readOctetString());
+              }
+              entry.addAttribute(attribute);
+            }
+            finally
+            {
+              reader.readEndSet();
+            }
+          }
+          finally
+          {
+            reader.readEndSequence();
+          }
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    final SearchResultEntry message = Responses.newSearchResultEntry(entry);
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID,
+          message));
+    }
+
+    handler.searchResultEntry(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 reader as a search result
+   * reference protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeSearchResultReference(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    SearchResultReference message;
+
+    reader.readStartSequence(OP_TYPE_SEARCH_RESULT_REFERENCE);
+    try
+    {
+      message = Responses.newSearchResultReference(reader
+          .readOctetStringAsString());
+      while (reader.hasNextElement())
+      {
+        message.addURI(reader.readOctetStringAsString());
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)",
+          messageID, message));
+    }
+
+    handler.searchResultReference(p, messageID, message);
+  }
+
+
+
+  /**
+   * Decodes the elements from the provided ASN.1 read as an LDAP unbind request
+   * protocol op.
+   *
+   * @param reader
+   *          The ASN.1 reader.
+   * @param messageID
+   *          The decoded message ID for this message.
+   * @param handler
+   *          The <code>LDAPMessageHandler</code> that will handle this decoded
+   *          message.
+   * @param p
+   *          The parameter to pass into the <code>LDAPMessageHandler</code>
+   * @throws IOException
+   *           If an error occurred while reading bytes to decode.
+   */
+  private <P> void decodeUnbindRequest(final ASN1Reader reader,
+      final int messageID, final LDAPMessageHandler<P> handler, final P p)
+      throws IOException
+  {
+    UnbindRequest message;
+    reader.readNull(OP_TYPE_UNBIND_REQUEST);
+    message = Requests.newUnbindRequest();
+
+    decodeControls(reader, message);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "DECODE LDAP UNBIND REQUEST(messageID=%d, request=%s)", messageID,
+          message));
+    }
+
+    handler.unbindRequest(p, messageID, message);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPSearchFutureResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPSearchFutureResultImpl.java
new file mode 100644
index 0000000..a7c71ea
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPSearchFutureResultImpl.java
@@ -0,0 +1,141 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.responses.SearchResultReference;
+
+
+
+/**
+ * Search result future implementation.
+ */
+final class LDAPSearchFutureResultImpl extends
+    AbstractLDAPFutureResultImpl<Result> implements SearchResultHandler
+{
+
+  private SearchResultHandler searchResultHandler;
+
+  private final SearchRequest request;
+
+
+
+  LDAPSearchFutureResultImpl(final int requestID, final SearchRequest request,
+      final SearchResultHandler resultHandler,
+      final IntermediateResponseHandler intermediateResponseHandler,
+      final AsynchronousConnection connection)
+  {
+    super(requestID, resultHandler, intermediateResponseHandler, connection);
+    this.request = request;
+    this.searchResultHandler = resultHandler;
+  }
+
+
+
+  public boolean handleEntry(final SearchResultEntry entry)
+  {
+    // FIXME: there's a potential race condition here - the future could
+    // get cancelled between the isDone() call and the handler
+    // invocation. We'd need to add support for intermediate handlers in
+    // the synchronizer.
+    if (!isDone())
+    {
+      updateTimestamp();
+      if (searchResultHandler != null)
+      {
+        if (!searchResultHandler.handleEntry(entry))
+        {
+          searchResultHandler = null;
+        }
+      }
+    }
+    return true;
+  }
+
+
+
+  public boolean handleReference(final SearchResultReference reference)
+  {
+    // FIXME: there's a potential race condition here - the future could
+    // get cancelled between the isDone() call and the handler
+    // invocation. We'd need to add support for intermediate handlers in
+    // the synchronizer.
+    if (!isDone())
+    {
+      updateTimestamp();
+      if (searchResultHandler != null)
+      {
+        if (!searchResultHandler.handleReference(reference))
+        {
+          searchResultHandler = null;
+        }
+      }
+    }
+    return true;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder sb = new StringBuilder();
+    sb.append("LDAPSearchFutureResultImpl(");
+    sb.append("request = ");
+    sb.append(request);
+    super.toString(sb);
+    sb.append(")");
+    return sb.toString();
+  }
+
+
+
+  SearchRequest getRequest()
+  {
+    return request;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  Result newErrorResult(final ResultCode resultCode,
+      final String diagnosticMessage, final Throwable cause)
+  {
+    return Responses.newResult(resultCode).setDiagnosticMessage(
+        diagnosticMessage).setCause(cause);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPServerFilter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPServerFilter.java
new file mode 100644
index 0000000..a4b9747
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPServerFilter.java
@@ -0,0 +1,1163 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.OID_NOTICE_OF_DISCONNECTION;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.Connection;
+import org.glassfish.grizzly.Grizzly;
+import org.glassfish.grizzly.attributes.Attribute;
+import org.glassfish.grizzly.filterchain.*;
+import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
+import org.glassfish.grizzly.ssl.SSLFilter;
+import org.glassfish.grizzly.ssl.SSLUtils;
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Grizzly filter implementation for decoding LDAP requests and handling server
+ * side logic for SSL and SASL operations over LDAP.
+ */
+final class LDAPServerFilter extends BaseFilter
+{
+  private abstract class AbstractHandler<R extends Result> implements
+      IntermediateResponseHandler, ResultHandler<R>
+  {
+    protected final int messageID;
+    protected final Connection<?> connection;
+
+
+
+    protected AbstractHandler(final int messageID,
+        final Connection<?> connection)
+    {
+      this.messageID = messageID;
+      this.connection = connection;
+    }
+
+
+
+    @Override
+    public final boolean handleIntermediateResponse(
+        final IntermediateResponse response)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.intermediateResponse(asn1Writer, messageID, response);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+        return false;
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+      return true;
+    }
+  }
+
+
+
+  private final class AddHandler extends AbstractHandler<Result>
+  {
+    private AddHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      handleResult(error.getResult());
+    }
+
+
+
+    @Override
+    public void handleResult(final Result result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.addResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  private final class BindHandler extends AbstractHandler<BindResult>
+  {
+    private BindHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      final Result result = error.getResult();
+      if (result instanceof BindResult)
+      {
+        handleResult((BindResult) result);
+      }
+      else
+      {
+        final BindResult newResult = Responses.newBindResult(result
+            .getResultCode());
+        newResult.setDiagnosticMessage(result.getDiagnosticMessage());
+        newResult.setMatchedDN(result.getMatchedDN());
+        newResult.setCause(result.getCause());
+        for (final Control control : result.getControls())
+        {
+          newResult.addControl(control);
+        }
+        handleResult(newResult);
+      }
+    }
+
+
+
+    @Override
+    public void handleResult(final BindResult result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.bindResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  private final class ClientContextImpl implements LDAPClientContext
+  {
+    private final Connection<?> connection;
+
+    private volatile boolean isClosed = false;
+
+    private ServerConnection<Integer> serverConnection = null;
+
+
+
+    private ClientContextImpl(final Connection<?> connection)
+    {
+      this.connection = connection;
+    }
+
+
+
+    @Override
+    public void disconnect()
+    {
+      LDAPServerFilter.notifyConnectionDisconnected(connection, null, null);
+    }
+
+
+
+    @Override
+    public void disconnect(final ResultCode resultCode, final String message)
+    {
+      Validator.ensureNotNull(resultCode);
+
+      final GenericExtendedResult notification = Responses
+          .newGenericExtendedResult(resultCode)
+          .setOID(OID_NOTICE_OF_DISCONNECTION).setDiagnosticMessage(message);
+      sendUnsolicitedNotification(notification);
+      LDAPServerFilter.notifyConnectionDisconnected(connection, resultCode,
+          message);
+    }
+
+
+
+    @Override
+    public InetSocketAddress getLocalAddress()
+    {
+      return (InetSocketAddress) connection.getLocalAddress();
+    }
+
+
+
+    @Override
+    public InetSocketAddress getPeerAddress()
+    {
+      return (InetSocketAddress) connection.getPeerAddress();
+    }
+
+
+
+    @Override
+    public int getSecurityStrengthFactor()
+    {
+      int ssf = 0;
+      final SSLEngine sslEngine = SSLUtils.getSSLEngine(connection);
+      if (sslEngine != null)
+      {
+        final String cipherString = sslEngine.getSession().getCipherSuite();
+        for (final Map.Entry<String, Integer> mapEntry : CIPHER_KEY_SIZES
+            .entrySet())
+        {
+          if (cipherString.indexOf(mapEntry.getKey()) >= 0)
+          {
+            ssf = mapEntry.getValue();
+            break;
+          }
+        }
+      }
+
+      return ssf;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isClosed()
+    {
+      return isClosed;
+    }
+
+
+
+    @Override
+    public void sendUnsolicitedNotification(final ExtendedResult notification)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.extendedResult(asn1Writer, 0, notification);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        LDAPServerFilter.notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+
+
+
+    @Override
+    public void startSASL(final ConnectionSecurityLayer bindContext)
+    {
+      installFilter(connection, new SASLFilter(bindContext, connection
+          .getTransport().getMemoryManager()));
+    }
+
+
+
+    @Override
+    public void startTLS(final SSLContext sslContext, final String[] protocols,
+        final String[] suites, final boolean wantClientAuth,
+        final boolean needClientAuth)
+    {
+      Validator.ensureNotNull(sslContext);
+      SSLEngineConfigurator sslEngineConfigurator;
+
+      sslEngineConfigurator = new SSLEngineConfigurator(sslContext, false,
+          false, false);
+      sslEngineConfigurator.setEnabledCipherSuites(suites);
+      sslEngineConfigurator.setEnabledProtocols(protocols);
+      sslEngineConfigurator.setWantClientAuth(wantClientAuth);
+      sslEngineConfigurator.setNeedClientAuth(needClientAuth);
+      installFilter(connection, new SSLFilter(sslEngineConfigurator, null));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+      StringBuilder builder = new StringBuilder();
+      builder.append("LDAPClientContext(");
+      builder.append(getLocalAddress());
+      builder.append(',');
+      builder.append(getPeerAddress());
+      builder.append(')');
+      return builder.toString();
+    }
+
+
+
+    private void close()
+    {
+      isClosed = true;
+    }
+
+
+
+    private ServerConnection<Integer> getServerConnection()
+    {
+      return serverConnection;
+    }
+
+
+
+    private void setServerConnection(
+        final ServerConnection<Integer> serverConnection)
+    {
+      this.serverConnection = serverConnection;
+    }
+
+  }
+
+
+
+  private final class CompareHandler extends AbstractHandler<CompareResult>
+  {
+    private CompareHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      final Result result = error.getResult();
+      if (result instanceof CompareResult)
+      {
+        handleResult((CompareResult) result);
+      }
+      else
+      {
+        final CompareResult newResult = Responses.newCompareResult(result
+            .getResultCode());
+        newResult.setDiagnosticMessage(result.getDiagnosticMessage());
+        newResult.setMatchedDN(result.getMatchedDN());
+        newResult.setCause(result.getCause());
+        for (final Control control : result.getControls())
+        {
+          newResult.addControl(control);
+        }
+        handleResult(newResult);
+      }
+    }
+
+
+
+    @Override
+    public void handleResult(final CompareResult result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.compareResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  private final class DeleteHandler extends AbstractHandler<Result>
+  {
+    private DeleteHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      handleResult(error.getResult());
+    }
+
+
+
+    @Override
+    public void handleResult(final Result result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.deleteResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  private final class ExtendedHandler<R extends ExtendedResult> extends
+      AbstractHandler<R>
+  {
+    private ExtendedHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      final Result result = error.getResult();
+      if (result instanceof ExtendedResult)
+      {
+        handleResult((ExtendedResult) result);
+      }
+      else
+      {
+        final ExtendedResult newResult = Responses
+            .newGenericExtendedResult(result.getResultCode());
+        newResult.setDiagnosticMessage(result.getDiagnosticMessage());
+        newResult.setMatchedDN(result.getMatchedDN());
+        newResult.setCause(result.getCause());
+        for (final Control control : result.getControls())
+        {
+          newResult.addControl(control);
+        }
+        handleResult(newResult);
+      }
+    }
+
+
+
+    @Override
+    public void handleResult(final ExtendedResult result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.extendedResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  private final class ModifyDNHandler extends AbstractHandler<Result>
+  {
+    private ModifyDNHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      handleResult(error.getResult());
+    }
+
+
+
+    @Override
+    public void handleResult(final Result result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.modifyDNResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  private final class ModifyHandler extends AbstractHandler<Result>
+  {
+    private ModifyHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      handleResult(error.getResult());
+    }
+
+
+
+    @Override
+    public void handleResult(final Result result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.modifyResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  private final class SearchHandler extends AbstractHandler<Result> implements
+      SearchResultHandler
+  {
+    private SearchHandler(final int messageID, final Connection<?> connection)
+    {
+      super(messageID, connection);
+    }
+
+
+
+    @Override
+    public boolean handleEntry(final SearchResultEntry entry)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.searchResultEntry(asn1Writer, messageID, entry);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+        return false;
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+      return true;
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      handleResult(error.getResult());
+    }
+
+
+
+    @Override
+    public boolean handleReference(final SearchResultReference reference)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.searchResultReference(asn1Writer, messageID, reference);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+        return false;
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+      return true;
+    }
+
+
+
+    @Override
+    public void handleResult(final Result result)
+    {
+      final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter();
+      try
+      {
+        LDAP_WRITER.searchResult(asn1Writer, messageID, result);
+        connection.write(asn1Writer.getBuffer(), null);
+      }
+      catch (final IOException ioe)
+      {
+        notifyConnectionException(connection, ioe);
+      }
+      finally
+      {
+        asn1Writer.recycle();
+      }
+    }
+  }
+
+
+
+  // Map of cipher phrases to effective key size (bits). Taken from the
+  // following RFCs: 5289, 4346, 3268,4132 and 4162.
+  private static final Map<String, Integer> CIPHER_KEY_SIZES;
+
+  static
+  {
+    CIPHER_KEY_SIZES = new LinkedHashMap<String, Integer>();
+    CIPHER_KEY_SIZES.put("_WITH_AES_256_CBC_", 256);
+    CIPHER_KEY_SIZES.put("_WITH_CAMELLIA_256_CBC_", 256);
+    CIPHER_KEY_SIZES.put("_WITH_AES_256_GCM_", 256);
+    CIPHER_KEY_SIZES.put("_WITH_3DES_EDE_CBC_", 112);
+    CIPHER_KEY_SIZES.put("_WITH_AES_128_GCM_", 128);
+    CIPHER_KEY_SIZES.put("_WITH_SEED_CBC_", 128);
+    CIPHER_KEY_SIZES.put("_WITH_CAMELLIA_128_CBC_", 128);
+    CIPHER_KEY_SIZES.put("_WITH_AES_128_CBC_", 128);
+    CIPHER_KEY_SIZES.put("_WITH_IDEA_CBC_", 128);
+    CIPHER_KEY_SIZES.put("_WITH_DES_CBC_", 56);
+    CIPHER_KEY_SIZES.put("_WITH_RC2_CBC_40_", 40);
+    CIPHER_KEY_SIZES.put("_WITH_RC4_40_", 40);
+    CIPHER_KEY_SIZES.put("_WITH_DES40_CBC_", 40);
+    CIPHER_KEY_SIZES.put("_WITH_NULL_", 0);
+  }
+
+  private static final LDAPWriter LDAP_WRITER = new LDAPWriter();
+
+  private static final Attribute<ClientContextImpl> LDAP_CONNECTION_ATTR =
+    Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPServerConnection");
+
+  private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR =
+    Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader");
+
+
+
+  private static void notifyConnectionClosed(final Connection<?> connection,
+      final int messageID, final UnbindRequest unbindRequest)
+  {
+    final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR
+        .remove(connection);
+    if (clientContext != null)
+    {
+      // Close the connection context.
+      clientContext.close();
+
+      // Notify the server connection: it may be null if disconnect is invoked
+      // during accept.
+      final ServerConnection<Integer> serverConnection = clientContext
+          .getServerConnection();
+      if (serverConnection != null)
+      {
+        serverConnection.handleConnectionClosed(messageID, unbindRequest);
+      }
+
+      // If this close was a result of an unbind request then the connection
+      // won't actually be closed yet. To avoid TIME_WAIT TCP state, let the
+      // client disconnect.
+      if (unbindRequest != null)
+      {
+        return;
+      }
+
+      // Close the connection.
+      try
+      {
+        connection.close();
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e);
+      }
+    }
+  }
+
+
+
+  private static void notifyConnectionDisconnected(
+      final Connection<?> connection, final ResultCode resultCode,
+      final String message)
+  {
+    final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR
+        .remove(connection);
+    if (clientContext != null)
+    {
+      // Close the connection context.
+      clientContext.close();
+
+      // Notify the server connection: it may be null if disconnect is invoked
+      // during accept.
+      final ServerConnection<Integer> serverConnection = clientContext
+          .getServerConnection();
+      if (serverConnection != null)
+      {
+        serverConnection.handleConnectionDisconnected(resultCode, message);
+      }
+
+      // Close the connection.
+      try
+      {
+        connection.close();
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e);
+      }
+    }
+  }
+
+
+
+  private static void notifyConnectionException(final Connection<?> connection,
+      final Throwable error)
+  {
+    final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR
+        .remove(connection);
+    if (clientContext != null)
+    {
+      // Close the connection context.
+      clientContext.close();
+
+      // Notify the server connection: it may be null if disconnect is invoked
+      // during accept.
+      final ServerConnection<Integer> serverConnection = clientContext
+          .getServerConnection();
+      if (serverConnection != null)
+      {
+        serverConnection.handleConnectionError(error);
+      }
+
+      // Close the connection.
+      try
+      {
+        connection.close();
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e);
+      }
+    }
+  }
+
+
+
+  private final AbstractLDAPMessageHandler<FilterChainContext> serverRequestHandler =
+    new AbstractLDAPMessageHandler<FilterChainContext>()
+  {
+    @Override
+    public void abandonRequest(final FilterChainContext ctx,
+        final int messageID, final AbandonRequest request)
+        throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        conn.handleAbandon(messageID, request);
+      }
+    }
+
+
+
+    @Override
+    public void addRequest(final FilterChainContext ctx, final int messageID,
+        final AddRequest request) throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final AddHandler handler = new AddHandler(messageID,
+            ctx.getConnection());
+        conn.handleAdd(messageID, request, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public void bindRequest(final FilterChainContext ctx, final int messageID,
+        final int version, final GenericBindRequest bindContext)
+        throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final BindHandler handler = new BindHandler(messageID,
+            ctx.getConnection());
+        conn.handleBind(messageID, version, bindContext, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public void compareRequest(final FilterChainContext ctx,
+        final int messageID, final CompareRequest request)
+        throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final CompareHandler handler = new CompareHandler(messageID,
+            ctx.getConnection());
+        conn.handleCompare(messageID, request, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public void deleteRequest(final FilterChainContext ctx,
+        final int messageID, final DeleteRequest request)
+        throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final DeleteHandler handler = new DeleteHandler(messageID,
+            ctx.getConnection());
+        conn.handleDelete(messageID, request, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public <R extends ExtendedResult> void extendedRequest(
+        final FilterChainContext ctx, final int messageID,
+        final ExtendedRequest<R> request) throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final ExtendedHandler<R> handler = new ExtendedHandler<R>(messageID,
+            ctx.getConnection());
+        conn.handleExtendedRequest(messageID, request, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public void modifyDNRequest(final FilterChainContext ctx,
+        final int messageID, final ModifyDNRequest request)
+        throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final ModifyDNHandler handler = new ModifyDNHandler(messageID,
+            ctx.getConnection());
+        conn.handleModifyDN(messageID, request, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public void modifyRequest(final FilterChainContext ctx,
+        final int messageID, final ModifyRequest request)
+        throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final ModifyHandler handler = new ModifyHandler(messageID,
+            ctx.getConnection());
+        conn.handleModify(messageID, request, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public void searchRequest(final FilterChainContext ctx,
+        final int messageID, final SearchRequest request)
+        throws UnexpectedRequestException
+    {
+      final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx
+          .getConnection());
+      if (clientContext != null)
+      {
+        final ServerConnection<Integer> conn = clientContext
+            .getServerConnection();
+        final SearchHandler handler = new SearchHandler(messageID,
+            ctx.getConnection());
+        conn.handleSearch(messageID, request, handler, handler);
+      }
+    }
+
+
+
+    @Override
+    public void unbindRequest(final FilterChainContext ctx,
+        final int messageID, final UnbindRequest request)
+    {
+      notifyConnectionClosed(ctx.getConnection(), messageID, request);
+    }
+
+
+
+    @Override
+    public void unrecognizedMessage(final FilterChainContext ctx,
+        final int messageID, final byte messageTag,
+        final ByteString messageBytes)
+    {
+      notifyConnectionException(ctx.getConnection(),
+          new UnsupportedMessageException(messageID, messageTag, messageBytes));
+    }
+  };
+
+  private final int maxASN1ElementSize;
+
+  private final LDAPReader ldapReader;
+
+  private final LDAPListenerImpl listener;
+
+
+
+  LDAPServerFilter(final LDAPListenerImpl listener,
+      final LDAPReader ldapReader, final int maxASN1ElementSize)
+  {
+    this.listener = listener;
+    this.ldapReader = ldapReader;
+    this.maxASN1ElementSize = maxASN1ElementSize;
+  }
+
+
+
+  @Override
+  public void exceptionOccurred(final FilterChainContext ctx,
+      final Throwable error)
+  {
+    notifyConnectionException(ctx.getConnection(), error);
+  }
+
+
+
+  @Override
+  public NextAction handleAccept(final FilterChainContext ctx)
+      throws IOException
+  {
+    final Connection<?> connection = ctx.getConnection();
+    connection.configureBlocking(true);
+    try
+    {
+      final ClientContextImpl clientContext = new ClientContextImpl(connection);
+      final ServerConnection<Integer> serverConn = listener
+          .getConnectionFactory().handleAccept(clientContext);
+      clientContext.setServerConnection(serverConn);
+      LDAP_CONNECTION_ATTR.set(connection, clientContext);
+    }
+    catch (final ErrorResultException e)
+    {
+      connection.close();
+    }
+
+    return ctx.getStopAction();
+  }
+
+
+
+  @Override
+  public NextAction handleClose(final FilterChainContext ctx)
+      throws IOException
+  {
+    notifyConnectionClosed(ctx.getConnection(), -1, null);
+    return ctx.getStopAction();
+  }
+
+
+
+  @Override
+  public NextAction handleRead(final FilterChainContext ctx) throws IOException
+  {
+    final Buffer buffer = (Buffer) ctx.getMessage();
+    ASN1BufferReader asn1Reader = LDAP_ASN1_READER_ATTR
+        .get(ctx.getConnection());
+    if (asn1Reader == null)
+    {
+      asn1Reader = new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection()
+          .getTransport().getMemoryManager());
+      LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader);
+    }
+    asn1Reader.appendBytesRead(buffer);
+
+    try
+    {
+      while (asn1Reader.elementAvailable())
+      {
+        ldapReader.decode(asn1Reader, serverRequestHandler, ctx);
+      }
+    }
+    finally
+    {
+      asn1Reader.disposeBytesRead();
+    }
+
+    return ctx.getStopAction();
+  }
+
+
+
+  private synchronized void installFilter(final Connection<?> connection,
+      final org.glassfish.grizzly.filterchain.Filter filter)
+  {
+    FilterChain filterChain = (FilterChain) connection.getProcessor();
+    if (filter instanceof SSLFilter)
+    {
+      if (filterChain.get(filterChain.size() - 1) instanceof SSLFilter
+          || filterChain.get(filterChain.size() - 2) instanceof SSLFilter)
+      {
+        // SSLFilter already installed.
+        throw new IllegalStateException(
+            "SSLFilter already installed on connection");
+      }
+    }
+    if (filter instanceof SASLFilter)
+    {
+      if (filterChain.get(filterChain.size() - 1) instanceof SASLFilter)
+      {
+        // SASLFilter already installed.
+        throw new IllegalStateException(
+            "SASLFilter already installed on connection");
+      }
+    }
+
+    if (listener.getDefaultFilterChain() == filterChain)
+    {
+      filterChain = new DefaultFilterChain(filterChain);
+      connection.setProcessor(filterChain);
+    }
+
+    if (filter instanceof SSLFilter
+        && filterChain.get(filterChain.size() - 1) instanceof SASLFilter)
+    {
+      filterChain.add(filterChain.size() - 2, filter);
+    }
+    else
+    {
+      filterChain.add(filterChain.size() - 1, filter);
+    }
+
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPUtils.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPUtils.java
new file mode 100644
index 0000000..b91adc1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPUtils.java
@@ -0,0 +1,727 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.*;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.responses.SearchResultEntry;
+
+
+
+/**
+ * Common LDAP utility methods which may be used when implementing new controls
+ * and extension.
+ */
+public final class LDAPUtils
+{
+
+  private static final FilterVisitor<IOException, ASN1Writer> ASN1_ENCODER =
+    new FilterVisitor<IOException, ASN1Writer>()
+  {
+
+    public IOException visitAndFilter(final ASN1Writer writer,
+        final List<Filter> subFilters)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_AND);
+        for (final Filter subFilter : subFilters)
+        {
+          final IOException e = subFilter.accept(this, writer);
+          if (e != null)
+          {
+            return e;
+          }
+        }
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitApproxMatchFilter(final ASN1Writer writer,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_APPROXIMATE);
+        writer.writeOctetString(attributeDescription);
+        writer.writeOctetString(assertionValue);
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitEqualityMatchFilter(final ASN1Writer writer,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_EQUALITY);
+        writer.writeOctetString(attributeDescription);
+        writer.writeOctetString(assertionValue);
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitExtensibleMatchFilter(final ASN1Writer writer,
+        final String matchingRule, final String attributeDescription,
+        final ByteString assertionValue, final boolean dnAttributes)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_EXTENSIBLE_MATCH);
+
+        if (matchingRule != null)
+        {
+          writer.writeOctetString(TYPE_MATCHING_RULE_ID, matchingRule);
+        }
+
+        if (attributeDescription != null)
+        {
+          writer
+              .writeOctetString(TYPE_MATCHING_RULE_TYPE, attributeDescription);
+        }
+
+        writer.writeOctetString(TYPE_MATCHING_RULE_VALUE, assertionValue);
+
+        if (dnAttributes)
+        {
+          writer.writeBoolean(TYPE_MATCHING_RULE_DN_ATTRIBUTES, true);
+        }
+
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitGreaterOrEqualFilter(final ASN1Writer writer,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_GREATER_OR_EQUAL);
+        writer.writeOctetString(attributeDescription);
+        writer.writeOctetString(assertionValue);
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitLessOrEqualFilter(final ASN1Writer writer,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_LESS_OR_EQUAL);
+        writer.writeOctetString(attributeDescription);
+        writer.writeOctetString(assertionValue);
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitNotFilter(final ASN1Writer writer,
+        final Filter subFilter)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_NOT);
+        final IOException e = subFilter.accept(this, writer);
+        if (e != null)
+        {
+          return e;
+        }
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitOrFilter(final ASN1Writer writer,
+        final List<Filter> subFilters)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_OR);
+        for (final Filter subFilter : subFilters)
+        {
+          final IOException e = subFilter.accept(this, writer);
+          if (e != null)
+          {
+            return e;
+          }
+        }
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitPresentFilter(final ASN1Writer writer,
+        final String attributeDescription)
+    {
+      try
+      {
+        writer.writeOctetString(TYPE_FILTER_PRESENCE, attributeDescription);
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitSubstringsFilter(final ASN1Writer writer,
+        final String attributeDescription, final ByteString initialSubstring,
+        final List<ByteString> anySubstrings, final ByteString finalSubstring)
+    {
+      try
+      {
+        writer.writeStartSequence(TYPE_FILTER_SUBSTRING);
+        writer.writeOctetString(attributeDescription);
+
+        writer.writeStartSequence();
+        if (initialSubstring != null)
+        {
+          writer.writeOctetString(TYPE_SUBINITIAL, initialSubstring);
+        }
+
+        for (final ByteSequence anySubstring : anySubstrings)
+        {
+          writer.writeOctetString(TYPE_SUBANY, anySubstring);
+        }
+
+        if (finalSubstring != null)
+        {
+          writer.writeOctetString(TYPE_SUBFINAL, finalSubstring);
+        }
+        writer.writeEndSequence();
+
+        writer.writeEndSequence();
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+
+
+
+    public IOException visitUnrecognizedFilter(final ASN1Writer writer,
+        final byte filterTag, final ByteString filterBytes)
+    {
+      try
+      {
+        writer.writeOctetString(filterTag, filterBytes);
+        return null;
+      }
+      catch (final IOException e)
+      {
+        return e;
+      }
+    }
+  };
+
+
+
+  /**
+   * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a
+   * {@code Filter}.
+   *
+   * @param reader
+   *          The {@code ASN1Reader} from which the ASN.1 encoded {@code Filter}
+   *          should be read.
+   * @return The decoded {@code Filter}.
+   * @throws IOException
+   *           If an error occurs while reading from {@code reader}.
+   */
+  public static Filter decodeFilter(final ASN1Reader reader) throws IOException
+  {
+    final byte type = reader.peekType();
+
+    switch (type)
+    {
+    case TYPE_FILTER_AND:
+      return decodeAndFilter(reader);
+
+    case TYPE_FILTER_OR:
+      return decodeOrFilter(reader);
+
+    case TYPE_FILTER_NOT:
+      return decodeNotFilter(reader);
+
+    case TYPE_FILTER_EQUALITY:
+      return decodeEqualityMatchFilter(reader);
+
+    case TYPE_FILTER_GREATER_OR_EQUAL:
+      return decodeGreaterOrEqualMatchFilter(reader);
+
+    case TYPE_FILTER_LESS_OR_EQUAL:
+      return decodeLessOrEqualMatchFilter(reader);
+
+    case TYPE_FILTER_APPROXIMATE:
+      return decodeApproxMatchFilter(reader);
+
+    case TYPE_FILTER_SUBSTRING:
+      return decodeSubstringsFilter(reader);
+
+    case TYPE_FILTER_PRESENCE:
+      return Filter.newPresentFilter(reader.readOctetStringAsString(type));
+
+    case TYPE_FILTER_EXTENSIBLE_MATCH:
+      return decodeExtensibleMatchFilter(reader);
+
+    default:
+      return Filter.newUnrecognizedFilter(type, reader.readOctetString(type));
+    }
+  }
+
+
+
+  /**
+   * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a
+   * {@code SearchResultEntry}.
+   *
+   * @param reader
+   *          The {@code ASN1Reader} from which the ASN.1 encoded {@code
+   *          SearchResultEntry} should be read.
+   * @param options
+   *          The decode options to use when decoding the entry.
+   * @return The decoded {@code SearchResultEntry}.
+   * @throws IOException
+   *           If an error occurs while reading from {@code reader}.
+   */
+  public static SearchResultEntry decodeSearchResultEntry(
+      final ASN1Reader reader, final DecodeOptions options) throws IOException
+  {
+    return LDAPReader.decodeEntry(reader, options);
+  }
+
+
+
+  /**
+   * Writes the ASN.1 encoding of the provided {@code Filter} to the provided
+   * {@code ASN1Writer}.
+   *
+   * @param writer
+   *          The {@code ASN1Writer} to which the ASN.1 encoding of the provided
+   *          {@code Filter} should be written.
+   * @param filter
+   *          The filter to be encoded.
+   * @return The updated {@code ASN1Writer}.
+   * @throws IOException
+   *           If an error occurs while writing to {@code writer}.
+   */
+  public static ASN1Writer encodeFilter(final ASN1Writer writer,
+      final Filter filter) throws IOException
+  {
+    final IOException e = filter.accept(ASN1_ENCODER, writer);
+    if (e != null)
+    {
+      throw e;
+    }
+    else
+    {
+      return writer;
+    }
+  }
+
+
+
+  /**
+   * Writes the ASN.1 encoding of the provided {@code SearchResultEntry} to the
+   * provided {@code ASN1Writer}.
+   *
+   * @param writer
+   *          The {@code ASN1Writer} to which the ASN.1 encoding of the provided
+   *          {@code SearchResultEntry} should be written.
+   * @param entry
+   *          The Search Result Entry to be encoded.
+   * @return The updated {@code ASN1Writer}.
+   * @throws IOException
+   *           If an error occurs while writing to {@code writer}.
+   */
+  public static ASN1Writer encodeSearchResultEntry(final ASN1Writer writer,
+      final SearchResultEntry entry) throws IOException
+  {
+    // FIXME: this should include Controls.
+    LDAPWriter.encodeEntry(writer, entry);
+    return writer;
+  }
+
+
+
+  // Decodes an and filter.
+  private static Filter decodeAndFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    Filter filter;
+
+    reader.readStartSequence(TYPE_FILTER_AND);
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        final List<Filter> subFilters = new LinkedList<Filter>();
+        do
+        {
+          subFilters.add(decodeFilter(reader));
+        }
+        while (reader.hasNextElement());
+        filter = Filter.newAndFilter(subFilters);
+      }
+      else
+      {
+        // No sub-filters - this is an RFC 4526 absolute true filter.
+        filter = Filter.getAbsoluteTrueFilter();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return filter;
+  }
+
+
+
+  // Decodes an approximate match filter.
+  private static Filter decodeApproxMatchFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    String attributeDescription;
+    ByteString assertionValue;
+
+    reader.readStartSequence(TYPE_FILTER_APPROXIMATE);
+    try
+    {
+      attributeDescription = reader.readOctetStringAsString();
+      assertionValue = reader.readOctetString();
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return Filter.newApproxMatchFilter(attributeDescription, assertionValue);
+  }
+
+
+
+  // Decodes an equality match filter.
+  private static Filter decodeEqualityMatchFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    String attributeDescription;
+    ByteString assertionValue;
+
+    reader.readStartSequence(TYPE_FILTER_EQUALITY);
+    try
+    {
+      attributeDescription = reader.readOctetStringAsString();
+      assertionValue = reader.readOctetString();
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return Filter.newEqualityMatchFilter(attributeDescription, assertionValue);
+  }
+
+
+
+  // Decodes an extensible match filter.
+  private static Filter decodeExtensibleMatchFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    String matchingRule;
+    String attributeDescription;
+    boolean dnAttributes;
+    ByteString assertionValue;
+
+    reader.readStartSequence(TYPE_FILTER_EXTENSIBLE_MATCH);
+    try
+    {
+      matchingRule = null;
+      if (reader.peekType() == TYPE_MATCHING_RULE_ID)
+      {
+        matchingRule = reader.readOctetStringAsString(TYPE_MATCHING_RULE_ID);
+      }
+      attributeDescription = null;
+      if (reader.peekType() == TYPE_MATCHING_RULE_TYPE)
+      {
+        attributeDescription = reader
+            .readOctetStringAsString(TYPE_MATCHING_RULE_TYPE);
+      }
+      dnAttributes = false;
+      if (reader.hasNextElement()
+          && (reader.peekType() == TYPE_MATCHING_RULE_DN_ATTRIBUTES))
+      {
+        dnAttributes = reader.readBoolean();
+      }
+      assertionValue = reader.readOctetString(TYPE_MATCHING_RULE_VALUE);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return Filter.newExtensibleMatchFilter(matchingRule, attributeDescription,
+        assertionValue, dnAttributes);
+  }
+
+
+
+  // Decodes a greater than or equal filter.
+  private static Filter decodeGreaterOrEqualMatchFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    String attributeDescription;
+    ByteString assertionValue;
+
+    reader.readStartSequence(TYPE_FILTER_GREATER_OR_EQUAL);
+    try
+    {
+      attributeDescription = reader.readOctetStringAsString();
+      assertionValue = reader.readOctetString();
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+    return Filter.newGreaterOrEqualFilter(attributeDescription, assertionValue);
+  }
+
+
+
+  // Decodes a less than or equal filter.
+  private static Filter decodeLessOrEqualMatchFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    String attributeDescription;
+    ByteString assertionValue;
+
+    reader.readStartSequence(TYPE_FILTER_LESS_OR_EQUAL);
+    try
+    {
+      attributeDescription = reader.readOctetStringAsString();
+      assertionValue = reader.readOctetString();
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return Filter.newLessOrEqualFilter(attributeDescription, assertionValue);
+  }
+
+
+
+  // Decodes a not filter.
+  private static Filter decodeNotFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    Filter subFilter;
+
+    reader.readStartSequence(TYPE_FILTER_NOT);
+    try
+    {
+      subFilter = decodeFilter(reader);
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return Filter.newNotFilter(subFilter);
+  }
+
+
+
+  // Decodes an or filter.
+  private static Filter decodeOrFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    Filter filter;
+
+    reader.readStartSequence(TYPE_FILTER_OR);
+    try
+    {
+      if (reader.hasNextElement())
+      {
+        final List<Filter> subFilters = new LinkedList<Filter>();
+        do
+        {
+          subFilters.add(decodeFilter(reader));
+        }
+        while (reader.hasNextElement());
+        filter = Filter.newOrFilter(subFilters);
+      }
+      else
+      {
+        // No sub-filters - this is an RFC 4526 absolute false filter.
+        filter = Filter.getAbsoluteFalseFilter();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    return filter;
+  }
+
+
+
+  // Decodes a sub-strings filter.
+  private static Filter decodeSubstringsFilter(final ASN1Reader reader)
+      throws IOException
+  {
+    ByteString initialSubstring = null;
+    List<ByteString> anySubstrings = null;
+    ByteString finalSubstring = null;
+    String attributeDescription;
+
+    reader.readStartSequence(TYPE_FILTER_SUBSTRING);
+    try
+    {
+      attributeDescription = reader.readOctetStringAsString();
+      reader.readStartSequence();
+      try
+      {
+        // FIXME: There should be at least one element in this substring
+        // filter sequence.
+        if (reader.peekType() == TYPE_SUBINITIAL)
+        {
+          initialSubstring = reader.readOctetString(TYPE_SUBINITIAL);
+        }
+        if (reader.hasNextElement() && (reader.peekType() == TYPE_SUBANY))
+        {
+          anySubstrings = new LinkedList<ByteString>();
+          do
+          {
+            anySubstrings.add(reader.readOctetString(TYPE_SUBANY));
+          }
+          while (reader.hasNextElement() && (reader.peekType() == TYPE_SUBANY));
+        }
+        if (reader.hasNextElement() && (reader.peekType() == TYPE_SUBFINAL))
+        {
+          finalSubstring = reader.readOctetString(TYPE_SUBFINAL);
+        }
+      }
+      finally
+      {
+        reader.readEndSequence();
+      }
+    }
+    finally
+    {
+      reader.readEndSequence();
+    }
+
+    if (anySubstrings == null)
+    {
+      anySubstrings = Collections.emptyList();
+    }
+
+    return Filter.newSubstringsFilter(attributeDescription, initialSubstring,
+        anySubstrings, finalSubstring);
+  }
+
+
+
+  /**
+   * Prevent instantiation.
+   */
+  private LDAPUtils()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPWriter.java
new file mode 100644
index 0000000..feaabf7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/LDAPWriter.java
@@ -0,0 +1,677 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.*;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.logging.Level;
+
+import org.opends.sdk.Attribute;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DN;
+import org.opends.sdk.Modification;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Static methods for encoding LDAP messages.
+ */
+final class LDAPWriter implements LDAPMessageHandler<ASN1Writer>
+{
+  public static void encodeControl(final ASN1Writer writer,
+      final Control control) throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeOctetString(control.getOID());
+    if (control.isCritical())
+    {
+      writer.writeBoolean(control.isCritical());
+    }
+    if (control.getValue() != null)
+    {
+      writer.writeOctetString(control.getValue());
+    }
+    writer.writeEndSequence();
+  }
+
+
+
+  public static void encodeEntry(final ASN1Writer writer,
+      final SearchResultEntry searchResultEntry) throws IOException
+  {
+    writer.writeStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY);
+    writer.writeOctetString(searchResultEntry.getName().toString());
+
+    writer.writeStartSequence();
+    for (final Attribute attr : searchResultEntry.getAllAttributes())
+    {
+      encodeAttribute(writer, attr);
+    }
+    writer.writeEndSequence();
+    writer.writeEndSequence();
+  }
+
+
+
+  private static void encodeAttribute(final ASN1Writer writer,
+      final Attribute attribute) throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeOctetString(attribute.getAttributeDescriptionAsString());
+
+    writer.writeStartSet();
+    for (final ByteString value : attribute)
+    {
+      writer.writeOctetString(value);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+  }
+
+
+
+  private static void encodeChange(final ASN1Writer writer,
+      final Modification change) throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeEnumerated(change.getModificationType().intValue());
+    encodeAttribute(writer, change.getAttribute());
+    writer.writeEndSequence();
+  }
+
+
+
+  private static void encodeMessageFooter(final ASN1Writer writer,
+      final Request request) throws IOException
+  {
+    final List<Control> controls = request.getControls();
+    if (!controls.isEmpty())
+    {
+      writer.writeStartSequence(TYPE_CONTROL_SEQUENCE);
+      for (final Control control : controls)
+      {
+        encodeControl(writer, control);
+      }
+      writer.writeEndSequence();
+    }
+
+    writer.writeEndSequence();
+  }
+
+
+
+  private static void encodeMessageFooter(final ASN1Writer writer,
+      final Response response) throws IOException
+  {
+    final List<Control> controls = response.getControls();
+    if (!controls.isEmpty())
+    {
+      writer.writeStartSequence(TYPE_CONTROL_SEQUENCE);
+      for (final Control control : controls)
+      {
+        encodeControl(writer, control);
+      }
+      writer.writeEndSequence();
+    }
+
+    writer.writeEndSequence();
+  }
+
+
+
+  private static void encodeMessageHeader(final ASN1Writer writer,
+      final int messageID) throws IOException
+  {
+    writer.writeStartSequence();
+    writer.writeInteger(messageID);
+  }
+
+
+
+  private static void encodeResultFooter(final ASN1Writer writer)
+      throws IOException
+  {
+    writer.writeEndSequence();
+  }
+
+
+
+  private static void encodeResultHeader(final ASN1Writer writer,
+      final byte typeTag, final Result rawMessage) throws IOException
+  {
+    writer.writeStartSequence(typeTag);
+    writer.writeEnumerated(rawMessage.getResultCode().intValue());
+    writer.writeOctetString(rawMessage.getMatchedDN());
+    writer.writeOctetString(rawMessage.getDiagnosticMessage());
+
+    final List<String> referralURIs = rawMessage.getReferralURIs();
+    if (!referralURIs.isEmpty())
+    {
+      writer.writeStartSequence(TYPE_REFERRAL_SEQUENCE);
+      for (final String s : referralURIs)
+      {
+        writer.writeOctetString(s);
+      }
+      writer.writeEndSequence();
+    }
+  }
+
+
+
+  public void abandonRequest(final ASN1Writer writer, final int messageID,
+      final AbandonRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP ABANDON REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeInteger(OP_TYPE_ABANDON_REQUEST, request.getRequestID());
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void addRequest(final ASN1Writer writer, final int messageID,
+      final AddRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_ADD_REQUEST);
+    writer.writeOctetString(request.getName().toString());
+
+    // Write the attributes
+    writer.writeStartSequence();
+    for (final Attribute attr : request.getAllAttributes())
+    {
+      encodeAttribute(writer, attr);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void addResult(final ASN1Writer writer, final int messageID,
+      final Result result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG
+          .finer(String.format(
+              "ENCODE LDAP ADD RESULT(messageID=%d, result=%s)", messageID,
+              result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_ADD_RESPONSE, result);
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public void bindRequest(final ASN1Writer writer, final int messageID,
+      final int version, final GenericBindRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP BIND REQUEST(messageID=%d, auth=0x%x, request=%s)",
+          messageID, request.getAuthenticationType(), request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_BIND_REQUEST);
+
+    writer.writeInteger(version);
+    writer.writeOctetString(request.getName());
+    writer.writeOctetString(request.getAuthenticationType(), request
+        .getAuthenticationValue());
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void bindResult(final ASN1Writer writer, final int messageID,
+      final BindResult result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String
+          .format("ENCODE LDAP BIND RESULT(messageID=%d, result=%s)",
+              messageID, result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_BIND_RESPONSE, result);
+
+    final ByteString saslCredentials = result.getServerSASLCredentials();
+    if (saslCredentials != null && saslCredentials.length() > 0)
+    {
+      writer.writeOctetString(TYPE_SERVER_SASL_CREDENTIALS, result
+          .getServerSASLCredentials());
+    }
+
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public void compareRequest(final ASN1Writer writer, final int messageID,
+      final CompareRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP COMPARE REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_COMPARE_REQUEST);
+    writer.writeOctetString(request.getName().toString());
+
+    writer.writeStartSequence();
+    writer.writeOctetString(request.getAttributeDescription().toString());
+    writer.writeOctetString(request.getAssertionValue());
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void compareResult(final ASN1Writer writer, final int messageID,
+      final CompareResult result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP COMPARE RESULT(messageID=%d, result=%s)", messageID,
+          result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_COMPARE_RESPONSE, result);
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public void deleteRequest(final ASN1Writer writer, final int messageID,
+      final DeleteRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP DELETE REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeOctetString(OP_TYPE_DELETE_REQUEST, request.getName()
+        .toString());
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void deleteResult(final ASN1Writer writer, final int messageID,
+      final Result result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP DELETE RESULT(messageID=%d, result=%s)", messageID,
+          result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_DELETE_RESPONSE, result);
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public <R extends ExtendedResult> void extendedRequest(
+      final ASN1Writer writer, final int messageID,
+      final ExtendedRequest<R> request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP EXTENDED REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_EXTENDED_REQUEST);
+    writer.writeOctetString(TYPE_EXTENDED_REQUEST_OID, request.getOID());
+
+    final ByteString requestValue = request.getValue();
+    if (requestValue != null)
+    {
+      writer.writeOctetString(TYPE_EXTENDED_REQUEST_VALUE, requestValue);
+    }
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void extendedResult(final ASN1Writer writer, final int messageID,
+      final ExtendedResult result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP EXTENDED RESULT(messageID=%d, result=%s)", messageID,
+          result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_EXTENDED_RESPONSE, result);
+
+    final String responseName = result.getOID();
+    final ByteString responseValue = result.getValue();
+
+    if (responseName != null)
+    {
+      writer.writeOctetString(TYPE_EXTENDED_RESPONSE_OID, responseName);
+    }
+
+    if (responseValue != null)
+    {
+      writer.writeOctetString(TYPE_EXTENDED_RESPONSE_VALUE, responseValue);
+    }
+
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public void intermediateResponse(final ASN1Writer writer,
+      final int messageID, final IntermediateResponse response)
+      throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP INTERMEDIATE RESPONSE(messageID=%d, response=%s)",
+          messageID, response));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_INTERMEDIATE_RESPONSE);
+
+    final String responseName = response.getOID();
+    final ByteString responseValue = response.getValue();
+
+    if (responseName != null)
+    {
+      writer
+          .writeOctetString(TYPE_INTERMEDIATE_RESPONSE_OID, response.getOID());
+    }
+
+    if (responseValue != null)
+    {
+      writer.writeOctetString(TYPE_INTERMEDIATE_RESPONSE_VALUE, response
+          .getValue());
+    }
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, response);
+  }
+
+
+
+  public void modifyDNRequest(final ASN1Writer writer, final int messageID,
+      final ModifyDNRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP MODIFY DN REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_MODIFY_DN_REQUEST);
+    writer.writeOctetString(request.getName().toString());
+    writer.writeOctetString(request.getNewRDN().toString());
+    writer.writeBoolean(request.isDeleteOldRDN());
+
+    final DN newSuperior = request.getNewSuperior();
+    if (newSuperior != null)
+    {
+      writer.writeOctetString(TYPE_MODIFY_DN_NEW_SUPERIOR, newSuperior
+          .toString());
+    }
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void modifyDNResult(final ASN1Writer writer, final int messageID,
+      final Result result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP MODIFY DN RESULT(messageID=%d, result=%s)", messageID,
+          result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_MODIFY_DN_RESPONSE, result);
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public void modifyRequest(final ASN1Writer writer, final int messageID,
+      final ModifyRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP MODIFY REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_MODIFY_REQUEST);
+    writer.writeOctetString(request.getName().toString());
+
+    writer.writeStartSequence();
+    for (final Modification change : request.getModifications())
+    {
+      encodeChange(writer, change);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void modifyResult(final ASN1Writer writer, final int messageID,
+      final Result result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP MODIFY RESULT(messageID=%d, result=%s)", messageID,
+          result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_MODIFY_RESPONSE, result);
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public void searchRequest(final ASN1Writer writer, final int messageID,
+      final SearchRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP SEARCH REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_SEARCH_REQUEST);
+    writer.writeOctetString(request.getName().toString());
+    writer.writeEnumerated(request.getScope().intValue());
+    writer.writeEnumerated(request.getDereferenceAliasesPolicy().intValue());
+    writer.writeInteger(request.getSizeLimit());
+    writer.writeInteger(request.getTimeLimit());
+    writer.writeBoolean(request.isTypesOnly());
+    LDAPUtils.encodeFilter(writer, request.getFilter());
+
+    writer.writeStartSequence();
+    for (final String attribute : request.getAttributes())
+    {
+      writer.writeOctetString(attribute);
+    }
+    writer.writeEndSequence();
+
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void searchResult(final ASN1Writer writer, final int messageID,
+      final Result result) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP SEARCH RESULT(messageID=%d, result=%s)", messageID,
+          result));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeResultHeader(writer, OP_TYPE_SEARCH_RESULT_DONE, result);
+    encodeResultFooter(writer);
+    encodeMessageFooter(writer, result);
+  }
+
+
+
+  public void searchResultEntry(final ASN1Writer writer, final int messageID,
+      final SearchResultEntry entry) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID,
+          entry));
+    }
+    encodeMessageHeader(writer, messageID);
+    encodeEntry(writer, entry);
+    encodeMessageFooter(writer, entry);
+  }
+
+
+
+  public void searchResultReference(final ASN1Writer writer,
+      final int messageID, final SearchResultReference reference)
+      throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)",
+          messageID, reference));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeStartSequence(OP_TYPE_SEARCH_RESULT_REFERENCE);
+    for (final String url : reference.getURIs())
+    {
+      writer.writeOctetString(url);
+    }
+    writer.writeEndSequence();
+    encodeMessageFooter(writer, reference);
+  }
+
+
+
+  public void unbindRequest(final ASN1Writer writer, final int messageID,
+      final UnbindRequest request) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP UNBIND REQUEST(messageID=%d, request=%s)", messageID,
+          request));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeNull(OP_TYPE_UNBIND_REQUEST);
+    encodeMessageFooter(writer, request);
+  }
+
+
+
+  public void unrecognizedMessage(final ASN1Writer writer, final int messageID,
+      final byte messageTag, final ByteString messageBytes) throws IOException
+  {
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER))
+    {
+      StaticUtils.DEBUG_LOG.finer(String.format(
+          "ENCODE LDAP UNKNOWN MESSAGE(messageID=%d, messageTag=%s, "
+              + "messageBytes=%s)", messageID, StaticUtils
+              .byteToHex(messageTag), messageBytes.toString()));
+    }
+    encodeMessageHeader(writer, messageID);
+    writer.writeOctetString(messageTag, messageBytes);
+    writer.writeEndSequence();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLDecoderTransformer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLDecoderTransformer.java
new file mode 100644
index 0000000..fa518da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLDecoderTransformer.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.ConnectionSecurityLayer;
+import org.opends.sdk.ErrorResultException;
+
+import org.glassfish.grizzly.*;
+import org.glassfish.grizzly.attributes.AttributeStorage;
+import org.glassfish.grizzly.memory.Buffers;
+import org.glassfish.grizzly.memory.MemoryManager;
+
+
+
+/**
+ * <tt>Transformer</tt>, which decodes SASL encrypted data, contained in the
+ * input Buffer, to the output Buffer.
+ */
+final class SASLDecoderTransformer extends AbstractTransformer<Buffer, Buffer>
+{
+  private static final int BUFFER_SIZE = 4096;
+  private final byte[] buffer = new byte[BUFFER_SIZE];
+  private final ConnectionSecurityLayer bindContext;
+
+  private final MemoryManager<?> memoryManager;
+
+
+
+  public SASLDecoderTransformer(final ConnectionSecurityLayer bindContext,
+      final MemoryManager<?> memoryManager)
+  {
+    this.bindContext = bindContext;
+    this.memoryManager = memoryManager;
+  }
+
+
+
+  public String getName()
+  {
+    return this.getClass().getName();
+  }
+
+
+
+  public boolean hasInputRemaining(final AttributeStorage storage,
+      final Buffer input)
+  {
+    return input != null && input.hasRemaining();
+  }
+
+
+
+  @Override
+  public TransformationResult<Buffer, Buffer> transformImpl(
+      final AttributeStorage storage, final Buffer input)
+      throws TransformationException
+  {
+
+    final int len = Math.min(buffer.length, input.remaining());
+    input.get(buffer, 0, len);
+
+    try
+    {
+      final Buffer output = Buffers.wrap(memoryManager, bindContext.unwrap(
+          buffer, 0, len));
+      return TransformationResult.createCompletedResult(output, input);
+    }
+    catch (final ErrorResultException e)
+    {
+      return TransformationResult.createErrorResult(e.getResult()
+          .getResultCode().intValue(), e.getMessage());
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLEncoderTransformer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLEncoderTransformer.java
new file mode 100644
index 0000000..7c57777
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLEncoderTransformer.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.ConnectionSecurityLayer;
+import org.opends.sdk.ErrorResultException;
+
+import org.glassfish.grizzly.*;
+import org.glassfish.grizzly.attributes.AttributeStorage;
+import org.glassfish.grizzly.memory.Buffers;
+import org.glassfish.grizzly.memory.MemoryManager;
+
+
+
+/**
+ * <tt>Transformer</tt>, which encodes SASL encrypted data, contained in the
+ * input Buffer, to the output Buffer.
+ */
+final class SASLEncoderTransformer extends AbstractTransformer<Buffer, Buffer>
+{
+  private static final int BUFFER_SIZE = 4096;
+  private final byte[] buffer = new byte[BUFFER_SIZE];
+  private final ConnectionSecurityLayer bindContext;
+
+  private final MemoryManager<?> memoryManager;
+
+
+
+  public SASLEncoderTransformer(final ConnectionSecurityLayer bindContext,
+      final MemoryManager<?> memoryManager)
+  {
+    this.bindContext = bindContext;
+    this.memoryManager = memoryManager;
+  }
+
+
+
+  public String getName()
+  {
+    return this.getClass().getName();
+  }
+
+
+
+  public boolean hasInputRemaining(final AttributeStorage storage,
+      final Buffer input)
+  {
+    return input != null && input.hasRemaining();
+  }
+
+
+
+  @Override
+  public TransformationResult<Buffer, Buffer> transformImpl(
+      final AttributeStorage storage, final Buffer input)
+      throws TransformationException
+  {
+
+    final int len = Math.min(buffer.length, input.remaining());
+    input.get(buffer, 0, len);
+
+    try
+    {
+      final Buffer output = Buffers.wrap(memoryManager, bindContext.wrap(
+          buffer, 0, len));
+      return TransformationResult.createCompletedResult(output, input);
+    }
+    catch (final ErrorResultException e)
+    {
+      return TransformationResult.createErrorResult(e.getResult()
+          .getResultCode().intValue(), e.getMessage());
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLFilter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLFilter.java
new file mode 100644
index 0000000..17cf702
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/SASLFilter.java
@@ -0,0 +1,51 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.ConnectionSecurityLayer;
+
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.filterchain.AbstractCodecFilter;
+import org.glassfish.grizzly.memory.MemoryManager;
+
+
+
+/**
+ * SASL filter adapter.
+ */
+final class SASLFilter extends AbstractCodecFilter<Buffer, Buffer>
+{
+  public SASLFilter(final ConnectionSecurityLayer bindContext,
+      final MemoryManager<?> memoryManager)
+  {
+    super(new SASLDecoderTransformer(bindContext, memoryManager),
+        new SASLEncoderTransformer(bindContext, memoryManager));
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/TimeoutChecker.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/TimeoutChecker.java
new file mode 100644
index 0000000..bdae4a6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/TimeoutChecker.java
@@ -0,0 +1,157 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.glassfish.grizzly.utils.LinkedTransferQueue;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Checks connection for pending requests that have timed out.
+ */
+final class TimeoutChecker
+{
+  static final TimeoutChecker INSTANCE = new TimeoutChecker();
+
+  private final LinkedTransferQueue<LDAPConnection> connections;
+  private transient final ReentrantLock lock;
+  private transient final Condition available;
+
+
+
+  private TimeoutChecker()
+  {
+    this.connections = new LinkedTransferQueue<LDAPConnection>();
+    this.lock = new ReentrantLock();
+    this.available = lock.newCondition();
+
+    final Thread checkerThread = new Thread("Timeout Checker")
+    {
+      @Override
+      public void run()
+      {
+        StaticUtils.DEBUG_LOG.fine("Timeout Checker Starting");
+        final ReentrantLock lock = TimeoutChecker.this.lock;
+        lock.lock();
+        try
+        {
+          while (true)
+          {
+            final long currentTime = System.currentTimeMillis();
+            long delay = 0;
+
+            for (final LDAPConnection connection : connections)
+            {
+              StaticUtils.DEBUG_LOG.finer("Checking connection " + connection
+                  + " delay = " + delay);
+              final long newDelay = connection
+                  .cancelExpiredRequests(currentTime);
+              if (newDelay > 0)
+              {
+                if (delay > 0)
+                {
+                  delay = Math.min(newDelay, delay);
+                }
+                else
+                {
+                  delay = newDelay;
+                }
+              }
+            }
+
+            try
+            {
+              if (delay <= 0)
+              {
+                StaticUtils.DEBUG_LOG.finer("There are no connections with "
+                    + "timeout specified. Sleeping");
+                available.await();
+              }
+              else
+              {
+                StaticUtils.DEBUG_LOG.finer("Sleeping for " + delay + "ms");
+                available.await(delay, TimeUnit.MILLISECONDS);
+              }
+            }
+            catch (final InterruptedException e)
+            {
+              // Just go around again.
+            }
+          }
+        }
+        finally
+        {
+          lock.unlock();
+        }
+      }
+    };
+
+    checkerThread.setDaemon(true);
+    checkerThread.start();
+  }
+
+
+
+  void addConnection(final LDAPConnection connection)
+  {
+    final ReentrantLock lock = this.lock;
+    lock.lock();
+    try
+    {
+      connections.add(connection);
+      available.signalAll();
+    }
+    finally
+    {
+      lock.unlock();
+    }
+  }
+
+
+
+  void removeConnection(final LDAPConnection connection)
+  {
+    final ReentrantLock lock = this.lock;
+    lock.lock();
+    try
+    {
+      connections.remove(connection);
+    }
+    finally
+    {
+      lock.unlock();
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedRequestException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedRequestException.java
new file mode 100644
index 0000000..0ba8a17
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedRequestException.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.requests.Request;
+
+
+
+/**
+ * Thrown when an expected LDAP request is received.
+ */
+@SuppressWarnings("serial")
+final class UnexpectedRequestException extends IOException
+{
+  private final int messageID;
+  private final Request request;
+
+
+
+  public UnexpectedRequestException(final int messageID, final Request request)
+  {
+    super(LocalizableMessage.raw("Unexpected LDAP request: id=%d, message=%s",
+        messageID, request).toString());
+    this.messageID = messageID;
+    this.request = request;
+  }
+
+
+
+  public int getMessageID()
+  {
+    return messageID;
+  }
+
+
+
+  public Request getRequest()
+  {
+    return request;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedResponseException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedResponseException.java
new file mode 100644
index 0000000..8ee00f4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnexpectedResponseException.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.responses.Response;
+
+
+
+/**
+ * Thrown when an unexpected LDAP response is received.
+ */
+@SuppressWarnings("serial")
+final class UnexpectedResponseException extends IOException
+{
+  private final int messageID;
+  private final Response response;
+
+
+
+  public UnexpectedResponseException(final int messageID,
+      final Response response)
+  {
+    super(LocalizableMessage.raw("Unexpected LDAP response: id=%d, message=%s",
+        messageID, response).toString());
+    this.messageID = messageID;
+    this.response = response;
+  }
+
+
+
+  public int getMessageID()
+  {
+    return messageID;
+  }
+
+
+
+  public Response getResponse()
+  {
+    return response;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnsupportedMessageException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnsupportedMessageException.java
new file mode 100644
index 0000000..91c301a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/UnsupportedMessageException.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * Thrown when an unsupported LDAP message is received.
+ */
+@SuppressWarnings("serial")
+final class UnsupportedMessageException extends IOException
+{
+  private final int id;
+  private final byte tag;
+  private final ByteString content;
+
+
+
+  public UnsupportedMessageException(final int id, final byte tag,
+      final ByteString content)
+  {
+    super(org.opends.sdk.LocalizableMessage
+        .raw("Unsupported LDAP message: id=%d, tag=%d, content=%s", id, tag,
+            content).toString());
+    this.id = id;
+    this.tag = tag;
+    this.content = content;
+  }
+
+
+
+  public ByteString getContent()
+  {
+    return content;
+  }
+
+
+
+  public int getID()
+  {
+    return id;
+  }
+
+
+
+  public byte getTag()
+  {
+    return tag;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/package-info.java
new file mode 100644
index 0000000..a967a6b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/ldap/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes implementing LDAP protocol.
+ */
+package com.sun.opends.sdk.ldap;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ASCIICharProp.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ASCIICharProp.java
new file mode 100644
index 0000000..f1ed00a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ASCIICharProp.java
@@ -0,0 +1,397 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+/**
+ * A {@code ASCIICharProp} provides fast access to ASCII character properties.
+ * In particular, the ability to query whether or not a character is a letter, a
+ * digit, hexadecimal character, as well as various methods for performing
+ * character conversions.
+ * <p>
+ * The methods in this class do not perform memory allocations nor calculations
+ * and so can be used safely in high performance situations.
+ */
+public final class ASCIICharProp implements Comparable<ASCIICharProp>
+{
+  private final char c;
+
+  private final char upperCaseChar;
+
+  private final char lowerCaseChar;
+
+  private final boolean isUpperCaseChar;
+
+  private final boolean isLowerCaseChar;
+
+  private final boolean isDigit;
+
+  private final boolean isLetter;
+
+  private final boolean isKeyChar;
+
+  private final boolean isHexChar;
+
+  private final int hexValue;
+
+  private final int decimalValue;
+
+  private final String stringValue;
+
+  private static final ASCIICharProp[] CHAR_PROPS = new ASCIICharProp[128];
+
+  static
+  {
+    for (int i = 0; i < 128; i++)
+    {
+      CHAR_PROPS[i] = new ASCIICharProp((char) i);
+    }
+  }
+
+
+
+  /**
+   * Returns the character properties for the provided ASCII character. If a
+   * non-ASCII character is provided then this method returns {@code null}.
+   *
+   * @param c
+   *          The ASCII character.
+   * @return The character properties for the provided ASCII character, or
+   *         {@code null} if {@code c} is greater than {@code \u007F} .
+   */
+  public static ASCIICharProp valueOf(final char c)
+  {
+    if (c < 128)
+    {
+      return CHAR_PROPS[c];
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Returns the character properties for the provided ASCII character. If a
+   * non-ASCII character is provided then this method returns {@code null}.
+   *
+   * @param c
+   *          The ASCII character.
+   * @return The character properties for the provided ASCII character, or
+   *         {@code null} if {@code c} is less than zero or greater than {@code
+   *         \u007F} .
+   */
+  public static ASCIICharProp valueOf(final int c)
+  {
+    if (c >= 0 && c < 128)
+    {
+      return CHAR_PROPS[c];
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  private ASCIICharProp(final char c)
+  {
+    this.c = c;
+    this.stringValue = new String(new char[] { c });
+
+    if (c >= 'a' && c <= 'z')
+    {
+      this.upperCaseChar = (char) (c - 32);
+      this.lowerCaseChar = c;
+      this.isUpperCaseChar = false;
+      this.isLowerCaseChar = true;
+      this.isDigit = false;
+      this.isLetter = true;
+      this.isKeyChar = true;
+      this.decimalValue = -1;
+      if (c >= 'a' && c <= 'f')
+      {
+        this.isHexChar = true;
+        this.hexValue = c - 87;
+      }
+      else
+      {
+        this.isHexChar = false;
+        this.hexValue = -1;
+      }
+    }
+    else if (c >= 'A' && c <= 'Z')
+    {
+      this.upperCaseChar = c;
+      this.lowerCaseChar = (char) (c + 32);
+      this.isUpperCaseChar = true;
+      this.isLowerCaseChar = false;
+      this.isDigit = false;
+      this.isLetter = true;
+      this.isKeyChar = true;
+      this.decimalValue = -1;
+      if (c >= 'A' && c <= 'F')
+      {
+        this.isHexChar = true;
+        this.hexValue = c - 55;
+      }
+      else
+      {
+        this.isHexChar = false;
+        this.hexValue = -1;
+      }
+    }
+    else if (c >= '0' && c <= '9')
+    {
+      this.upperCaseChar = c;
+      this.lowerCaseChar = c;
+      this.isUpperCaseChar = false;
+      this.isLowerCaseChar = false;
+      this.isDigit = true;
+      this.isLetter = false;
+      this.isKeyChar = true;
+      this.isHexChar = true;
+      this.hexValue = c - 48;
+      this.decimalValue = c - 48;
+    }
+    else
+    {
+      this.upperCaseChar = c;
+      this.lowerCaseChar = c;
+      this.isUpperCaseChar = false;
+      this.isLowerCaseChar = false;
+      this.isDigit = false;
+      this.isLetter = false;
+      this.isKeyChar = c == '-';
+      this.isHexChar = false;
+      this.hexValue = -1;
+      this.decimalValue = -1;
+    }
+  }
+
+
+
+  /**
+   * Returns the char value associated with this {@code ASCIICharProp}.
+   *
+   * @return The char value associated with this {@code ASCIICharProp}.
+   */
+  public char charValue()
+  {
+    return c;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final ASCIICharProp o)
+  {
+    return c - o.c;
+  }
+
+
+
+  /**
+   * Returns the decimal value associated with this {@code ASCIICharProp}, or
+   * {@code -1} if the value is not a decimal digit.
+   *
+   * @return The decimal value associated with this {@code ASCIICharProp}, or
+   *         {@code -1} if the value is not a decimal digit.
+   */
+  public int decimalValue()
+  {
+    return decimalValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    return this == obj;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return c;
+  }
+
+
+
+  /**
+   * Returns the hexadecimal value associated with this {@code ASCIICharProp} ,
+   * or {@code -1} if the value is not a hexadecimal digit.
+   *
+   * @return The hexadecimal value associated with this {@code ASCIICharProp} ,
+   *         or {@code -1} if the value is not a hexadecimal digit.
+   */
+  public int hexValue()
+  {
+    return hexValue;
+  }
+
+
+
+  /**
+   * Indicates whether or not the char value associated with this {@code
+   * ASCIICharProp} is a decimal digit.
+   *
+   * @return {@code true} if the char value associated with this {@code
+   *         ASCIICharProp} is a decimal digit.
+   */
+  public boolean isDigit()
+  {
+    return isDigit;
+  }
+
+
+
+  /**
+   * Indicates whether or not the char value associated with this {@code
+   * ASCIICharProp} is a hexadecimal digit.
+   *
+   * @return {@code true} if the char value associated with this {@code
+   *         ASCIICharProp} is a hexadecimal digit.
+   */
+  public boolean isHexDigit()
+  {
+    return isHexChar;
+  }
+
+
+
+  /**
+   * Indicates whether or not the char value associated with this {@code
+   * ASCIICharProp} is a {@code keychar} as defined in RFC 4512. A {@code
+   * keychar} is a letter, a digit, or a hyphen.
+   *
+   * @return {@code true} if the char value associated with this {@code
+   *         ASCIICharProp} is a {@code keychar}.
+   */
+  public boolean isKeyChar()
+  {
+    return isKeyChar;
+  }
+
+
+
+  /**
+   * Indicates whether or not the char value associated with this {@code
+   * ASCIICharProp} is a letter.
+   *
+   * @return {@code true} if the char value associated with this {@code
+   *         ASCIICharProp} is a letter.
+   */
+  public boolean isLetter()
+  {
+    return isLetter;
+  }
+
+
+
+  /**
+   * Indicates whether or not the char value associated with this {@code
+   * ASCIICharProp} is a lower-case character.
+   *
+   * @return {@code true} if the char value associated with this {@code
+   *         ASCIICharProp} is a lower-case character.
+   */
+  public boolean isLowerCase()
+  {
+    return isLowerCaseChar;
+  }
+
+
+
+  /**
+   * Indicates whether or not the char value associated with this {@code
+   * ASCIICharProp} is an upper-case character.
+   *
+   * @return {@code true} if the char value associated with this {@code
+   *         ASCIICharProp} is an upper-case character.
+   */
+  public boolean isUpperCase()
+  {
+    return isUpperCaseChar;
+  }
+
+
+
+  /**
+   * Returns the lower-case char value associated with this {@code
+   * ASCIICharProp}.
+   *
+   * @return The lower-case char value associated with this {@code
+   *         ASCIICharProp}.
+   */
+  public char toLowerCase()
+  {
+    return lowerCaseChar;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return stringValue;
+  }
+
+
+
+  /**
+   * Returns the upper-case char value associated with this {@code
+   * ASCIICharProp}.
+   *
+   * @return The upper-case char value associated with this {@code
+   *         ASCIICharProp}.
+   */
+  public char toUpperCase()
+  {
+    return upperCaseChar;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousConnectionDecorator.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousConnectionDecorator.java
new file mode 100644
index 0000000..14a4c48
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousConnectionDecorator.java
@@ -0,0 +1,508 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.Collection;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * A base class from which asynchronous connection decorators may be easily
+ * implemented. The default implementation of each method is to delegate to the
+ * decorated connection.
+ */
+public abstract class AsynchronousConnectionDecorator implements
+    AsynchronousConnection
+{
+  /**
+   * The decorated asynchronous connection.
+   */
+  protected final AsynchronousConnection connection;
+
+
+
+  /**
+   * Creates a new asynchronous connection decorator.
+   *
+   * @param connection
+   *          The asynchronous connection to be decorated.
+   */
+  protected AsynchronousConnectionDecorator(AsynchronousConnection connection)
+  {
+    Validator.ensureNotNull(connection);
+    this.connection = connection;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Void> abandon(AbandonRequest request)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.abandon(request);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> add(AddRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.add(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> add(AddRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.add(request, resultHandler, intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public void addConnectionEventListener(ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException
+  {
+    connection.addConnectionEventListener(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<BindResult> bind(BindRequest request,
+      ResultHandler<? super BindResult> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.bind(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<BindResult> bind(BindRequest request,
+      ResultHandler<? super BindResult> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.bind(request, resultHandler, intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public void close()
+  {
+    connection.close();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public void close(UnbindRequest request, String reason)
+      throws NullPointerException
+  {
+    connection.close(request, reason);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<CompareResult> compare(CompareRequest request,
+      ResultHandler<? super CompareResult> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.compare(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<CompareResult> compare(CompareRequest request,
+      ResultHandler<? super CompareResult> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.compare(request, resultHandler,
+        intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> delete(DeleteRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.delete(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> delete(DeleteRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.delete(request, resultHandler,
+        intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public <R extends ExtendedResult> FutureResult<R> extendedRequest(
+      ExtendedRequest<R> request, ResultHandler<? super R> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.extendedRequest(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public <R extends ExtendedResult> FutureResult<R> extendedRequest(
+      ExtendedRequest<R> request, ResultHandler<? super R> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.extendedRequest(request, resultHandler,
+        intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to return a synchronous view of this
+   * decorated connection.
+   */
+  public Connection getSynchronousConnection()
+  {
+    return new SynchronousConnection(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public boolean isClosed()
+  {
+    return connection.isClosed();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public boolean isValid()
+  {
+    return connection.isValid();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> modify(ModifyRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.modify(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> modify(ModifyRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.modify(request, resultHandler,
+        intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> modifyDN(ModifyDNRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.modifyDN(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> modifyDN(ModifyDNRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.modifyDN(request, resultHandler,
+        intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<SearchResultEntry> readEntry(DN name,
+      Collection<String> attributeDescriptions,
+      ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.readEntry(name, attributeDescriptions, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<RootDSE> readRootDSE(
+      ResultHandler<? super RootDSE> handler)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return connection.readRootDSE(handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Schema> readSchema(DN name,
+      ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return connection.readSchema(name, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Schema> readSchemaForEntry(DN name,
+      ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return connection.readSchemaForEntry(name, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public void removeConnectionEventListener(ConnectionEventListener listener)
+      throws NullPointerException
+  {
+    connection.removeConnectionEventListener(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> search(SearchRequest request,
+      SearchResultHandler handler) throws UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return connection.search(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<Result> search(SearchRequest request,
+      SearchResultHandler resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.search(request, resultHandler,
+        intermediateResponseHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public FutureResult<SearchResultEntry> searchSingleEntry(
+      SearchRequest request, ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return connection.searchSingleEntry(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to delegate.
+   */
+  public String toString()
+  {
+    return connection.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousFutureResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousFutureResult.java
new file mode 100644
index 0000000..0fe5a68
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/AsynchronousFutureResult.java
@@ -0,0 +1,483 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+import org.opends.sdk.*;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * This class provides a skeletal implementation of the {@code FutureResult}
+ * interface, to minimize the effort required to implement this interface.
+ * <p>
+ * This {@code FutureResult} implementation provides the following features:
+ * <ul>
+ * <li>The {@link #get} methods throw {@link ErrorResultException}s instead of
+ * the more generic {@code ExecutionException}s.
+ * <li>The {@link #get} methods never throw {@code CancellationException} since
+ * requests in this SDK can usually be cancelled via other external means (e.g.
+ * the {@code Cancel} extended operation) for which there are well defined error
+ * results. Therefore cancellation is always signalled by throwing a
+ * {@link CancelledResultException} in order to be consistent with other error
+ * results.
+ * <li>A {@link ResultHandler} can be provided to the constructor. The result
+ * handler will be invoked immediately after the result or error is received but
+ * before threads blocked on {@link #get} are released. More specifically,
+ * result handler invocation <i>happens-before</i> a call to {@link #get}.
+ * <b>NOTE:</b> a result handler which attempts to call {@link #get} will
+ * deadlock.
+ * <li>Sub-classes may choose to implement specific cancellation cleanup by
+ * implementing the {@link #handleCancelRequest} method.
+ * </ul>
+ *
+ * @param <M>
+ *          The type of result returned by this completion future.
+ */
+public class AsynchronousFutureResult<M> implements FutureResult<M>,
+    ResultHandler<M>
+{
+  @SuppressWarnings("serial")
+  private final class Sync extends AbstractQueuedSynchronizer
+  {
+    // State value representing the initial state before a result has
+    // been received.
+    private static final int WAITING = 0;
+
+    // State value representing that a result has been received and is
+    // being processed.
+    private static final int PENDING = 1;
+
+    // State value representing that the request was cancelled.
+    private static final int CANCELLED = 2;
+
+    // State value representing that the request has failed.
+    private static final int FAIL = 3;
+
+    // State value representing that the request has succeeded.
+    private static final int SUCCESS = 4;
+
+    // These do not need to be volatile since their values are published
+    // by updating the state after they are set and reading the state
+    // immediately before they are read.
+    private ErrorResultException errorResult = null;
+
+    private M result = null;
+
+
+
+    /**
+     * Allow all threads to acquire if future has completed.
+     */
+    @Override
+    protected int tryAcquireShared(final int ignore)
+    {
+      return innerIsDone() ? 1 : -1;
+    }
+
+
+
+    /**
+     * Signal that the future has completed and threads waiting on get() can be
+     * released.
+     */
+    @Override
+    protected boolean tryReleaseShared(final int finalState)
+    {
+      // Ensures that errorResult/result is published.
+      setState(finalState);
+      return true;
+    }
+
+
+
+    boolean innerCancel(final boolean mayInterruptIfRunning)
+    {
+      if (!isCancelable() || !setStatePending())
+      {
+        return false;
+      }
+
+      // Perform implementation defined cancellation.
+      ErrorResultException errorResult = handleCancelRequest(mayInterruptIfRunning);
+      if (errorResult == null)
+      {
+        final Result result = Responses
+            .newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
+        errorResult = ErrorResultException.wrap(result);
+      }
+      this.errorResult = errorResult;
+
+      try
+      {
+        // Invoke error result completion handler.
+        if (handler != null)
+        {
+          handler.handleErrorResult(errorResult);
+        }
+      }
+      finally
+      {
+        releaseShared(CANCELLED); // Publishes errorResult.
+      }
+
+      return true;
+    }
+
+
+
+    M innerGet() throws ErrorResultException, InterruptedException
+    {
+      acquireSharedInterruptibly(0);
+      return get0();
+    }
+
+
+
+    M innerGet(final long nanosTimeout) throws ErrorResultException,
+        TimeoutException, InterruptedException
+    {
+      if (!tryAcquireSharedNanos(0, nanosTimeout))
+      {
+        throw new TimeoutException();
+      }
+      else
+      {
+        return get0();
+      }
+    }
+
+
+
+    boolean innerIsCancelled()
+    {
+      return getState() == CANCELLED;
+    }
+
+
+
+    boolean innerIsDone()
+    {
+      return getState() > 1;
+    }
+
+
+
+    void innerSetErrorResult(final ErrorResultException errorResult)
+    {
+      if (setStatePending())
+      {
+        this.errorResult = errorResult;
+
+        try
+        {
+          // Invoke error result completion handler.
+          if (handler != null)
+          {
+            handler.handleErrorResult(errorResult);
+          }
+        }
+        finally
+        {
+          releaseShared(FAIL); // Publishes errorResult.
+        }
+      }
+    }
+
+
+
+    void innerSetResult(final M result)
+    {
+      if (setStatePending())
+      {
+        this.result = result;
+
+        try
+        {
+          // Invoke result completion handler.
+          if (handler != null)
+          {
+            handler.handleResult(result);
+          }
+        }
+        finally
+        {
+          releaseShared(SUCCESS); // Publishes result.
+        }
+      }
+    }
+
+
+
+    private M get0() throws ErrorResultException
+    {
+      if (errorResult != null)
+      {
+        // State must be FAILED or CANCELLED.
+        throw errorResult;
+      }
+      else
+      {
+        // State must be SUCCESS.
+        return result;
+      }
+    }
+
+
+
+    private boolean setStatePending()
+    {
+      for (;;)
+      {
+        final int s = getState();
+        if (s != WAITING)
+        {
+          return false;
+        }
+        if (compareAndSetState(s, PENDING))
+        {
+          return true;
+        }
+      }
+    }
+  }
+
+
+
+  private final Sync sync = new Sync();
+
+  private final ResultHandler<? super M> handler;
+
+  private final int requestID;
+
+
+
+  /**
+   * Creates a new asynchronous future result with the provided result handler
+   * and a request ID of -1.
+   *
+   * @param handler
+   *          A result handler which will be forwarded the result or error when
+   *          it arrives, may be {@code null}.
+   */
+  public AsynchronousFutureResult(final ResultHandler<? super M> handler)
+  {
+    this(handler, -1);
+  }
+
+
+
+  /**
+   * Creates a new asynchronous future result with the provided result handler
+   * and request ID.
+   *
+   * @param handler
+   *          A result handler which will be forwarded the result or error when
+   *          it arrives, may be {@code null}.
+   * @param requestID
+   *          The request ID which will be returned by the default
+   *          implementation of {@link #getRequestID}.
+   */
+  public AsynchronousFutureResult(final ResultHandler<? super M> handler,
+      final int requestID)
+  {
+    this.handler = handler;
+    this.requestID = requestID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final boolean cancel(final boolean mayInterruptIfRunning)
+  {
+    return sync.innerCancel(mayInterruptIfRunning);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final M get() throws ErrorResultException, InterruptedException
+  {
+    return sync.innerGet();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final M get(final long timeout, final TimeUnit unit)
+      throws ErrorResultException, TimeoutException, InterruptedException
+  {
+    return sync.innerGet(unit.toNanos(timeout));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation returns the request ID passed in during
+   * construction, or -1 if none was provided.
+   */
+  @Override
+  public int getRequestID()
+  {
+    return requestID;
+  }
+
+
+
+  /**
+   * Sets the error result associated with this future. If ({@code isDone() ==
+   * true}) then the error result will be ignored, otherwise the result handler
+   * will be invoked if one was provided and, on return, any threads waiting on
+   * {@link #get} will be released and the provided error result will be thrown.
+   *
+   * @param errorResult
+   *          The error result.
+   */
+  @Override
+  public final void handleErrorResult(final ErrorResultException errorResult)
+  {
+    sync.innerSetErrorResult(errorResult);
+  }
+
+
+
+  /**
+   * Sets the result associated with this future. If ({@code isDone() == true})
+   * then the result will be ignored, otherwise the result handler will be
+   * invoked if one was provided and, on return, any threads waiting on
+   * {@link #get} will be released and the provided result will be returned.
+   *
+   * @param result
+   *          The result.
+   */
+  @Override
+  public final void handleResult(final M result)
+  {
+    sync.innerSetResult(result);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final boolean isCancelled()
+  {
+    return sync.innerIsCancelled();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final boolean isDone()
+  {
+    return sync.innerIsDone();
+  }
+
+
+
+  /**
+   * Invoked when {@link #cancel} is called and {@code isDone() == false} and
+   * immediately before any threads waiting on {@link #get} are released.
+   * Implementations may choose to return a custom error result if needed or
+   * return {@code null} if the following default error result is acceptable:
+   *
+   * <pre>
+   * Result result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
+   * </pre>
+   *
+   * In addition, implementations may perform other cleanup, for example, by
+   * issuing an LDAP abandon request. The default implementation is to do
+   * nothing.
+   *
+   * @param mayInterruptIfRunning
+   *          {@code true} if the thread executing executing the response
+   *          handler should be interrupted; otherwise, in-progress response
+   *          handlers are allowed to complete.
+   * @return The custom error result, or {@code null} if the default is
+   *         acceptable.
+   */
+  protected ErrorResultException handleCancelRequest(
+      final boolean mayInterruptIfRunning)
+  {
+    // Do nothing by default.
+    return null;
+  }
+
+
+
+  /**
+   * Indicates whether this future result can be canceled.
+   *
+   * @return {@code true} if this future result is cancelable or {@code false}
+   *         otherwise.
+   */
+  protected boolean isCancelable()
+  {
+    // Return true by default.
+    return true;
+  }
+
+
+
+  /**
+   * Appends a string representation of this future's state to the provided
+   * builder.
+   *
+   * @param sb
+   *          The string builder.
+   */
+  protected void toString(final StringBuilder sb)
+  {
+    sb.append(" state = ");
+    sb.append(sync);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Base64.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Base64.java
new file mode 100755
index 0000000..2ae7a8e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Base64.java
@@ -0,0 +1,383 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.util;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_BASE64_DECODE_INVALID_CHARACTER;
+import static com.sun.opends.sdk.messages.Messages.ERR_BASE64_DECODE_INVALID_LENGTH;
+import static com.sun.opends.sdk.util.Validator.ensureNotNull;
+
+import org.opends.sdk.*;
+
+
+
+/**
+ * This class provides methods for performing base64 encoding and decoding.
+ * Base64 is a mechanism for encoding binary data in ASCII form by converting
+ * sets of three bytes with eight significant bits each to sets of four bytes
+ * with six significant bits each.
+ */
+public final class Base64
+{
+  /**
+   * The set of characters that may be used in base64-encoded values.
+   */
+  private static final char[] BASE64_ALPHABET = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/").toCharArray();
+
+
+
+  /**
+   * Decodes the provided base64 encoded data.
+   *
+   * @param base64
+   *          The base64 encoded data.
+   * @return The decoded data.
+   * @throws LocalizedIllegalArgumentException
+   *           If a problem occurs while attempting to decode {@code base64}.
+   * @throws NullPointerException
+   *           If {@code base64} was {@code null}.
+   */
+  public static ByteString decode(final String base64)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    ensureNotNull(base64);
+
+    // The encoded value must have length that is a multiple of four
+    // bytes.
+    final int length = base64.length();
+    if ((length % 4) != 0)
+    {
+      final LocalizableMessage message = ERR_BASE64_DECODE_INVALID_LENGTH
+          .get(base64);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    final ByteStringBuilder builder = new ByteStringBuilder(length);
+    for (int i = 0; i < length; i += 4)
+    {
+      boolean append = true;
+      int value = 0;
+
+      for (int j = 0; j < 4; j++)
+      {
+        switch (base64.charAt(i + j))
+        {
+        case 'A':
+          value <<= 6;
+          break;
+        case 'B':
+          value = (value << 6) | 0x01;
+          break;
+        case 'C':
+          value = (value << 6) | 0x02;
+          break;
+        case 'D':
+          value = (value << 6) | 0x03;
+          break;
+        case 'E':
+          value = (value << 6) | 0x04;
+          break;
+        case 'F':
+          value = (value << 6) | 0x05;
+          break;
+        case 'G':
+          value = (value << 6) | 0x06;
+          break;
+        case 'H':
+          value = (value << 6) | 0x07;
+          break;
+        case 'I':
+          value = (value << 6) | 0x08;
+          break;
+        case 'J':
+          value = (value << 6) | 0x09;
+          break;
+        case 'K':
+          value = (value << 6) | 0x0A;
+          break;
+        case 'L':
+          value = (value << 6) | 0x0B;
+          break;
+        case 'M':
+          value = (value << 6) | 0x0C;
+          break;
+        case 'N':
+          value = (value << 6) | 0x0D;
+          break;
+        case 'O':
+          value = (value << 6) | 0x0E;
+          break;
+        case 'P':
+          value = (value << 6) | 0x0F;
+          break;
+        case 'Q':
+          value = (value << 6) | 0x10;
+          break;
+        case 'R':
+          value = (value << 6) | 0x11;
+          break;
+        case 'S':
+          value = (value << 6) | 0x12;
+          break;
+        case 'T':
+          value = (value << 6) | 0x13;
+          break;
+        case 'U':
+          value = (value << 6) | 0x14;
+          break;
+        case 'V':
+          value = (value << 6) | 0x15;
+          break;
+        case 'W':
+          value = (value << 6) | 0x16;
+          break;
+        case 'X':
+          value = (value << 6) | 0x17;
+          break;
+        case 'Y':
+          value = (value << 6) | 0x18;
+          break;
+        case 'Z':
+          value = (value << 6) | 0x19;
+          break;
+        case 'a':
+          value = (value << 6) | 0x1A;
+          break;
+        case 'b':
+          value = (value << 6) | 0x1B;
+          break;
+        case 'c':
+          value = (value << 6) | 0x1C;
+          break;
+        case 'd':
+          value = (value << 6) | 0x1D;
+          break;
+        case 'e':
+          value = (value << 6) | 0x1E;
+          break;
+        case 'f':
+          value = (value << 6) | 0x1F;
+          break;
+        case 'g':
+          value = (value << 6) | 0x20;
+          break;
+        case 'h':
+          value = (value << 6) | 0x21;
+          break;
+        case 'i':
+          value = (value << 6) | 0x22;
+          break;
+        case 'j':
+          value = (value << 6) | 0x23;
+          break;
+        case 'k':
+          value = (value << 6) | 0x24;
+          break;
+        case 'l':
+          value = (value << 6) | 0x25;
+          break;
+        case 'm':
+          value = (value << 6) | 0x26;
+          break;
+        case 'n':
+          value = (value << 6) | 0x27;
+          break;
+        case 'o':
+          value = (value << 6) | 0x28;
+          break;
+        case 'p':
+          value = (value << 6) | 0x29;
+          break;
+        case 'q':
+          value = (value << 6) | 0x2A;
+          break;
+        case 'r':
+          value = (value << 6) | 0x2B;
+          break;
+        case 's':
+          value = (value << 6) | 0x2C;
+          break;
+        case 't':
+          value = (value << 6) | 0x2D;
+          break;
+        case 'u':
+          value = (value << 6) | 0x2E;
+          break;
+        case 'v':
+          value = (value << 6) | 0x2F;
+          break;
+        case 'w':
+          value = (value << 6) | 0x30;
+          break;
+        case 'x':
+          value = (value << 6) | 0x31;
+          break;
+        case 'y':
+          value = (value << 6) | 0x32;
+          break;
+        case 'z':
+          value = (value << 6) | 0x33;
+          break;
+        case '0':
+          value = (value << 6) | 0x34;
+          break;
+        case '1':
+          value = (value << 6) | 0x35;
+          break;
+        case '2':
+          value = (value << 6) | 0x36;
+          break;
+        case '3':
+          value = (value << 6) | 0x37;
+          break;
+        case '4':
+          value = (value << 6) | 0x38;
+          break;
+        case '5':
+          value = (value << 6) | 0x39;
+          break;
+        case '6':
+          value = (value << 6) | 0x3A;
+          break;
+        case '7':
+          value = (value << 6) | 0x3B;
+          break;
+        case '8':
+          value = (value << 6) | 0x3C;
+          break;
+        case '9':
+          value = (value << 6) | 0x3D;
+          break;
+        case '+':
+          value = (value << 6) | 0x3E;
+          break;
+        case '/':
+          value = (value << 6) | 0x3F;
+          break;
+        case '=':
+          append = false;
+          switch (j)
+          {
+          case 2:
+            builder.append((byte) ((value >>> 4) & 0xFF));
+            break;
+          case 3:
+            builder.append((byte) ((value >>> 10) & 0xFF));
+            builder.append((byte) ((value >>> 2) & 0xFF));
+            break;
+          }
+          break;
+        default:
+          final LocalizableMessage message = ERR_BASE64_DECODE_INVALID_CHARACTER
+              .get(base64, base64.charAt(i + j));
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        if (!append)
+        {
+          break;
+        }
+      }
+
+      if (append)
+      {
+        builder.append((byte) ((value >>> 16) & 0xFF));
+        builder.append((byte) ((value >>> 8) & 0xFF));
+        builder.append((byte) (value & 0xFF));
+      }
+      else
+      {
+        break;
+      }
+    }
+
+    return builder.toByteString();
+  }
+
+
+
+  /**
+   * Encodes the provided data as a base64 string.
+   *
+   * @param bytes
+   *          The data to be encoded.
+   * @return The base64 encoded representation of {@code bytes}.
+   * @throws NullPointerException
+   *           If {@code bytes} was {@code null}.
+   */
+  public static String encode(final ByteSequence bytes)
+      throws NullPointerException
+  {
+    ensureNotNull(bytes);
+
+    final StringBuilder buffer = new StringBuilder(4 * bytes.length() / 3);
+
+    int pos = 0;
+    final int iterations = bytes.length() / 3;
+    for (int i = 0; i < iterations; i++)
+    {
+      final int value = ((bytes.byteAt(pos++) & 0xFF) << 16)
+          | ((bytes.byteAt(pos++) & 0xFF) << 8) | (bytes.byteAt(pos++) & 0xFF);
+
+      buffer.append(BASE64_ALPHABET[(value >>> 18) & 0x3F]);
+      buffer.append(BASE64_ALPHABET[(value >>> 12) & 0x3F]);
+      buffer.append(BASE64_ALPHABET[(value >>> 6) & 0x3F]);
+      buffer.append(BASE64_ALPHABET[value & 0x3F]);
+    }
+
+    switch (bytes.length() % 3)
+    {
+    case 1:
+      buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) >>> 2) & 0x3F]);
+      buffer.append(BASE64_ALPHABET[(bytes.byteAt(pos) << 4) & 0x3F]);
+      buffer.append("==");
+      break;
+    case 2:
+      final int value = ((bytes.byteAt(pos++) & 0xFF) << 8)
+          | (bytes.byteAt(pos) & 0xFF);
+      buffer.append(BASE64_ALPHABET[(value >>> 10) & 0x3F]);
+      buffer.append(BASE64_ALPHABET[(value >>> 4) & 0x3F]);
+      buffer.append(BASE64_ALPHABET[(value << 2) & 0x3F]);
+      buffer.append("=");
+      break;
+    }
+
+    return buffer.toString();
+  }
+
+
+
+  /**
+   * Prevent instance creation.
+   */
+  private Base64()
+  {
+    // No implementation required.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ByteSequenceOutputStream.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ByteSequenceOutputStream.java
new file mode 100644
index 0000000..018c0ea
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/ByteSequenceOutputStream.java
@@ -0,0 +1,144 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.util;
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.opends.sdk.ByteStringBuilder;
+
+
+
+/**
+ * An adapter class that allows writing to an byte string builder with the
+ * outputstream interface.
+ */
+public final class ByteSequenceOutputStream extends OutputStream
+{
+
+  private final ByteStringBuilder buffer;
+
+
+
+  /**
+   * Creates a new byte string builder output stream.
+   *
+   * @param buffer
+   *          The underlying byte string builder.
+   */
+  public ByteSequenceOutputStream(final ByteStringBuilder buffer)
+  {
+    this.buffer = buffer;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close() throws IOException
+  {
+    buffer.clear();
+  }
+
+
+
+  /**
+   * Gets the length of the underlying byte string builder.
+   *
+   * @return The length of the underlying byte string builder.
+   */
+  public int length()
+  {
+    return buffer.length();
+  }
+
+
+
+  /**
+   * Resets this output stream such that the underlying byte string builder is
+   * empty.
+   */
+  public void reset()
+  {
+    buffer.clear();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void write(final byte[] bytes) throws IOException
+  {
+    buffer.append(bytes);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void write(final byte[] bytes, final int i, final int i1)
+      throws IOException
+  {
+    buffer.append(bytes, i, i1);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void write(final int i) throws IOException
+  {
+    buffer.append(((byte) (i & 0xFF)));
+  }
+
+
+
+  /**
+   * Writes the content of the underlying byte string builder to the provided
+   * output stream.
+   *
+   * @param stream
+   *          The output stream.
+   * @throws IOException
+   *           If an I/O error occurs. In particular, an {@code IOException} is
+   *           thrown if the output stream is closed.
+   */
+  public void writeTo(final OutputStream stream) throws IOException
+  {
+    buffer.copyTo(stream);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Collections2.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Collections2.java
new file mode 100644
index 0000000..fd54426
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Collections2.java
@@ -0,0 +1,507 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.*;
+
+
+
+/**
+ * Additional {@code Collection} based utility methods.
+ */
+public final class Collections2
+{
+  private static class TransformedCollection<M, N, P, C extends Collection<M>>
+      extends AbstractCollection<N> implements Collection<N>
+  {
+
+    protected final C collection;
+
+    protected final Function<? super M, ? extends N, P> funcMtoN;
+
+    protected final Function<? super N, ? extends M, P> funcNtoM;
+
+    protected final P p;
+
+
+
+    protected TransformedCollection(final C collection,
+        final Function<? super M, ? extends N, P> funcMtoN,
+        final Function<? super N, ? extends M, P> funcNtoM, final P p)
+    {
+      this.collection = collection;
+      this.funcMtoN = funcMtoN;
+      this.funcNtoM = funcNtoM;
+      this.p = p;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean add(final N e)
+    {
+      return collection.add(funcNtoM.apply(e, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void clear()
+    {
+      collection.clear();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean contains(final Object o)
+    {
+      final N tmp = (N) o;
+      return collection.contains(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isEmpty()
+    {
+      return collection.isEmpty();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterator<N> iterator()
+    {
+      return Iterators.transformedIterator(collection.iterator(), funcMtoN, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean remove(final Object o)
+    {
+      final N tmp = (N) o;
+      return collection.remove(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int size()
+    {
+      return collection.size();
+    }
+
+  }
+
+
+
+  private static final class TransformedList<M, N, P> extends
+      TransformedCollection<M, N, P, List<M>> implements List<N>
+  {
+
+    private TransformedList(final List<M> list,
+        final Function<? super M, ? extends N, P> funcMtoN,
+        final Function<? super N, ? extends M, P> funcNtoM, final P p)
+    {
+      super(list, funcMtoN, funcNtoM, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void add(final int index, final N element)
+    {
+      collection.add(index, funcNtoM.apply(element, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean addAll(final int index, final Collection<? extends N> c)
+    {
+      // We cannot transform c here due to type-safety.
+      boolean result = false;
+      for (final N e : c)
+      {
+        result |= add(e);
+      }
+      return result;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public N get(final int index)
+    {
+      return funcMtoN.apply(collection.get(index), p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public int indexOf(final Object o)
+    {
+      final N tmp = (N) o;
+      return collection.indexOf(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public int lastIndexOf(final Object o)
+    {
+      final N tmp = (N) o;
+      return collection.lastIndexOf(funcNtoM.apply(tmp, p));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ListIterator<N> listIterator()
+    {
+      return listIterator(0);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ListIterator<N> listIterator(final int index)
+    {
+      final ListIterator<M> iterator = collection.listIterator(index);
+      return new ListIterator<N>()
+      {
+
+        @Override
+        public void add(final N e)
+        {
+          iterator.add(funcNtoM.apply(e, p));
+        }
+
+
+
+        @Override
+        public boolean hasNext()
+        {
+          return iterator.hasNext();
+        }
+
+
+
+        @Override
+        public boolean hasPrevious()
+        {
+          return iterator.hasPrevious();
+        }
+
+
+
+        @Override
+        public N next()
+        {
+          return funcMtoN.apply(iterator.next(), p);
+        }
+
+
+
+        @Override
+        public int nextIndex()
+        {
+          return iterator.nextIndex();
+        }
+
+
+
+        @Override
+        public N previous()
+        {
+          return funcMtoN.apply(iterator.previous(), p);
+        }
+
+
+
+        @Override
+        public int previousIndex()
+        {
+          return iterator.previousIndex();
+        }
+
+
+
+        @Override
+        public void remove()
+        {
+          iterator.remove();
+        }
+
+
+
+        @Override
+        public void set(final N e)
+        {
+          iterator.set(funcNtoM.apply(e, p));
+        }
+
+      };
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public N remove(final int index)
+    {
+      return funcMtoN.apply(collection.remove(index), p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public N set(final int index, final N element)
+    {
+      final M result = collection.set(index, funcNtoM.apply(element, p));
+      return funcMtoN.apply(result, p);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<N> subList(final int fromIndex, final int toIndex)
+    {
+      final List<M> subList = collection.subList(fromIndex, toIndex);
+      return new TransformedList<M, N, P>(subList, funcMtoN, funcNtoM, p);
+    }
+
+  }
+
+
+
+  /**
+   * Returns a view of {@code collection} whose values have been mapped to
+   * elements of type {@code N} using {@code funcMtoN}. The returned collection
+   * supports all operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code collection}.
+   * @param <N>
+   *          The type of elements contained in the returned collection.
+   * @param <P>
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
+   * @param collection
+   *          The collection to be transformed.
+   * @param funcMtoN
+   *          A function which maps values of type {@code M} to values of type
+   *          {@code N}. This function will be used when retrieving values from
+   *          {@code collection}.
+   * @param funcNtoM
+   *          A function which maps values of type {@code N} to values of type
+   *          {@code M}. This function will be used when performing queries and
+   *          adding values to {@code collection} .
+   * @param p
+   *          A predicate specified parameter.
+   * @return A view of {@code collection} whose values have been mapped to
+   *         elements of type {@code N} using {@code funcMtoN}.
+   */
+  public static <M, N, P> Collection<N> transformedCollection(
+      final Collection<M> collection,
+      final Function<? super M, ? extends N, P> funcMtoN,
+      final Function<? super N, ? extends M, P> funcNtoM, final P p)
+  {
+    return new TransformedCollection<M, N, P, Collection<M>>(collection,
+        funcMtoN, funcNtoM, p);
+  }
+
+
+
+  /**
+   * Returns a view of {@code collection} whose values have been mapped to
+   * elements of type {@code N} using {@code funcMtoN}. The returned collection
+   * supports all operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code collection}.
+   * @param <N>
+   *          The type of elements contained in the returned collection.
+   * @param collection
+   *          The collection to be transformed.
+   * @param funcMtoN
+   *          A function which maps values of type {@code M} to values of type
+   *          {@code N}. This function will be used when retrieving values from
+   *          {@code collection}.
+   * @param funcNtoM
+   *          A function which maps values of type {@code N} to values of type
+   *          {@code M}. This function will be used when performing queries and
+   *          adding values to {@code collection} .
+   * @return A view of {@code collection} whose values have been mapped to
+   *         elements of type {@code N} using {@code funcMtoN}.
+   */
+  public static <M, N> Collection<N> transformedCollection(
+      final Collection<M> collection,
+      final Function<? super M, ? extends N, Void> funcMtoN,
+      final Function<? super N, ? extends M, Void> funcNtoM)
+  {
+    return new TransformedCollection<M, N, Void, Collection<M>>(collection,
+        funcMtoN, funcNtoM, null);
+  }
+
+
+
+  /**
+   * Returns a view of {@code list} whose values have been mapped to elements of
+   * type {@code N} using {@code funcMtoN}. The returned list supports all
+   * operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code list}.
+   * @param <N>
+   *          The type of elements contained in the returned list.
+   * @param <P>
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
+   * @param list
+   *          The list to be transformed.
+   * @param funcMtoN
+   *          A function which maps values of type {@code M} to values of type
+   *          {@code N}. This function will be used when retrieving values from
+   *          {@code list}.
+   * @param funcNtoM
+   *          A function which maps values of type {@code N} to values of type
+   *          {@code M}. This function will be used when performing queries and
+   *          adding values to {@code list} .
+   * @param p
+   *          A predicate specified parameter.
+   * @return A view of {@code list} whose values have been mapped to elements of
+   *         type {@code N} using {@code funcMtoN}.
+   */
+  public static <M, N, P> List<N> transformedList(final List<M> list,
+      final Function<? super M, ? extends N, P> funcMtoN,
+      final Function<? super N, ? extends M, P> funcNtoM, final P p)
+  {
+    return new TransformedList<M, N, P>(list, funcMtoN, funcNtoM, p);
+  }
+
+
+
+  /**
+   * Returns a view of {@code list} whose values have been mapped to elements of
+   * type {@code N} using {@code funcMtoN}. The returned list supports all
+   * operations.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code list}.
+   * @param <N>
+   *          The type of elements contained in the returned list.
+   * @param list
+   *          The list to be transformed.
+   * @param funcMtoN
+   *          A function which maps values of type {@code M} to values of type
+   *          {@code N}. This function will be used when retrieving values from
+   *          {@code list}.
+   * @param funcNtoM
+   *          A function which maps values of type {@code N} to values of type
+   *          {@code M}. This function will be used when performing queries and
+   *          adding values to {@code list} .
+   * @return A view of {@code list} whose values have been mapped to elements of
+   *         type {@code N} using {@code funcMtoN}.
+   */
+  public static <M, N> List<N> transformedList(final List<M> list,
+      final Function<? super M, ? extends N, Void> funcMtoN,
+      final Function<? super N, ? extends M, Void> funcNtoM)
+  {
+    return new TransformedList<M, N, Void>(list, funcMtoN, funcNtoM, null);
+  }
+
+
+
+  // Prevent instantiation
+  private Collections2()
+  {
+    // Do nothing.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/CompletedFutureResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/CompletedFutureResult.java
new file mode 100644
index 0000000..756d461
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/CompletedFutureResult.java
@@ -0,0 +1,196 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.FutureResult;
+
+
+
+/**
+ * An implementation of {@code FutureResult} which can be used in cases where
+ * the result is known in advance, for example, if the result is obtained
+ * synchronously.
+ *
+ * @param <S>
+ *          The type of result returned by this future.
+ */
+public final class CompletedFutureResult<S> implements FutureResult<S>
+{
+  private final S result;
+
+  private final ErrorResultException errorResult;
+
+  private final int requestID;
+
+
+
+  /**
+   * Creates a new completed future which will throw the provided error result
+   * and request ID of {@code -1}.
+   *
+   * @param errorResult
+   *          The error result.
+   * @throws NullPointerException
+   *           If {@code errorResult} was {@code null}.
+   */
+  public CompletedFutureResult(final ErrorResultException errorResult)
+      throws NullPointerException
+  {
+    this(errorResult, -1);
+  }
+
+
+
+  /**
+   * Creates a new completed future which will throw the provided error result
+   * and request ID.
+   *
+   * @param errorResult
+   *          The error result.
+   * @param requestID
+   *          The request ID.
+   * @throws NullPointerException
+   *           If {@code errorResult} was {@code null}.
+   */
+  public CompletedFutureResult(final ErrorResultException errorResult,
+      final int requestID) throws NullPointerException
+  {
+    Validator.ensureNotNull(errorResult);
+    this.result = null;
+    this.errorResult = errorResult;
+    this.requestID = requestID;
+  }
+
+
+
+  /**
+   * Creates a new completed future which will return the provided result and
+   * request ID of {@code -1}.
+   *
+   * @param result
+   *          The result, which may be {@code null}.
+   */
+  public CompletedFutureResult(final S result)
+  {
+    this(result, -1);
+  }
+
+
+
+  /**
+   * Creates a new completed future which will return the provided result and
+   * request ID.
+   *
+   * @param result
+   *          The result, which may be {@code null}.
+   * @param requestID
+   *          The request ID.
+   */
+  public CompletedFutureResult(final S result, final int requestID)
+  {
+    this.result = result;
+    this.errorResult = null;
+    this.requestID = requestID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean cancel(final boolean mayInterruptIfRunning)
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public S get() throws ErrorResultException, InterruptedException
+  {
+    if (errorResult == null)
+    {
+      // May be null.
+      return result;
+    }
+    else
+    {
+      throw errorResult;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public S get(final long timeout, final TimeUnit unit)
+      throws ErrorResultException, TimeoutException, InterruptedException
+  {
+    return get();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getRequestID()
+  {
+    return requestID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCancelled()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isDone()
+  {
+    return true;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Function.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Function.java
new file mode 100644
index 0000000..eb20f63
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Function.java
@@ -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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+/**
+ * Functions transform input values of type {@code M} to output values of type
+ * {@code N}.
+ *
+ * @param <M>
+ *          The type of input values transformed by this function.
+ * @param <N>
+ *          The type of output values return by this function.
+ * @param <P>
+ *          The type of the additional parameter to this function's {@code
+ *          apply} method. Use {@link java.lang.Void} for functions that do not
+ *          need an additional parameter.
+ */
+public interface Function<M, N, P>
+{
+  /**
+   * Applies this function to the provided input value of type {@code M} ,
+   * returning an output value of type {@code N}.
+   *
+   * @param value
+   *          The value to be transformed.
+   * @param p
+   *          A function specified parameter.
+   * @return The result of the transformation.
+   */
+  N apply(M value, P p);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Functions.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Functions.java
new file mode 100644
index 0000000..7892222
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Functions.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import org.opends.sdk.AttributeDescription;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DN;
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * Common {@link Function} implementations.
+ */
+public final class Functions
+{
+
+  private static final class FixedFunction<M, N, P> implements
+      Function<M, N, Void>
+  {
+    private final Function<M, N, P> function;
+
+    private final P parameter;
+
+
+
+    private FixedFunction(final Function<M, N, P> function, final P p)
+    {
+      this.function = function;
+      this.parameter = p;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public N apply(final M value, final Void p)
+    {
+      return function.apply(value, parameter);
+    }
+
+  }
+
+
+
+  private static final Function<ByteString, AttributeDescription, Schema>
+    BYTESTRING_TO_ATTRIBUTE_DESCRIPTION =
+      new Function<ByteString, AttributeDescription, Schema>()
+  {
+
+    public AttributeDescription apply(final ByteString value, final Schema p)
+    {
+      // FIXME: what should we do if parsing fails?
+      return AttributeDescription.valueOf(value.toString(), p);
+    }
+  };
+
+  private static final Function<ByteString, Boolean, Void>
+    BYTESTRING_TO_BOOLEAN = new Function<ByteString, Boolean, Void>()
+  {
+
+    public Boolean apply(final ByteString value, final Void p)
+    {
+      final String valueString = StaticUtils.toLowerCase(value.toString());
+
+      if (valueString.equals("true") || valueString.equals("yes")
+          || valueString.equals("on") || valueString.equals("1"))
+      {
+        return Boolean.TRUE;
+      }
+      else if (valueString.equals("false") || valueString.equals("no")
+          || valueString.equals("off") || valueString.equals("0"))
+      {
+        return Boolean.FALSE;
+      }
+      else
+      {
+        throw new NumberFormatException("Invalid boolean value \""
+            + valueString + "\"");
+      }
+    }
+  };
+
+  private static final Function<ByteString, DN, Schema> BYTESTRING_TO_DN =
+    new Function<ByteString, DN, Schema>()
+  {
+
+    public DN apply(final ByteString value, final Schema p)
+    {
+      // FIXME: what should we do if parsing fails?
+
+      // FIXME: we should have a ByteString valueOf implementation.
+      return DN.valueOf(value.toString(), p);
+    }
+  };
+
+  private static final Function<ByteString, Integer, Void>
+    BYTESTRING_TO_INTEGER = new Function<ByteString, Integer, Void>()
+  {
+
+    public Integer apply(final ByteString value, final Void p)
+    {
+      // We do not use ByteString.toInt() as we are string based.
+      return Integer.valueOf(value.toString());
+    }
+  };
+
+  private static final Function<ByteString, Long, Void> BYTESTRING_TO_LONG =
+    new Function<ByteString, Long, Void>()
+  {
+
+    public Long apply(final ByteString value, final Void p)
+    {
+      // We do not use ByteString.toLong() as we are string based.
+      return Long.valueOf(value.toString());
+    }
+  };
+
+  private static final Function<ByteString, String, Void> BYTESTRING_TO_STRING =
+    new Function<ByteString, String, Void>()
+  {
+
+    public String apply(final ByteString value, final Void p)
+    {
+      return value.toString();
+    }
+  };
+
+  private static final Function<Object, ByteString, Void> OBJECT_TO_BYTESTRING =
+    new Function<Object, ByteString, Void>()
+  {
+
+    public ByteString apply(final Object value, final Void p)
+    {
+      return ByteString.valueOf(value);
+    }
+  };
+
+  private static final Function<String, String, Void> NORMALIZE_STRING =
+    new Function<String, String, Void>()
+  {
+
+    public String apply(final String value, final Void p)
+    {
+      return StaticUtils.toLowerCase(value).trim();
+    }
+  };
+
+  private static final Function<Object, Object, Void> IDENTITY =
+    new Function<Object, Object, Void>()
+  {
+
+    public Object apply(Object value, Void p)
+    {
+      return value;
+    }
+
+  };
+
+
+
+  /**
+   * Returns a function which which always invokes {@code function} with {@code
+   * p}.
+   *
+   * @param <M>
+   *          The type of input values transformed by this function.
+   * @param <N>
+   *          The type of output values return by this function.
+   * @param <P>
+   *          The type of the additional parameter to this function's {@code
+   *          apply} method. Use {@link java.lang.Void} for functions that do
+   *          not need an additional parameter.
+   * @param function
+   *          The function to wrap.
+   * @param p
+   *          The parameter which will always be passed to {@code function}.
+   * @return A function which which always invokes {@code function} with {@code
+   *         p}.
+   */
+  public static <M, N, P> Function<M, N, Void> fixedFunction(
+      final Function<M, N, P> function, final P p)
+  {
+    return new FixedFunction<M, N, P>(function, p);
+  }
+
+
+
+  /**
+   * Returns a function which always returns the value that it was provided
+   * with.
+   *
+   * @param <M>
+   *          The type of values transformed by this function.
+   * @return A function which always returns the value that it was provided
+   *         with.
+   */
+  @SuppressWarnings("unchecked")
+  public static <M> Function<M, M, Void> identityFunction()
+  {
+    return (Function<M, M, Void>) IDENTITY;
+  }
+
+
+
+  /**
+   * Returns a function which converts a {@code String} to lower case using
+   * {@link StaticUtils#toLowerCase} and then trims it.
+   *
+   * @return A function which converts a {@code String} to lower case using
+   *         {@link StaticUtils#toLowerCase} and then trims it.
+   */
+  public static Function<String, String, Void> normalizeString()
+  {
+    return NORMALIZE_STRING;
+  }
+
+
+
+  /**
+   * Returns a function which converts an {@code Object} to a {@code ByteString}
+   * using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @return A function which converts an {@code Object} to a {@code ByteString}
+   *         .
+   */
+  public static Function<Object, ByteString, Void> objectToByteString()
+  {
+    return OBJECT_TO_BYTESTRING;
+  }
+
+
+
+  /**
+   * Returns a function which parses the string representation of a {@code
+   * ByteString} as an {@code AttributeDescription} using the default schema.
+   * Invalid values will result in a {@code LocalizedIllegalArgumentException}.
+   *
+   * @return A function which parses the string representation of a {@code
+   *         ByteString} as an {@code AttributeDescription}.
+   */
+  public static Function<ByteString, AttributeDescription, Void> valueToAttributeDescription()
+  {
+    return fixedFunction(BYTESTRING_TO_ATTRIBUTE_DESCRIPTION, Schema
+        .getDefaultSchema());
+  }
+
+
+
+  /**
+   * Returns a function which parses the string representation of a {@code
+   * ByteString} as an {@code AttributeDescription} using the provided schema.
+   * Invalid values will result in a {@code LocalizedIllegalArgumentException}.
+   *
+   * @param schema
+   *          The schema to use for decoding attribute descriptions.
+   * @return A function which parses the string representation of a {@code
+   *         ByteString} as an {@code AttributeDescription}.
+   */
+  public static Function<ByteString, AttributeDescription, Void> valueToAttributeDescription(
+      final Schema schema)
+  {
+    return fixedFunction(BYTESTRING_TO_ATTRIBUTE_DESCRIPTION, schema);
+  }
+
+
+
+  /**
+   * Returns a function which parses the string representation of a {@code
+   * ByteString} to a {@code Boolean}. The function will accept the values
+   * {@code 0}, {@code false}, {@code no}, {@code off}, {@code 1}, {@code true},
+   * {@code yes}, {@code on}. All other values will result in a {@code
+   * NumberFormatException}.
+   *
+   * @return A function which transforms a {@code ByteString} to a {@code
+   *         Boolean}.
+   */
+  public static Function<ByteString, Boolean, Void> valueToBoolean()
+  {
+    return BYTESTRING_TO_BOOLEAN;
+  }
+
+
+
+  /**
+   * Returns a function which parses the string representation of a {@code
+   * ByteString} as a {@code DN} using the default schema. Invalid values will
+   * result in a {@code LocalizedIllegalArgumentException}.
+   *
+   * @return A function which parses the string representation of a {@code
+   *         ByteString} as an {@code DN}.
+   */
+  public static Function<ByteString, DN, Void> valueToDN()
+  {
+    return fixedFunction(BYTESTRING_TO_DN, Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Returns a function which parses the string representation of a {@code
+   * ByteString} as a {@code DN} using the provided schema. Invalid values will
+   * result in a {@code LocalizedIllegalArgumentException}.
+   *
+   * @param schema
+   *          The schema to use for decoding DNs.
+   * @return A function which parses the string representation of a {@code
+   *         ByteString} as an {@code DN}.
+   */
+  public static Function<ByteString, DN, Void> valueToDN(final Schema schema)
+  {
+    return fixedFunction(BYTESTRING_TO_DN, schema);
+  }
+
+
+
+  /**
+   * Returns a function which parses the string representation of a {@code
+   * ByteString} as an {@code Integer}. Invalid values will result in a {@code
+   * NumberFormatException}.
+   *
+   * @return A function which parses the string representation of a {@code
+   *         ByteString} as an {@code Integer}.
+   */
+  public static Function<ByteString, Integer, Void> valueToInteger()
+  {
+    return BYTESTRING_TO_INTEGER;
+  }
+
+
+
+  /**
+   * Returns a function which parses the string representation of a {@code
+   * ByteString} as a {@code Long}. Invalid values will result in a {@code
+   * NumberFormatException}.
+   *
+   * @return A function which parses the string representation of a {@code
+   *         ByteString} as a {@code Long}.
+   */
+  public static Function<ByteString, Long, Void> valueToLong()
+  {
+    return BYTESTRING_TO_LONG;
+  }
+
+
+
+  /**
+   * Returns a function which parses a {@code ByteString} as a UTF-8 encoded
+   * {@code String}.
+   *
+   * @return A function which parses the string representation of a {@code
+   *         ByteString} as a UTF-8 encoded {@code String}.
+   */
+  public static Function<ByteString, String, Void> valueToString()
+  {
+    return BYTESTRING_TO_STRING;
+  }
+
+
+
+  // Prevent instantiation
+  private Functions()
+  {
+    // Do nothing.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/FutureResultTransformer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/FutureResultTransformer.java
new file mode 100644
index 0000000..07ba47e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/FutureResultTransformer.java
@@ -0,0 +1,243 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.FutureResult;
+import org.opends.sdk.ResultHandler;
+
+
+
+/**
+ * An implementation of the {@code FutureResult} interface which transforms the
+ * result of an asynchronous operation from one type to another. The
+ * implementation ensures that the transformed is computed only once.
+ *
+ * @param <M>
+ *          The type of the inner result.
+ * @param <N>
+ *          The type of the outer result.
+ */
+public abstract class FutureResultTransformer<M, N> implements FutureResult<N>,
+    ResultHandler<M>
+{
+
+  private final ResultHandler<? super N> handler;
+
+  private volatile FutureResult<? extends M> future = null;
+
+  // These do not need to be volatile since the future acts as a memory
+  // barrier.
+  private N transformedResult = null;
+
+  private ErrorResultException transformedErrorResult = null;
+
+
+
+  /**
+   * Creates a new result transformer which will transform the results of an
+   * inner asynchronous request.
+   *
+   * @param handler
+   *          The outer result handler.
+   */
+  protected FutureResultTransformer(final ResultHandler<? super N> handler)
+  {
+    this.handler = handler;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean cancel(final boolean mayInterruptIfRunning)
+  {
+    return future.cancel(mayInterruptIfRunning);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final N get() throws ErrorResultException, InterruptedException
+  {
+    future.get();
+
+    // The handlers are guaranteed to have been invoked at this point.
+    return get0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final N get(final long timeout, final TimeUnit unit)
+      throws ErrorResultException, TimeoutException, InterruptedException
+  {
+    future.get(timeout, unit);
+
+    // The handlers are guaranteed to have been invoked at this point.
+    return get0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final int getRequestID()
+  {
+    return future.getRequestID();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final void handleErrorResult(final ErrorResultException error)
+  {
+    transformedErrorResult = transformErrorResult(error);
+    if (handler != null)
+    {
+      handler.handleErrorResult(transformedErrorResult);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final void handleResult(final M result)
+  {
+    try
+    {
+      transformedResult = transformResult(result);
+      if (handler != null)
+      {
+        handler.handleResult(transformedResult);
+      }
+    }
+    catch (final ErrorResultException e)
+    {
+      transformedErrorResult = e;
+      if (handler != null)
+      {
+        handler.handleErrorResult(transformedErrorResult);
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isCancelled()
+  {
+    return future.isCancelled();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isDone()
+  {
+    return future.isDone();
+  }
+
+
+
+  /**
+   * Sets the inner future for this result transformer. This must be done before
+   * this future is published.
+   *
+   * @param future
+   *          The inner future.
+   */
+  public final void setFutureResult(final FutureResult<? extends M> future)
+  {
+    this.future = future;
+  }
+
+
+
+  /**
+   * Transforms the inner error result to an outer error result. The default
+   * implementation is to return the inner error result.
+   *
+   * @param errorResult
+   *          The inner error result.
+   * @return The outer error result.
+   */
+  protected ErrorResultException transformErrorResult(
+      final ErrorResultException errorResult)
+  {
+    return errorResult;
+  }
+
+
+
+  /**
+   * Transforms the inner result to an outer result, possibly throwing an
+   * {@code ErrorResultException} if the transformation fails for some reason.
+   *
+   * @param result
+   *          The inner result.
+   * @return The outer result.
+   * @throws ErrorResultException
+   *           If the transformation fails for some reason.
+   */
+  protected abstract N transformResult(M result) throws ErrorResultException;
+
+
+
+  private N get0() throws ErrorResultException
+  {
+    if (transformedErrorResult != null)
+    {
+      throw transformedErrorResult;
+    }
+    else
+    {
+      return transformedResult;
+    }
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterables.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterables.java
new file mode 100644
index 0000000..c3e3d66
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterables.java
@@ -0,0 +1,393 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.Iterator;
+
+
+
+/**
+ * Utility methods for manipulating {@link Iterable}s.
+ */
+public final class Iterables
+{
+  private static final class ArrayIterable<M> implements Iterable<M>
+  {
+
+    private final M[] a;
+
+
+
+    // Constructed via factory methods.
+    private ArrayIterable(final M[] a)
+    {
+      this.a = a;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<M> iterator()
+    {
+      return Iterators.arrayIterator(a);
+    }
+
+  }
+
+
+
+  private static final class EmptyIterable<M> implements Iterable<M>
+  {
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<M> iterator()
+    {
+      return Iterators.emptyIterator();
+    }
+
+  }
+
+
+
+  private static final class FilteredIterable<M, P> implements Iterable<M>
+  {
+
+    private final Iterable<M> iterable;
+    private final P parameter;
+    private final Predicate<? super M, P> predicate;
+
+
+
+    // Constructed via factory methods.
+    private FilteredIterable(final Iterable<M> iterable,
+        final Predicate<? super M, P> predicate, final P p)
+    {
+      this.iterable = iterable;
+      this.predicate = predicate;
+      this.parameter = p;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<M> iterator()
+    {
+      return Iterators.filteredIterator(iterable.iterator(), predicate, parameter);
+    }
+
+  }
+
+
+
+  private static final class SingletonIterable<M> implements Iterable<M>
+  {
+
+    private final M value;
+
+
+
+    // Constructed via factory methods.
+    private SingletonIterable(final M value)
+    {
+      this.value = value;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<M> iterator()
+    {
+      return Iterators.singletonIterator(value);
+    }
+
+  }
+
+
+
+  private static final class TransformedIterable<M, N, P> implements
+      Iterable<N>
+  {
+
+    private final Function<? super M, ? extends N, P> function;
+    private final Iterable<M> iterable;
+    private final P parameter;
+
+
+
+    // Constructed via factory methods.
+    private TransformedIterable(final Iterable<M> iterable,
+        final Function<? super M, ? extends N, P> function, final P p)
+    {
+      this.iterable = iterable;
+      this.function = function;
+      this.parameter = p;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<N> iterator()
+    {
+      return Iterators.transformedIterator(iterable.iterator(), function, parameter);
+    }
+
+  }
+
+
+
+  private static final class UnmodifiableIterable<M> implements Iterable<M>
+  {
+
+    private final Iterable<M> iterable;
+
+
+
+    // Constructed via factory methods.
+    private UnmodifiableIterable(final Iterable<M> iterable)
+    {
+      this.iterable = iterable;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<M> iterator()
+    {
+      return Iterators.unmodifiableIterator(iterable.iterator());
+    }
+
+  }
+
+
+
+  private static final Iterable<Object> EMPTY_ITERABLE = new EmptyIterable<Object>();
+
+
+
+  /**
+   * Returns an iterable containing the elements of {@code a}. The returned
+   * iterable's iterator does not support element removal via the
+   * {@code remove()} method.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code a}.
+   * @param a
+   *          The array of elements.
+   * @return An iterable containing the elements of {@code a}.
+   */
+  public static <M> Iterable<M> arrayIterable(final M[] a)
+  {
+    return new ArrayIterable<M>(a);
+  }
+
+
+
+  /**
+   * Returns an immutable empty iterable.
+   *
+   * @param <M>
+   *          The required type of the empty iterable.
+   * @return An immutable empty iterable.
+   */
+  @SuppressWarnings("unchecked")
+  public static <M> Iterable<M> emptyIterable()
+  {
+    return (Iterable<M>) EMPTY_ITERABLE;
+  }
+
+
+
+  /**
+   * Returns a filtered view of {@code iterable} containing only those elements
+   * which match {@code predicate}. The returned iterable's iterator supports
+   * element removal via the {@code remove()} method subject to any constraints
+   * imposed by {@code iterable}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterable}.
+   * @param <P>
+   *          The type of the additional parameter to the predicate's
+   *          {@code matches} method. Use {@link java.lang.Void} for predicates
+   *          that do not need an additional parameter.
+   * @param iterable
+   *          The iterable to be filtered.
+   * @param predicate
+   *          The predicate.
+   * @param p
+   *          A predicate specified parameter.
+   * @return A filtered view of {@code iterable} containing only those elements
+   *         which match {@code predicate}.
+   */
+  public static <M, P> Iterable<M> filteredIterable(final Iterable<M> iterable,
+      final Predicate<? super M, P> predicate, final P p)
+  {
+    return new FilteredIterable<M, P>(iterable, predicate, p);
+  }
+
+
+
+  /**
+   * Returns a filtered view of {@code iterable} containing only those elements
+   * which match {@code predicate}. The returned iterable's iterator supports
+   * element removal via the {@code remove()} method subject to any constraints
+   * imposed by {@code iterable}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterable}.
+   * @param iterable
+   *          The iterable to be filtered.
+   * @param predicate
+   *          The predicate.
+   * @return A filtered view of {@code iterable} containing only those elements
+   *         which match {@code predicate}.
+   */
+  public static <M> Iterable<M> filteredIterable(final Iterable<M> iterable,
+      final Predicate<? super M, Void> predicate)
+  {
+    return new FilteredIterable<M, Void>(iterable, predicate, null);
+  }
+
+
+
+  /**
+   * Returns an iterable containing the single element {@code value}. The
+   * returned iterable's iterator does not support element removal via the
+   * {@code remove()} method.
+   *
+   * @param <M>
+   *          The type of the single element {@code value}.
+   * @param value
+   *          The single element.
+   * @return An iterable containing the single element {@code value}.
+   */
+  public static <M> Iterable<M> singletonIterable(final M value)
+  {
+    return new SingletonIterable<M>(value);
+  }
+
+
+
+  /**
+   * Returns a view of {@code iterable} whose values have been mapped to
+   * elements of type {@code N} using {@code function}. The returned iterable's
+   * iterator supports element removal via the {@code remove()} method subject
+   * to any constraints imposed by {@code iterable}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterable}.
+   * @param <N>
+   *          The type of elements contained in the returned iterable.
+   * @param <P>
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
+   * @param iterable
+   *          The iterable to be transformed.
+   * @param function
+   *          The function.
+   * @param p
+   *          A predicate specified parameter.
+   * @return A view of {@code iterable} whose values have been mapped to
+   *         elements of type {@code N} using {@code function}.
+   */
+  public static <M, N, P> Iterable<N> transformedIterable(
+      final Iterable<M> iterable,
+      final Function<? super M, ? extends N, P> function, final P p)
+  {
+    return new TransformedIterable<M, N, P>(iterable, function, p);
+  }
+
+
+
+  /**
+   * Returns a view of {@code iterable} whose values have been mapped to
+   * elements of type {@code N} using {@code function}. The returned iterable's
+   * iterator supports element removal via the {@code remove()} method subject
+   * to any constraints imposed by {@code iterable}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterable}.
+   * @param <N>
+   *          The type of elements contained in the returned iterable.
+   * @param iterable
+   *          The iterable to be transformed.
+   * @param function
+   *          The function.
+   * @return A view of {@code iterable} whose values have been mapped to
+   *         elements of type {@code N} using {@code function}.
+   */
+  public static <M, N> Iterable<N> transformedIterable(
+      final Iterable<M> iterable,
+      final Function<? super M, ? extends N, Void> function)
+  {
+    return new TransformedIterable<M, N, Void>(iterable, function, null);
+  }
+
+
+
+  /**
+   * Returns a read-only view of {@code iterable} whose iterator does not
+   * support element removal via the {@code remove()}. Attempts to use the
+   * {@code remove()} method will result in a
+   * {@code UnsupportedOperationException}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterable}.
+   * @param iterable
+   *          The iterable to be made read-only.
+   * @return A read-only view of {@code iterable} whose iterator does not
+   *         support element removal via the {@code remove()}.
+   */
+  public static <M> Iterable<M> unmodifiableIterable(final Iterable<M> iterable)
+  {
+    return new UnmodifiableIterable<M>(iterable);
+  }
+
+
+
+  // Prevent instantiation
+  private Iterables()
+  {
+    // Do nothing.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterators.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterators.java
new file mode 100644
index 0000000..e58e1e0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Iterators.java
@@ -0,0 +1,547 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+
+
+/**
+ * Utility methods for manipulating {@link Iterator}s.
+ */
+public final class Iterators
+{
+  private static final class ArrayIterator<M> implements Iterator<M>
+  {
+    private int i = 0;
+    private final M[] a;
+
+
+
+    // Constructed via factory methods.
+    private ArrayIterator(final M[] a)
+    {
+      this.a = a;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext()
+    {
+      return i < a.length;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public M next()
+    {
+      if (hasNext())
+      {
+        return a[i++];
+      }
+      else
+      {
+        throw new NoSuchElementException();
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+
+  };
+
+
+
+  private static final class EmptyIterator<M> implements Iterator<M>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext()
+    {
+      return false;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public M next()
+    {
+      throw new NoSuchElementException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+
+
+  private static final class FilteredIterator<M, P> implements Iterator<M>
+  {
+
+    private boolean hasNextMustIterate = true;
+    private final Iterator<M> iterator;
+    private M next = null;
+
+    private final P parameter;
+    private final Predicate<? super M, P> predicate;
+
+
+
+    // Constructed via factory methods.
+    private FilteredIterator(final Iterator<M> iterator,
+        final Predicate<? super M, P> predicate, final P p)
+    {
+      this.iterator = iterator;
+      this.predicate = predicate;
+      this.parameter = p;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext()
+    {
+      if (hasNextMustIterate)
+      {
+        hasNextMustIterate = false;
+        while (iterator.hasNext())
+        {
+          next = iterator.next();
+          if (predicate.matches(next, parameter))
+          {
+            return true;
+          }
+        }
+        next = null;
+        return false;
+      }
+      else
+      {
+        return next != null;
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public M next()
+    {
+      if (!hasNext())
+      {
+        throw new NoSuchElementException();
+      }
+      hasNextMustIterate = true;
+      return next;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove()
+    {
+      iterator.remove();
+    }
+
+  }
+
+
+
+  private static final class SingletonIterator<M> implements Iterator<M>
+  {
+    private M value;
+
+
+
+    // Constructed via factory methods.
+    private SingletonIterator(final M value)
+    {
+      this.value = value;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext()
+    {
+      return value != null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public M next()
+    {
+      if (value != null)
+      {
+        final M tmp = value;
+        value = null;
+        return tmp;
+      }
+      else
+      {
+        throw new NoSuchElementException();
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+
+  }
+
+
+
+  private static final class TransformedIterator<M, N, P> implements
+      Iterator<N>
+  {
+
+    private final Function<? super M, ? extends N, P> function;
+    private final Iterator<M> iterator;
+    private final P parameter;
+
+
+
+    // Constructed via factory methods.
+    private TransformedIterator(final Iterator<M> iterator,
+        final Function<? super M, ? extends N, P> function, final P p)
+    {
+      this.iterator = iterator;
+      this.function = function;
+      this.parameter = p;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext()
+    {
+      return iterator.hasNext();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public N next()
+    {
+      return function.apply(iterator.next(), parameter);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove()
+    {
+      iterator.remove();
+    }
+
+  }
+
+
+
+  private static final class UnmodifiableIterator<M> implements Iterator<M>
+  {
+    private final Iterator<M> iterator;
+
+
+
+    private UnmodifiableIterator(final Iterator<M> iterator)
+    {
+      this.iterator = iterator;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext()
+    {
+      return iterator.hasNext();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public M next()
+    {
+      return iterator.next();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+
+
+  private static final Iterator<Object> EMPTY_ITERATOR = new EmptyIterator<Object>();
+
+
+
+  /**
+   * Returns an iterator over the elements contained in {@code a}. The returned
+   * iterator does not support element removal via the {@code remove()} method.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code a}.
+   * @param a
+   *          The array of elements to be returned by the iterator.
+   * @return An iterator over the elements contained in {@code a}.
+   */
+  public static <M> Iterator<M> arrayIterator(final M[] a)
+  {
+    return new ArrayIterator<M>(a);
+  }
+
+
+
+  /**
+   * Returns an immutable empty iterator.
+   *
+   * @param <M>
+   *          The required type of the empty iterator.
+   * @return An immutable empty iterator.
+   */
+  @SuppressWarnings("unchecked")
+  public static <M> Iterator<M> emptyIterator()
+  {
+    return (Iterator<M>) EMPTY_ITERATOR;
+  }
+
+
+
+  /**
+   * Returns a filtered view of {@code iterator} containing only those elements
+   * which match {@code predicate}. The returned iterator supports element
+   * removal via the {@code remove()} method subject to any constraints imposed
+   * by {@code iterator}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterator}.
+   * @param <P>
+   *          The type of the additional parameter to the predicate's
+   *          {@code matches} method. Use {@link java.lang.Void} for predicates
+   *          that do not need an additional parameter.
+   * @param iterator
+   *          The iterator to be filtered.
+   * @param predicate
+   *          The predicate.
+   * @param p
+   *          A predicate specified parameter.
+   * @return A filtered view of {@code iterator} containing only those elements
+   *         which match {@code predicate}.
+   */
+  public static <M, P> Iterator<M> filteredIterator(final Iterator<M> iterator,
+      final Predicate<? super M, P> predicate, final P p)
+  {
+    return new FilteredIterator<M, P>(iterator, predicate, p);
+  }
+
+
+
+  /**
+   * Returns a filtered view of {@code iterator} containing only those elements
+   * which match {@code predicate}. The returned iterator supports element
+   * removal via the {@code remove()} method subject to any constraints imposed
+   * by {@code iterator}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterator}.
+   * @param iterator
+   *          The iterator to be filtered.
+   * @param predicate
+   *          The predicate.
+   * @return A filtered view of {@code iterator} containing only those elements
+   *         which match {@code predicate}.
+   */
+  public static <M> Iterator<M> filteredIterator(final Iterator<M> iterator,
+      final Predicate<? super M, Void> predicate)
+  {
+    return new FilteredIterator<M, Void>(iterator, predicate, null);
+  }
+
+
+
+  /**
+   * Returns an iterator containing the single element {@code value}. The
+   * returned iterator does not support element removal via the {@code remove()}
+   * method.
+   *
+   * @param <M>
+   *          The type of the single element {@code value}.
+   * @param value
+   *          The single element to be returned by the iterator.
+   * @return An iterator containing the single element {@code value}.
+   */
+  public static <M> Iterator<M> singletonIterator(final M value)
+  {
+    return new SingletonIterator<M>(value);
+  }
+
+
+
+  /**
+   * Returns a view of {@code iterator} whose values have been mapped to
+   * elements of type {@code N} using {@code function}. The returned iterator
+   * supports element removal via the {@code remove()} method subject to any
+   * constraints imposed by {@code iterator}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterator}.
+   * @param <N>
+   *          The type of elements contained in the returned iterator.
+   * @param <P>
+   *          The type of the additional parameter to the function's
+   *          {@code apply} method. Use {@link java.lang.Void} for functions
+   *          that do not need an additional parameter.
+   * @param iterator
+   *          The iterator to be transformed.
+   * @param function
+   *          The function.
+   * @param p
+   *          A predicate specified parameter.
+   * @return A view of {@code iterator} whose values have been mapped to
+   *         elements of type {@code N} using {@code function}.
+   */
+  public static <M, N, P> Iterator<N> transformedIterator(
+      final Iterator<M> iterator,
+      final Function<? super M, ? extends N, P> function, final P p)
+  {
+    return new TransformedIterator<M, N, P>(iterator, function, p);
+  }
+
+
+
+  /**
+   * Returns a view of {@code iterator} whose values have been mapped to
+   * elements of type {@code N} using {@code function}. The returned iterator
+   * supports element removal via the {@code remove()} method subject to any
+   * constraints imposed by {@code iterator}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterator}.
+   * @param <N>
+   *          The type of elements contained in the returned iterator.
+   * @param iterator
+   *          The iterator to be transformed.
+   * @param function
+   *          The function.
+   * @return A view of {@code iterator} whose values have been mapped to
+   *         elements of type {@code N} using {@code function}.
+   */
+  public static <M, N> Iterator<N> transformedIterator(
+      final Iterator<M> iterator,
+      final Function<? super M, ? extends N, Void> function)
+  {
+    return new TransformedIterator<M, N, Void>(iterator, function, null);
+  }
+
+
+
+  /**
+   * Returns a read-only view of {@code iterator} which does not support element
+   * removal via the {@code remove()}. Attempts to use the {@code remove()}
+   * method will result in a {@code UnsupportedOperationException}.
+   *
+   * @param <M>
+   *          The type of elements contained in {@code iterator}.
+   * @param iterator
+   *          The iterator to be made read-only.
+   * @return A read-only view of {@code iterator} which does not support element
+   *         removal via the {@code remove()}.
+   */
+  public static <M> Iterator<M> unmodifiableIterator(final Iterator<M> iterator)
+  {
+    return new UnmodifiableIterator<M>(iterator);
+  }
+
+
+
+  // Prevent instantiation
+  private Iterators()
+  {
+    // Do nothing.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/LocalizableMessageDescriptor.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/LocalizableMessageDescriptor.java
new file mode 100755
index 0000000..8bb04eb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/LocalizableMessageDescriptor.java
@@ -0,0 +1,1091 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * An opaque handle to a localizable message.
+ */
+public abstract class LocalizableMessageDescriptor
+{
+  /**
+   * Subclass for creating messages with no arguments.
+   */
+  public static final class Arg0 extends LocalizableMessageDescriptor
+  {
+
+    /**
+     * Cached copy of the message created by this descriptor. We can get away
+     * with this for the zero argument message because it is immutable.
+     */
+    private final LocalizableMessage message;
+
+    private final boolean requiresFormat;
+
+
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg0(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+      message = newMessage(this);
+      requiresFormat = containsArgumentLiterals(getFormatString());
+    }
+
+
+
+    /**
+     * Creates a message.
+     *
+     * @return LocalizableMessage object
+     */
+    public LocalizableMessage get()
+    {
+      return message;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return requiresFormat;
+    }
+  }
+
+
+
+  /**
+   * Subclass for creating messages with one argument.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   */
+  public static final class Arg1<T1> extends LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg1(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1)
+    {
+      return newMessage(this, a1);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with two arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   */
+  public static final class Arg2<T1, T2> extends LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg2(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2)
+    {
+      return newMessage(this, a1, a2);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with three arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   * @param <T3>
+   *          The type of the third message argument.
+   */
+  public static final class Arg3<T1, T2, T3> extends
+      LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg3(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     * @param a3
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2, final T3 a3)
+    {
+      return newMessage(this, a1, a2, a3);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with four arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   * @param <T3>
+   *          The type of the third message argument.
+   * @param <T4>
+   *          The type of the fourth message argument.
+   */
+  public static final class Arg4<T1, T2, T3, T4> extends
+      LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg4(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     * @param a3
+     *          message argument
+     * @param a4
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2, final T3 a3,
+        final T4 a4)
+    {
+      return newMessage(this, a1, a2, a3, a4);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with five arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   * @param <T3>
+   *          The type of the third message argument.
+   * @param <T4>
+   *          The type of the fourth message argument.
+   * @param <T5>
+   *          The type of the fifth message argument.
+   */
+  public static final class Arg5<T1, T2, T3, T4, T5> extends
+      LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg5(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     * @param a3
+     *          message argument
+     * @param a4
+     *          message argument
+     * @param a5
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2, final T3 a3,
+        final T4 a4, final T5 a5)
+    {
+      return newMessage(this, a1, a2, a3, a4, a5);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with six arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   * @param <T3>
+   *          The type of the third message argument.
+   * @param <T4>
+   *          The type of the fourth message argument.
+   * @param <T5>
+   *          The type of the fifth message argument.
+   * @param <T6>
+   *          The type of the sixth message argument.
+   */
+  public static final class Arg6<T1, T2, T3, T4, T5, T6> extends
+      LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg6(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     * @param a3
+     *          message argument
+     * @param a4
+     *          message argument
+     * @param a5
+     *          message argument
+     * @param a6
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2, final T3 a3,
+        final T4 a4, final T5 a5, final T6 a6)
+    {
+      return newMessage(this, a1, a2, a3, a4, a5, a6);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with seven arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   * @param <T3>
+   *          The type of the third message argument.
+   * @param <T4>
+   *          The type of the fourth message argument.
+   * @param <T5>
+   *          The type of the fifth message argument.
+   * @param <T6>
+   *          The type of the sixth message argument.
+   * @param <T7>
+   *          The type of the seventh message argument.
+   */
+  public static final class Arg7<T1, T2, T3, T4, T5, T6, T7> extends
+      LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg7(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     * @param a3
+     *          message argument
+     * @param a4
+     *          message argument
+     * @param a5
+     *          message argument
+     * @param a6
+     *          message argument
+     * @param a7
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2, final T3 a3,
+        final T4 a4, final T5 a5, final T6 a6, final T7 a7)
+    {
+      return newMessage(this, a1, a2, a3, a4, a5, a6, a7);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with eight arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   * @param <T3>
+   *          The type of the third message argument.
+   * @param <T4>
+   *          The type of the fourth message argument.
+   * @param <T5>
+   *          The type of the fifth message argument.
+   * @param <T6>
+   *          The type of the sixth message argument.
+   * @param <T7>
+   *          The type of the seventh message argument.
+   * @param <T8>
+   *          The type of the eighth message argument.
+   */
+  public static final class Arg8<T1, T2, T3, T4, T5, T6, T7, T8> extends
+      LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg8(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     * @param a3
+     *          message argument
+     * @param a4
+     *          message argument
+     * @param a5
+     *          message argument
+     * @param a6
+     *          message argument
+     * @param a7
+     *          message argument
+     * @param a8
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2, final T3 a3,
+        final T4 a4, final T5 a5, final T6 a6, final T7 a7, final T8 a8)
+    {
+      return newMessage(this, a1, a2, a3, a4, a5, a6, a7, a8);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with nine arguments.
+   *
+   * @param <T1>
+   *          The type of the first message argument.
+   * @param <T2>
+   *          The type of the second message argument.
+   * @param <T3>
+   *          The type of the third message argument.
+   * @param <T4>
+   *          The type of the fourth message argument.
+   * @param <T5>
+   *          The type of the fifth message argument.
+   * @param <T6>
+   *          The type of the sixth message argument.
+   * @param <T7>
+   *          The type of the seventh message argument.
+   * @param <T8>
+   *          The type of the eighth message argument.
+   * @param <T9>
+   *          The type of the ninth message argument.
+   */
+  public static final class Arg9<T1, T2, T3, T4, T5, T6, T7, T8, T9> extends
+      LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public Arg9(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param a1
+     *          message argument
+     * @param a2
+     *          message argument
+     * @param a3
+     *          message argument
+     * @param a4
+     *          message argument
+     * @param a5
+     *          message argument
+     * @param a6
+     *          message argument
+     * @param a7
+     *          message argument
+     * @param a8
+     *          message argument
+     * @param a9
+     *          message argument
+     */
+    public LocalizableMessage get(final T1 a1, final T2 a2, final T3 a3,
+        final T4 a4, final T5 a5, final T6 a6, final T7 a7, final T8 a8,
+        final T9 a9)
+    {
+      return newMessage(this, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Subclass for creating messages with an any number of arguments. In general
+   * this class should be used when a message needs to be defined with more
+   * arguments that can be handled with the current number of subclasses
+   */
+  public static final class ArgN extends LocalizableMessageDescriptor
+  {
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param rbBase
+     *          base of the backing resource bundle
+     * @param key
+     *          for accessing the format string from the resource bundle
+     * @param classLoader
+     *          the class loader to be used to get the ResourceBundle
+     */
+    public ArgN(final String rbBase, final String key,
+        final ClassLoader classLoader)
+    {
+      super(rbBase, key, classLoader);
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param args
+     *          message arguments
+     */
+    public LocalizableMessage get(final Object... args)
+    {
+      return newMessage(this, args);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return true;
+    }
+
+  }
+
+
+
+  /**
+   * Factory interface for creating messages. Only LocalizableMessage should
+   * implement this.
+   */
+  public static interface MessageFactory
+  {
+    /**
+     * Creates a new parameterized message instance.
+     *
+     * @param descriptor
+     *          The message descriptor.
+     * @param args
+     *          The message parameters.
+     * @return The new message.
+     */
+    LocalizableMessage newMessage(LocalizableMessageDescriptor descriptor,
+        Object... args);
+  }
+
+
+
+  /**
+   * A descriptor for creating a raw message from a <code>String</code>. In
+   * general this descriptor should NOT be used internally. OpenDS plugins may
+   * want to use the mechanism to create messages without storing their strings
+   * in resource bundles.
+   */
+  public static final class Raw extends LocalizableMessageDescriptor
+  {
+
+    private final String formatString;
+
+    private final boolean requiresFormatter;
+
+
+
+    /**
+     * Creates a parameterized instance.
+     *
+     * @param formatString
+     *          for created messages
+     */
+    public Raw(final CharSequence formatString)
+    {
+      super(null, null, null);
+      this.formatString = formatString != null ? formatString.toString() : "";
+      this.requiresFormatter = this.formatString.matches(".*%.*");
+    }
+
+
+
+    /**
+     * Creates a message with arguments that will replace format specifiers in
+     * the assocated format string when the message is rendered to string
+     * representation.
+     *
+     * @return LocalizableMessage object
+     * @param args
+     *          message arguments
+     */
+    public LocalizableMessage get(final Object... args)
+    {
+      return newMessage(this, args);
+    }
+
+
+
+    /**
+     * Overridden in order to bypass the resource bundle plumbing and return the
+     * format string directly.
+     *
+     * @param locale
+     *          ignored
+     * @return format string
+     */
+    @Override
+    public String getFormatString(final Locale locale)
+    {
+      return this.formatString;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean requiresFormatter()
+    {
+      return this.requiresFormatter;
+    }
+
+  }
+
+
+
+  // Container for caching the last locale specific format string.
+  private static final class CachedFormatString
+  {
+    private final Locale locale;
+
+    private final String formatString;
+
+
+
+    private CachedFormatString(final Locale locale, final String formatString)
+    {
+      this.locale = locale;
+      this.formatString = formatString;
+    }
+  }
+
+
+
+  /**
+   * We use a factory for creating LocalizableMessage objects in order to avoid
+   * exposing this class in the public API.
+   */
+  public static MessageFactory messageFactory;
+
+  // Force messageFactory to be set.
+  static
+  {
+    try
+    {
+      Class.forName("org.opends.sdk.LocalizableMessage");
+    }
+    catch (final ClassNotFoundException e)
+    {
+      throw new RuntimeException(e);
+    }
+  }
+
+
+
+  /**
+   * Indicates whether or not formatting should be applied to the given format
+   * string. Note that a format string might have literal specifiers (%% or %n
+   * for example) that require formatting but are not replaced by arguments.
+   *
+   * @param s
+   *          candidate for formatting
+   * @return boolean where true indicates that the format string requires
+   *         formatting
+   */
+  private static final boolean containsArgumentLiterals(final String s)
+  {
+    return s.matches(".*%[n|%].*"); // match Formatter literals
+  }
+
+
+
+  private static LocalizableMessage newMessage(
+      final LocalizableMessageDescriptor descriptor, final Object... args)
+  {
+    return messageFactory.newMessage(descriptor, args);
+  }
+
+
+
+  // String for accessing backing resource bundle.
+  private final String rbBase;
+
+  // Used for accessing format string from the resource bundle.
+  private final String key;
+
+  /*
+   * The class loader to be used to retrieve the ResourceBundle. If null the
+   * default class loader will be used.
+   */
+  private final ClassLoader classLoader;
+
+  // It's ok if there are race conditions.
+  private CachedFormatString cachedFormatString = null;
+
+
+
+  /**
+   * Creates a parameterized message descriptor.
+   *
+   * @param rbBase
+   *          string for accessing the underlying message bundle
+   * @param key
+   *          for accessing the format string from the message bundle
+   * @param classLoader
+   *          the class loader to be used to get the ResourceBundle
+   */
+  private LocalizableMessageDescriptor(final String rbBase, final String key,
+      final ClassLoader classLoader)
+  {
+    this.rbBase = rbBase;
+    this.key = key;
+    this.classLoader = classLoader;
+  }
+
+
+
+  /**
+   * Returns the format string which should be used when creating the string
+   * representation of this message using the specified locale.
+   *
+   * @param locale
+   *          The locale.
+   * @return The format string.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public String getFormatString(final Locale locale)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(locale);
+
+    // Fast path.
+    final CachedFormatString cfs = cachedFormatString;
+    if (cfs != null && cfs.locale == locale)
+    {
+      return cfs.formatString;
+    }
+
+    // There's a potential race condition here but it's benign - we'll
+    // just do a bit more work than needed.
+    final ResourceBundle bundle = getBundle(locale);
+    final String formatString = bundle.getString(key);
+    cachedFormatString = new CachedFormatString(locale, formatString);
+
+    return formatString;
+  }
+
+
+
+  /**
+   * Indicates whether or not this descriptor format string should be processed
+   * by {@code Formatter} during string rendering.
+   *
+   * @return {@code true} if a {@code Formatter} should be used, otherwise
+   *         {@code false}.
+   */
+  public abstract boolean requiresFormatter();
+
+
+
+  /**
+   * Returns the format string which should be used when creating the string
+   * representation of this message using the default locale.
+   *
+   * @return The format string.
+   */
+  final String getFormatString()
+  {
+    return getFormatString(Locale.getDefault());
+  }
+
+
+
+  private ResourceBundle getBundle(Locale locale)
+  {
+    if (locale == null)
+    {
+      locale = Locale.getDefault();
+    }
+    if (classLoader == null)
+    {
+      return ResourceBundle.getBundle(this.rbBase, locale);
+    }
+    else
+    {
+      return ResourceBundle.getBundle(this.rbBase, locale, classLoader);
+    }
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Predicate.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Predicate.java
new file mode 100644
index 0000000..34253e0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Predicate.java
@@ -0,0 +1,57 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+/**
+ * Predicates transform input values of type {@code M} to a boolean output value
+ * and are typically used for performing filtering.
+ *
+ * @param <M>
+ *          The type of input values matched by this predicate.
+ * @param <P>
+ *          The type of the additional parameter to this predicate's {@code
+ *          matches} method. Use {@link java.lang.Void} for predicates that do
+ *          not need an additional parameter.
+ */
+public interface Predicate<M, P>
+{
+  /**
+   * Indicates whether or not this predicate matches the provided input value of
+   * type {@code M}.
+   *
+   * @param value
+   *          The input value for which to make the determination.
+   * @param p
+   *          A predicate specified parameter.
+   * @return {@code true} if this predicate matches {@code value}, otherwise
+   *         {@code false}.
+   */
+  boolean matches(M value, P p);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/RecursiveFutureResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/RecursiveFutureResult.java
new file mode 100644
index 0000000..0857e0a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/RecursiveFutureResult.java
@@ -0,0 +1,274 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.FutureResult;
+import org.opends.sdk.ResultHandler;
+
+
+
+/**
+ * An implementation of the {@code FutureResult} interface which can be used to
+ * combine a sequence of two asynchronous operations into a single future
+ * result. Implementations should override the methods {@link #chainResult} and
+ * {@link #chainErrorResult} in order to define the second asynchronous
+ * operation.
+ *
+ * @param <M>
+ *          The type of the inner result.
+ * @param <N>
+ *          The type of the outer result.
+ */
+public abstract class RecursiveFutureResult<M, N> implements FutureResult<N>,
+    ResultHandler<M>
+{
+  private final class FutureResultImpl extends AsynchronousFutureResult<N>
+  {
+    private FutureResultImpl(final ResultHandler<? super N> handler)
+    {
+      super(handler);
+    }
+
+
+
+    public int getRequestID()
+    {
+      if (innerFuture instanceof FutureResult<?>)
+      {
+        final FutureResult<?> tmp = (FutureResult<?>) innerFuture;
+        return tmp.getRequestID();
+      }
+      else
+      {
+        return -1;
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected ErrorResultException handleCancelRequest(
+        final boolean mayInterruptIfRunning)
+    {
+      innerFuture.cancel(mayInterruptIfRunning);
+      if (outerFuture != null)
+      {
+        outerFuture.cancel(mayInterruptIfRunning);
+      }
+      return null;
+    }
+
+  }
+
+
+
+  private final FutureResultImpl impl;
+
+  private volatile Future<?> innerFuture = null;
+
+  // This does not need to be volatile since the inner future acts as a
+  // memory barrier.
+  private FutureResult<? extends N> outerFuture = null;
+
+
+
+  /**
+   * Creates a new asynchronous result chain which will chain an outer
+   * asynchronous request once the inner asynchronous request completes.
+   *
+   * @param handler
+   *          The outer result handler.
+   */
+  protected RecursiveFutureResult(final ResultHandler<? super N> handler)
+  {
+    this.impl = new FutureResultImpl(handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean cancel(final boolean mayInterruptIfRunning)
+  {
+    return impl.cancel(mayInterruptIfRunning);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final N get() throws ErrorResultException, InterruptedException
+  {
+    return impl.get();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final N get(final long timeout, final TimeUnit unit)
+      throws ErrorResultException, TimeoutException, InterruptedException
+  {
+    return impl.get(timeout, unit);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final int getRequestID()
+  {
+    return impl.getRequestID();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final void handleErrorResult(final ErrorResultException error)
+  {
+    try
+    {
+      outerFuture = chainErrorResult(error, impl);
+    }
+    catch (final ErrorResultException e)
+    {
+      impl.handleErrorResult(e);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final void handleResult(final M result)
+  {
+    try
+    {
+      outerFuture = chainResult(result, impl);
+    }
+    catch (final ErrorResultException e)
+    {
+      impl.handleErrorResult(e);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isCancelled()
+  {
+    return impl.isCancelled();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isDone()
+  {
+    return impl.isDone();
+  }
+
+
+
+  /**
+   * Sets the inner future for this result chain. This must be done before this
+   * future is published.
+   *
+   * @param future
+   *          The inner future.
+   */
+  public final void setFutureResult(final Future<?> future)
+  {
+    this.innerFuture = future;
+  }
+
+
+
+  /**
+   * Invokes the outer request based on the error result of the inner request
+   * and returns a future representing the result of the outer request.
+   * <p>
+   * The default implementation is to terminate further processing by
+   * re-throwing the inner error result.
+   *
+   * @param innerError
+   *          The error result of the inner request.
+   * @param handler
+   *          The result handler to be used for the outer request.
+   * @return A future representing the result of the outer request.
+   * @throws ErrorResultException
+   *           If the outer request could not be invoked and processing should
+   *           terminate.
+   */
+  protected FutureResult<? extends N> chainErrorResult(
+      final ErrorResultException innerError,
+      final ResultHandler<? super N> handler) throws ErrorResultException
+  {
+    throw innerError;
+  }
+
+
+
+  /**
+   * Invokes the outer request based on the result of the inner request and
+   * returns a future representing the result of the outer request.
+   *
+   * @param innerResult
+   *          The result of the inner request.
+   * @param handler
+   *          The result handler to be used for the outer request.
+   * @return A future representing the result of the outer request.
+   * @throws ErrorResultException
+   *           If the outer request could not be invoked and processing should
+   *           terminate.
+   */
+  protected abstract FutureResult<? extends N> chainResult(M innerResult,
+      ResultHandler<? super N> handler) throws ErrorResultException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SizeLimitInputStream.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SizeLimitInputStream.java
new file mode 100644
index 0000000..9bdf0ed
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SizeLimitInputStream.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
+ *
+ *
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.util;
+
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+
+
+/**
+ * An implementation of input stream that enforces an read size limit.
+ */
+public class SizeLimitInputStream extends InputStream
+{
+  private int bytesRead;
+  private int markBytesRead;
+  private final int readLimit;
+  private final InputStream parentStream;
+
+
+
+  /**
+   * Creates a new a new size limit input stream.
+   *
+   * @param parentStream
+   *          The parent stream.
+   * @param readLimit
+   *          The size limit.
+   */
+  public SizeLimitInputStream(final InputStream parentStream,
+      final int readLimit)
+  {
+    this.parentStream = parentStream;
+    this.readLimit = readLimit;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int available() throws IOException
+  {
+    final int streamAvail = parentStream.available();
+    final int limitedAvail = readLimit - bytesRead;
+    return limitedAvail < streamAvail ? limitedAvail : streamAvail;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close() throws IOException
+  {
+    parentStream.close();
+  }
+
+
+
+  /**
+   * Retrieves the number of bytes read from this stream.
+   *
+   * @return The number of bytes read from this stream.
+   */
+  public int getBytesRead()
+  {
+    return bytesRead;
+  }
+
+
+
+  /**
+   * Retrieves the size limit of this stream.
+   *
+   * @return The size limit of this stream.
+   */
+  public int getSizeLimit()
+  {
+    return readLimit;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public synchronized void mark(final int readlimit)
+  {
+    parentStream.mark(readlimit);
+    markBytesRead = bytesRead;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean markSupported()
+  {
+    return parentStream.markSupported();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int read() throws IOException
+  {
+    if (bytesRead >= readLimit)
+    {
+      return -1;
+    }
+
+    final int b = parentStream.read();
+    if (b != -1)
+    {
+      ++bytesRead;
+    }
+    return b;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int read(final byte b[], final int off, int len) throws IOException
+  {
+    if (off < 0 || len < 0 || off + len > b.length)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    if (len == 0)
+    {
+      return 0;
+    }
+
+    if (bytesRead >= readLimit)
+    {
+      return -1;
+    }
+
+    if (bytesRead + len > readLimit)
+    {
+      len = readLimit - bytesRead;
+    }
+
+    final int readLen = parentStream.read(b, off, len);
+    if (readLen > 0)
+    {
+      bytesRead += readLen;
+    }
+    return readLen;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public synchronized void reset() throws IOException
+  {
+    parentStream.reset();
+    bytesRead = markBytesRead;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public long skip(long n) throws IOException
+  {
+    if (bytesRead + n > readLimit)
+    {
+      n = readLimit - bytesRead;
+    }
+
+    bytesRead += n;
+    return parentStream.skip(n);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StaticUtils.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StaticUtils.java
new file mode 100644
index 0000000..64cdabb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StaticUtils.java
@@ -0,0 +1,2271 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_HEX_DECODE_INVALID_CHARACTER;
+import static com.sun.opends.sdk.messages.Messages.ERR_HEX_DECODE_INVALID_LENGTH;
+
+import java.lang.reflect.InvocationTargetException;
+import java.text.ParseException;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import org.opends.sdk.*;
+
+
+
+/**
+ * Common utility methods.
+ */
+public final class StaticUtils
+{
+  /**
+   * The debug logger which should be used by the SDK.
+   */
+  public static final Logger DEBUG_LOG = Logger.getLogger("org.opends.sdk");
+
+  /**
+   * The end-of-line character for this platform.
+   */
+  public static final String EOL = System.getProperty("line.separator");
+
+  // The name of the time zone for universal coordinated time (UTC).
+  private static final String TIME_ZONE_UTC = "UTC";
+
+  // UTC TimeZone is assumed to never change over JVM lifetime
+  private static final TimeZone TIME_ZONE_UTC_OBJ = TimeZone
+      .getTimeZone(TIME_ZONE_UTC);
+
+  private static ScheduledExecutorService defaultScheduler = null;
+
+  private static final Object DEFAULT_SCHEDULER_LOCK = new Object();
+
+
+
+  /**
+   * Retrieves a string representation of the provided byte in hexadecimal.
+   *
+   * @param b
+   *          The byte for which to retrieve the hexadecimal string
+   *          representation.
+   * @return The string representation of the provided byte in hexadecimal.
+   */
+  public static String byteToHex(final byte b)
+  {
+    switch (b & 0xFF)
+    {
+    case 0x00:
+      return "00";
+    case 0x01:
+      return "01";
+    case 0x02:
+      return "02";
+    case 0x03:
+      return "03";
+    case 0x04:
+      return "04";
+    case 0x05:
+      return "05";
+    case 0x06:
+      return "06";
+    case 0x07:
+      return "07";
+    case 0x08:
+      return "08";
+    case 0x09:
+      return "09";
+    case 0x0A:
+      return "0A";
+    case 0x0B:
+      return "0B";
+    case 0x0C:
+      return "0C";
+    case 0x0D:
+      return "0D";
+    case 0x0E:
+      return "0E";
+    case 0x0F:
+      return "0F";
+    case 0x10:
+      return "10";
+    case 0x11:
+      return "11";
+    case 0x12:
+      return "12";
+    case 0x13:
+      return "13";
+    case 0x14:
+      return "14";
+    case 0x15:
+      return "15";
+    case 0x16:
+      return "16";
+    case 0x17:
+      return "17";
+    case 0x18:
+      return "18";
+    case 0x19:
+      return "19";
+    case 0x1A:
+      return "1A";
+    case 0x1B:
+      return "1B";
+    case 0x1C:
+      return "1C";
+    case 0x1D:
+      return "1D";
+    case 0x1E:
+      return "1E";
+    case 0x1F:
+      return "1F";
+    case 0x20:
+      return "20";
+    case 0x21:
+      return "21";
+    case 0x22:
+      return "22";
+    case 0x23:
+      return "23";
+    case 0x24:
+      return "24";
+    case 0x25:
+      return "25";
+    case 0x26:
+      return "26";
+    case 0x27:
+      return "27";
+    case 0x28:
+      return "28";
+    case 0x29:
+      return "29";
+    case 0x2A:
+      return "2A";
+    case 0x2B:
+      return "2B";
+    case 0x2C:
+      return "2C";
+    case 0x2D:
+      return "2D";
+    case 0x2E:
+      return "2E";
+    case 0x2F:
+      return "2F";
+    case 0x30:
+      return "30";
+    case 0x31:
+      return "31";
+    case 0x32:
+      return "32";
+    case 0x33:
+      return "33";
+    case 0x34:
+      return "34";
+    case 0x35:
+      return "35";
+    case 0x36:
+      return "36";
+    case 0x37:
+      return "37";
+    case 0x38:
+      return "38";
+    case 0x39:
+      return "39";
+    case 0x3A:
+      return "3A";
+    case 0x3B:
+      return "3B";
+    case 0x3C:
+      return "3C";
+    case 0x3D:
+      return "3D";
+    case 0x3E:
+      return "3E";
+    case 0x3F:
+      return "3F";
+    case 0x40:
+      return "40";
+    case 0x41:
+      return "41";
+    case 0x42:
+      return "42";
+    case 0x43:
+      return "43";
+    case 0x44:
+      return "44";
+    case 0x45:
+      return "45";
+    case 0x46:
+      return "46";
+    case 0x47:
+      return "47";
+    case 0x48:
+      return "48";
+    case 0x49:
+      return "49";
+    case 0x4A:
+      return "4A";
+    case 0x4B:
+      return "4B";
+    case 0x4C:
+      return "4C";
+    case 0x4D:
+      return "4D";
+    case 0x4E:
+      return "4E";
+    case 0x4F:
+      return "4F";
+    case 0x50:
+      return "50";
+    case 0x51:
+      return "51";
+    case 0x52:
+      return "52";
+    case 0x53:
+      return "53";
+    case 0x54:
+      return "54";
+    case 0x55:
+      return "55";
+    case 0x56:
+      return "56";
+    case 0x57:
+      return "57";
+    case 0x58:
+      return "58";
+    case 0x59:
+      return "59";
+    case 0x5A:
+      return "5A";
+    case 0x5B:
+      return "5B";
+    case 0x5C:
+      return "5C";
+    case 0x5D:
+      return "5D";
+    case 0x5E:
+      return "5E";
+    case 0x5F:
+      return "5F";
+    case 0x60:
+      return "60";
+    case 0x61:
+      return "61";
+    case 0x62:
+      return "62";
+    case 0x63:
+      return "63";
+    case 0x64:
+      return "64";
+    case 0x65:
+      return "65";
+    case 0x66:
+      return "66";
+    case 0x67:
+      return "67";
+    case 0x68:
+      return "68";
+    case 0x69:
+      return "69";
+    case 0x6A:
+      return "6A";
+    case 0x6B:
+      return "6B";
+    case 0x6C:
+      return "6C";
+    case 0x6D:
+      return "6D";
+    case 0x6E:
+      return "6E";
+    case 0x6F:
+      return "6F";
+    case 0x70:
+      return "70";
+    case 0x71:
+      return "71";
+    case 0x72:
+      return "72";
+    case 0x73:
+      return "73";
+    case 0x74:
+      return "74";
+    case 0x75:
+      return "75";
+    case 0x76:
+      return "76";
+    case 0x77:
+      return "77";
+    case 0x78:
+      return "78";
+    case 0x79:
+      return "79";
+    case 0x7A:
+      return "7A";
+    case 0x7B:
+      return "7B";
+    case 0x7C:
+      return "7C";
+    case 0x7D:
+      return "7D";
+    case 0x7E:
+      return "7E";
+    case 0x7F:
+      return "7F";
+    case 0x80:
+      return "80";
+    case 0x81:
+      return "81";
+    case 0x82:
+      return "82";
+    case 0x83:
+      return "83";
+    case 0x84:
+      return "84";
+    case 0x85:
+      return "85";
+    case 0x86:
+      return "86";
+    case 0x87:
+      return "87";
+    case 0x88:
+      return "88";
+    case 0x89:
+      return "89";
+    case 0x8A:
+      return "8A";
+    case 0x8B:
+      return "8B";
+    case 0x8C:
+      return "8C";
+    case 0x8D:
+      return "8D";
+    case 0x8E:
+      return "8E";
+    case 0x8F:
+      return "8F";
+    case 0x90:
+      return "90";
+    case 0x91:
+      return "91";
+    case 0x92:
+      return "92";
+    case 0x93:
+      return "93";
+    case 0x94:
+      return "94";
+    case 0x95:
+      return "95";
+    case 0x96:
+      return "96";
+    case 0x97:
+      return "97";
+    case 0x98:
+      return "98";
+    case 0x99:
+      return "99";
+    case 0x9A:
+      return "9A";
+    case 0x9B:
+      return "9B";
+    case 0x9C:
+      return "9C";
+    case 0x9D:
+      return "9D";
+    case 0x9E:
+      return "9E";
+    case 0x9F:
+      return "9F";
+    case 0xA0:
+      return "A0";
+    case 0xA1:
+      return "A1";
+    case 0xA2:
+      return "A2";
+    case 0xA3:
+      return "A3";
+    case 0xA4:
+      return "A4";
+    case 0xA5:
+      return "A5";
+    case 0xA6:
+      return "A6";
+    case 0xA7:
+      return "A7";
+    case 0xA8:
+      return "A8";
+    case 0xA9:
+      return "A9";
+    case 0xAA:
+      return "AA";
+    case 0xAB:
+      return "AB";
+    case 0xAC:
+      return "AC";
+    case 0xAD:
+      return "AD";
+    case 0xAE:
+      return "AE";
+    case 0xAF:
+      return "AF";
+    case 0xB0:
+      return "B0";
+    case 0xB1:
+      return "B1";
+    case 0xB2:
+      return "B2";
+    case 0xB3:
+      return "B3";
+    case 0xB4:
+      return "B4";
+    case 0xB5:
+      return "B5";
+    case 0xB6:
+      return "B6";
+    case 0xB7:
+      return "B7";
+    case 0xB8:
+      return "B8";
+    case 0xB9:
+      return "B9";
+    case 0xBA:
+      return "BA";
+    case 0xBB:
+      return "BB";
+    case 0xBC:
+      return "BC";
+    case 0xBD:
+      return "BD";
+    case 0xBE:
+      return "BE";
+    case 0xBF:
+      return "BF";
+    case 0xC0:
+      return "C0";
+    case 0xC1:
+      return "C1";
+    case 0xC2:
+      return "C2";
+    case 0xC3:
+      return "C3";
+    case 0xC4:
+      return "C4";
+    case 0xC5:
+      return "C5";
+    case 0xC6:
+      return "C6";
+    case 0xC7:
+      return "C7";
+    case 0xC8:
+      return "C8";
+    case 0xC9:
+      return "C9";
+    case 0xCA:
+      return "CA";
+    case 0xCB:
+      return "CB";
+    case 0xCC:
+      return "CC";
+    case 0xCD:
+      return "CD";
+    case 0xCE:
+      return "CE";
+    case 0xCF:
+      return "CF";
+    case 0xD0:
+      return "D0";
+    case 0xD1:
+      return "D1";
+    case 0xD2:
+      return "D2";
+    case 0xD3:
+      return "D3";
+    case 0xD4:
+      return "D4";
+    case 0xD5:
+      return "D5";
+    case 0xD6:
+      return "D6";
+    case 0xD7:
+      return "D7";
+    case 0xD8:
+      return "D8";
+    case 0xD9:
+      return "D9";
+    case 0xDA:
+      return "DA";
+    case 0xDB:
+      return "DB";
+    case 0xDC:
+      return "DC";
+    case 0xDD:
+      return "DD";
+    case 0xDE:
+      return "DE";
+    case 0xDF:
+      return "DF";
+    case 0xE0:
+      return "E0";
+    case 0xE1:
+      return "E1";
+    case 0xE2:
+      return "E2";
+    case 0xE3:
+      return "E3";
+    case 0xE4:
+      return "E4";
+    case 0xE5:
+      return "E5";
+    case 0xE6:
+      return "E6";
+    case 0xE7:
+      return "E7";
+    case 0xE8:
+      return "E8";
+    case 0xE9:
+      return "E9";
+    case 0xEA:
+      return "EA";
+    case 0xEB:
+      return "EB";
+    case 0xEC:
+      return "EC";
+    case 0xED:
+      return "ED";
+    case 0xEE:
+      return "EE";
+    case 0xEF:
+      return "EF";
+    case 0xF0:
+      return "F0";
+    case 0xF1:
+      return "F1";
+    case 0xF2:
+      return "F2";
+    case 0xF3:
+      return "F3";
+    case 0xF4:
+      return "F4";
+    case 0xF5:
+      return "F5";
+    case 0xF6:
+      return "F6";
+    case 0xF7:
+      return "F7";
+    case 0xF8:
+      return "F8";
+    case 0xF9:
+      return "F9";
+    case 0xFA:
+      return "FA";
+    case 0xFB:
+      return "FB";
+    case 0xFC:
+      return "FC";
+    case 0xFD:
+      return "FD";
+    case 0xFE:
+      return "FE";
+    case 0xFF:
+      return "FF";
+    default:
+      return "??";
+    }
+  }
+
+
+
+  /**
+   * Retrieves a string representation of the provided byte in hexadecimal.
+   *
+   * @param b
+   *          The byte for which to retrieve the hexadecimal string
+   *          representation.
+   * @return The string representation of the provided byte in hexadecimal using
+   *         lowercase characters.
+   */
+  public static String byteToLowerHex(final byte b)
+  {
+    switch (b & 0xFF)
+    {
+    case 0x00:
+      return "00";
+    case 0x01:
+      return "01";
+    case 0x02:
+      return "02";
+    case 0x03:
+      return "03";
+    case 0x04:
+      return "04";
+    case 0x05:
+      return "05";
+    case 0x06:
+      return "06";
+    case 0x07:
+      return "07";
+    case 0x08:
+      return "08";
+    case 0x09:
+      return "09";
+    case 0x0A:
+      return "0a";
+    case 0x0B:
+      return "0b";
+    case 0x0C:
+      return "0c";
+    case 0x0D:
+      return "0d";
+    case 0x0E:
+      return "0e";
+    case 0x0F:
+      return "0f";
+    case 0x10:
+      return "10";
+    case 0x11:
+      return "11";
+    case 0x12:
+      return "12";
+    case 0x13:
+      return "13";
+    case 0x14:
+      return "14";
+    case 0x15:
+      return "15";
+    case 0x16:
+      return "16";
+    case 0x17:
+      return "17";
+    case 0x18:
+      return "18";
+    case 0x19:
+      return "19";
+    case 0x1A:
+      return "1a";
+    case 0x1B:
+      return "1b";
+    case 0x1C:
+      return "1c";
+    case 0x1D:
+      return "1d";
+    case 0x1E:
+      return "1e";
+    case 0x1F:
+      return "1f";
+    case 0x20:
+      return "20";
+    case 0x21:
+      return "21";
+    case 0x22:
+      return "22";
+    case 0x23:
+      return "23";
+    case 0x24:
+      return "24";
+    case 0x25:
+      return "25";
+    case 0x26:
+      return "26";
+    case 0x27:
+      return "27";
+    case 0x28:
+      return "28";
+    case 0x29:
+      return "29";
+    case 0x2A:
+      return "2a";
+    case 0x2B:
+      return "2b";
+    case 0x2C:
+      return "2c";
+    case 0x2D:
+      return "2d";
+    case 0x2E:
+      return "2e";
+    case 0x2F:
+      return "2f";
+    case 0x30:
+      return "30";
+    case 0x31:
+      return "31";
+    case 0x32:
+      return "32";
+    case 0x33:
+      return "33";
+    case 0x34:
+      return "34";
+    case 0x35:
+      return "35";
+    case 0x36:
+      return "36";
+    case 0x37:
+      return "37";
+    case 0x38:
+      return "38";
+    case 0x39:
+      return "39";
+    case 0x3A:
+      return "3a";
+    case 0x3B:
+      return "3b";
+    case 0x3C:
+      return "3c";
+    case 0x3D:
+      return "3d";
+    case 0x3E:
+      return "3e";
+    case 0x3F:
+      return "3f";
+    case 0x40:
+      return "40";
+    case 0x41:
+      return "41";
+    case 0x42:
+      return "42";
+    case 0x43:
+      return "43";
+    case 0x44:
+      return "44";
+    case 0x45:
+      return "45";
+    case 0x46:
+      return "46";
+    case 0x47:
+      return "47";
+    case 0x48:
+      return "48";
+    case 0x49:
+      return "49";
+    case 0x4A:
+      return "4a";
+    case 0x4B:
+      return "4b";
+    case 0x4C:
+      return "4c";
+    case 0x4D:
+      return "4d";
+    case 0x4E:
+      return "4e";
+    case 0x4F:
+      return "4f";
+    case 0x50:
+      return "50";
+    case 0x51:
+      return "51";
+    case 0x52:
+      return "52";
+    case 0x53:
+      return "53";
+    case 0x54:
+      return "54";
+    case 0x55:
+      return "55";
+    case 0x56:
+      return "56";
+    case 0x57:
+      return "57";
+    case 0x58:
+      return "58";
+    case 0x59:
+      return "59";
+    case 0x5A:
+      return "5a";
+    case 0x5B:
+      return "5b";
+    case 0x5C:
+      return "5c";
+    case 0x5D:
+      return "5d";
+    case 0x5E:
+      return "5e";
+    case 0x5F:
+      return "5f";
+    case 0x60:
+      return "60";
+    case 0x61:
+      return "61";
+    case 0x62:
+      return "62";
+    case 0x63:
+      return "63";
+    case 0x64:
+      return "64";
+    case 0x65:
+      return "65";
+    case 0x66:
+      return "66";
+    case 0x67:
+      return "67";
+    case 0x68:
+      return "68";
+    case 0x69:
+      return "69";
+    case 0x6A:
+      return "6a";
+    case 0x6B:
+      return "6b";
+    case 0x6C:
+      return "6c";
+    case 0x6D:
+      return "6d";
+    case 0x6E:
+      return "6e";
+    case 0x6F:
+      return "6f";
+    case 0x70:
+      return "70";
+    case 0x71:
+      return "71";
+    case 0x72:
+      return "72";
+    case 0x73:
+      return "73";
+    case 0x74:
+      return "74";
+    case 0x75:
+      return "75";
+    case 0x76:
+      return "76";
+    case 0x77:
+      return "77";
+    case 0x78:
+      return "78";
+    case 0x79:
+      return "79";
+    case 0x7A:
+      return "7a";
+    case 0x7B:
+      return "7b";
+    case 0x7C:
+      return "7c";
+    case 0x7D:
+      return "7d";
+    case 0x7E:
+      return "7e";
+    case 0x7F:
+      return "7f";
+    case 0x80:
+      return "80";
+    case 0x81:
+      return "81";
+    case 0x82:
+      return "82";
+    case 0x83:
+      return "83";
+    case 0x84:
+      return "84";
+    case 0x85:
+      return "85";
+    case 0x86:
+      return "86";
+    case 0x87:
+      return "87";
+    case 0x88:
+      return "88";
+    case 0x89:
+      return "89";
+    case 0x8A:
+      return "8a";
+    case 0x8B:
+      return "8b";
+    case 0x8C:
+      return "8c";
+    case 0x8D:
+      return "8d";
+    case 0x8E:
+      return "8e";
+    case 0x8F:
+      return "8f";
+    case 0x90:
+      return "90";
+    case 0x91:
+      return "91";
+    case 0x92:
+      return "92";
+    case 0x93:
+      return "93";
+    case 0x94:
+      return "94";
+    case 0x95:
+      return "95";
+    case 0x96:
+      return "96";
+    case 0x97:
+      return "97";
+    case 0x98:
+      return "98";
+    case 0x99:
+      return "99";
+    case 0x9A:
+      return "9a";
+    case 0x9B:
+      return "9b";
+    case 0x9C:
+      return "9c";
+    case 0x9D:
+      return "9d";
+    case 0x9E:
+      return "9e";
+    case 0x9F:
+      return "9f";
+    case 0xA0:
+      return "a0";
+    case 0xA1:
+      return "a1";
+    case 0xA2:
+      return "a2";
+    case 0xA3:
+      return "a3";
+    case 0xA4:
+      return "a4";
+    case 0xA5:
+      return "a5";
+    case 0xA6:
+      return "a6";
+    case 0xA7:
+      return "a7";
+    case 0xA8:
+      return "a8";
+    case 0xA9:
+      return "a9";
+    case 0xAA:
+      return "aa";
+    case 0xAB:
+      return "ab";
+    case 0xAC:
+      return "ac";
+    case 0xAD:
+      return "ad";
+    case 0xAE:
+      return "ae";
+    case 0xAF:
+      return "af";
+    case 0xB0:
+      return "b0";
+    case 0xB1:
+      return "b1";
+    case 0xB2:
+      return "b2";
+    case 0xB3:
+      return "b3";
+    case 0xB4:
+      return "b4";
+    case 0xB5:
+      return "b5";
+    case 0xB6:
+      return "b6";
+    case 0xB7:
+      return "b7";
+    case 0xB8:
+      return "b8";
+    case 0xB9:
+      return "b9";
+    case 0xBA:
+      return "ba";
+    case 0xBB:
+      return "bb";
+    case 0xBC:
+      return "bc";
+    case 0xBD:
+      return "bd";
+    case 0xBE:
+      return "be";
+    case 0xBF:
+      return "bf";
+    case 0xC0:
+      return "c0";
+    case 0xC1:
+      return "c1";
+    case 0xC2:
+      return "c2";
+    case 0xC3:
+      return "c3";
+    case 0xC4:
+      return "c4";
+    case 0xC5:
+      return "c5";
+    case 0xC6:
+      return "c6";
+    case 0xC7:
+      return "c7";
+    case 0xC8:
+      return "c8";
+    case 0xC9:
+      return "c9";
+    case 0xCA:
+      return "ca";
+    case 0xCB:
+      return "cb";
+    case 0xCC:
+      return "cc";
+    case 0xCD:
+      return "cd";
+    case 0xCE:
+      return "ce";
+    case 0xCF:
+      return "cf";
+    case 0xD0:
+      return "d0";
+    case 0xD1:
+      return "d1";
+    case 0xD2:
+      return "d2";
+    case 0xD3:
+      return "d3";
+    case 0xD4:
+      return "d4";
+    case 0xD5:
+      return "d5";
+    case 0xD6:
+      return "d6";
+    case 0xD7:
+      return "d7";
+    case 0xD8:
+      return "d8";
+    case 0xD9:
+      return "d9";
+    case 0xDA:
+      return "da";
+    case 0xDB:
+      return "db";
+    case 0xDC:
+      return "dc";
+    case 0xDD:
+      return "dd";
+    case 0xDE:
+      return "de";
+    case 0xDF:
+      return "df";
+    case 0xE0:
+      return "e0";
+    case 0xE1:
+      return "e1";
+    case 0xE2:
+      return "e2";
+    case 0xE3:
+      return "e3";
+    case 0xE4:
+      return "e4";
+    case 0xE5:
+      return "e5";
+    case 0xE6:
+      return "e6";
+    case 0xE7:
+      return "e7";
+    case 0xE8:
+      return "e8";
+    case 0xE9:
+      return "e9";
+    case 0xEA:
+      return "ea";
+    case 0xEB:
+      return "eb";
+    case 0xEC:
+      return "ec";
+    case 0xED:
+      return "ed";
+    case 0xEE:
+      return "ee";
+    case 0xEF:
+      return "ef";
+    case 0xF0:
+      return "f0";
+    case 0xF1:
+      return "f1";
+    case 0xF2:
+      return "f2";
+    case 0xF3:
+      return "f3";
+    case 0xF4:
+      return "f4";
+    case 0xF5:
+      return "f5";
+    case 0xF6:
+      return "f6";
+    case 0xF7:
+      return "f7";
+    case 0xF8:
+      return "f8";
+    case 0xF9:
+      return "f9";
+    case 0xFA:
+      return "fa";
+    case 0xFB:
+      return "fb";
+    case 0xFC:
+      return "fc";
+    case 0xFD:
+      return "fd";
+    case 0xFE:
+      return "fe";
+    case 0xFF:
+      return "ff";
+    default:
+      return "??";
+    }
+  }
+
+
+
+  /**
+   * Attempts to compress the data in the provided source array into the given
+   * destination array. If the compressed data will fit into the destination
+   * array, then this method will return the number of bytes of compressed data
+   * in the array. Otherwise, it will return -1 to indicate that the compression
+   * was not successful. Note that if -1 is returned, then the data in the
+   * destination array should be considered invalid.
+   *
+   * @param src
+   *          The array containing the raw data to compress.
+   * @param srcOff
+   *          The start offset of the source data.
+   * @param srcLen
+   *          The maximum number of source data bytes to compress.
+   * @param dst
+   *          The array into which the compressed data should be written.
+   * @param dstOff
+   *          The start offset of the compressed data.
+   * @param dstLen
+   *          The maximum number of bytes of compressed data.
+   * @return The number of bytes of compressed data, or -1 if it was not
+   *         possible to actually compress the data.
+   */
+  public static int compress(final byte[] src, final int srcOff,
+      final int srcLen, final byte[] dst, final int dstOff, final int dstLen)
+  {
+    final Deflater deflater = new Deflater();
+    try
+    {
+      deflater.setInput(src, srcOff, srcLen);
+      deflater.finish();
+
+      final int compressedLength = deflater.deflate(dst, dstOff, dstLen);
+      if (deflater.finished())
+      {
+        return compressedLength;
+      }
+      else
+      {
+        return -1;
+      }
+    }
+    finally
+    {
+      deflater.end();
+    }
+  }
+
+
+
+  /**
+   * Attempts to compress the data in the provided byte sequence into the
+   * provided byte string builder. Note that if compression was not successful,
+   * then the byte string builder will be left unchanged.
+   *
+   * @param input
+   *          The source data to be compressed.
+   * @param output
+   *          The destination buffer to which the compressed data will be
+   *          appended.
+   * @return <code>true</code> if compression was successful or
+   *         <code>false</code> otherwise.
+   */
+  public static boolean compress(final ByteSequence input,
+      final ByteStringBuilder output)
+  {
+    final byte[] inputBytes = input.toByteArray();
+    final byte[] outputBytes = new byte[inputBytes.length];
+
+    final int compressedSize = compress(inputBytes, 0, inputBytes.length,
+        outputBytes, 0, outputBytes.length);
+
+    if (compressedSize != -1)
+    {
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+      {
+        StaticUtils.DEBUG_LOG.fine(String.format("Compression %d/%d%n",
+            compressedSize, inputBytes.length));
+      }
+
+      output.append(outputBytes, 0, compressedSize);
+      return true;
+    }
+
+    return false;
+  }
+
+
+
+  /**
+   * Returns a string containing provided date formatted using the generalized
+   * time syntax.
+   *
+   * @param date
+   *          The date to be formated.
+   * @return The string containing provided date formatted using the generalized
+   *         time syntax.
+   * @throws NullPointerException
+   *           If {@code date} was {@code null}.
+   */
+  public static String formatAsGeneralizedTime(final Date date)
+      throws NullPointerException
+  {
+    return formatAsGeneralizedTime(date.getTime());
+  }
+
+
+
+  /**
+   * Returns a string containing provided date formatted using the generalized
+   * time syntax.
+   *
+   * @param date
+   *          The date to be formated.
+   * @return The string containing provided date formatted using the generalized
+   *         time syntax.
+   * @throws IllegalArgumentException
+   *           If {@code date} was invalid.
+   */
+  public static String formatAsGeneralizedTime(final long date)
+      throws IllegalArgumentException
+  {
+    // Generalized time has the format yyyyMMddHHmmss.SSS'Z'
+
+    // Do this in a thread-safe non-synchronized fashion.
+    // (Simple)DateFormat is neither fast nor thread-safe.
+
+    final StringBuilder sb = new StringBuilder(19);
+
+    final GregorianCalendar calendar = new GregorianCalendar(TIME_ZONE_UTC_OBJ);
+    calendar.setLenient(false);
+    calendar.setTimeInMillis(date);
+
+    // Format the year yyyy.
+    int n = calendar.get(Calendar.YEAR);
+    if (n < 0)
+    {
+      final IllegalArgumentException e = new IllegalArgumentException(
+          "Year cannot be < 0:" + n);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax", "format", e);
+      throw e;
+    }
+    else if (n < 10)
+    {
+      sb.append("000");
+    }
+    else if (n < 100)
+    {
+      sb.append("00");
+    }
+    else if (n < 1000)
+    {
+      sb.append("0");
+    }
+    sb.append(n);
+
+    // Format the month MM.
+    n = calendar.get(Calendar.MONTH) + 1;
+    if (n < 10)
+    {
+      sb.append("0");
+    }
+    sb.append(n);
+
+    // Format the day dd.
+    n = calendar.get(Calendar.DAY_OF_MONTH);
+    if (n < 10)
+    {
+      sb.append("0");
+    }
+    sb.append(n);
+
+    // Format the hour HH.
+    n = calendar.get(Calendar.HOUR_OF_DAY);
+    if (n < 10)
+    {
+      sb.append("0");
+    }
+    sb.append(n);
+
+    // Format the minute mm.
+    n = calendar.get(Calendar.MINUTE);
+    if (n < 10)
+    {
+      sb.append("0");
+    }
+    sb.append(n);
+
+    // Format the seconds ss.
+    n = calendar.get(Calendar.SECOND);
+    if (n < 10)
+    {
+      sb.append("0");
+    }
+    sb.append(n);
+
+    // Format the milli-seconds.
+    sb.append('.');
+    n = calendar.get(Calendar.MILLISECOND);
+    if (n < 10)
+    {
+      sb.append("00");
+    }
+    else if (n < 100)
+    {
+      sb.append("0");
+    }
+    sb.append(n);
+
+    // Format the timezone (always Z).
+    sb.append('Z');
+
+    return sb.toString();
+  }
+
+
+
+  /**
+   * Construct a byte array containing the UTF-8 encoding of the provided
+   * string. This is significantly faster than calling
+   * {@link String#getBytes(String)} for ASCII strings.
+   *
+   * @param s
+   *          The string to convert to a UTF-8 byte array.
+   * @return Returns a byte array containing the UTF-8 encoding of the provided
+   *         string.
+   */
+  public static byte[] getBytes(final String s)
+  {
+    if (s == null)
+    {
+      return null;
+    }
+
+    try
+    {
+      char c;
+      final int length = s.length();
+      final byte[] returnArray = new byte[length];
+      for (int i = 0; i < length; i++)
+      {
+        c = s.charAt(i);
+        returnArray[i] = (byte) (c & 0x0000007F);
+        if (c != returnArray[i])
+        {
+          return s.getBytes("UTF-8");
+        }
+      }
+
+      return returnArray;
+    }
+    catch (final Exception e)
+    {
+      DEBUG_LOG.warning("Unable to encode UTF-8 string " + s);
+
+      return s.getBytes();
+    }
+  }
+
+
+
+  /**
+   * Returns the default scheduler which should be used by the SDK.
+   *
+   * @return The default scheduler.
+   */
+  public static ScheduledExecutorService getDefaultScheduler()
+  {
+    synchronized (DEFAULT_SCHEDULER_LOCK)
+    {
+      if (defaultScheduler == null)
+      {
+        final ThreadFactory factory = newThreadFactory(null,
+            "OpenDS SDK Default Scheduler", true);
+        defaultScheduler = Executors.newSingleThreadScheduledExecutor(factory);
+      }
+    }
+    return defaultScheduler;
+  }
+
+
+
+  /**
+   * Retrieves the best human-readable message for the provided exception. For
+   * exceptions defined in the OpenDS project, it will attempt to use the
+   * message (combining it with the message ID if available). For some
+   * exceptions that use encapsulation (e.g., InvocationTargetException), it
+   * will be unwrapped and the cause will be treated. For all others, the
+   *
+   * @param t
+   *          The {@code Throwable} object for which to retrieve the message.
+   * @return The human-readable message generated for the provided exception.
+   */
+  public static LocalizableMessage getExceptionMessage(final Throwable t)
+  {
+    if (t instanceof LocalizableException)
+    {
+      final LocalizableException ie = (LocalizableException) t;
+      return ie.getMessageObject();
+    }
+    else if (t instanceof NullPointerException)
+    {
+      final StackTraceElement[] stackElements = t.getStackTrace();
+
+      final LocalizableMessageBuilder message = new LocalizableMessageBuilder();
+      message.append("NullPointerException(");
+      message.append(stackElements[0].getFileName());
+      message.append(":");
+      message.append(stackElements[0].getLineNumber());
+      message.append(")");
+      return message.toMessage();
+    }
+    else if (t instanceof InvocationTargetException && t.getCause() != null)
+    {
+      return getExceptionMessage(t.getCause());
+    }
+    else
+    {
+      final StringBuilder message = new StringBuilder();
+
+      final String className = t.getClass().getName();
+      final int periodPos = className.lastIndexOf('.');
+      if (periodPos > 0)
+      {
+        message.append(className.substring(periodPos + 1));
+      }
+      else
+      {
+        message.append(className);
+      }
+
+      message.append("(");
+      if (t.getMessage() == null)
+      {
+        final StackTraceElement[] stackElements = t.getStackTrace();
+        message.append(stackElements[0].getFileName());
+        message.append(":");
+        message.append(stackElements[0].getLineNumber());
+
+        // FIXME Temporary to debug issue 2256.
+        if (t instanceof IllegalStateException)
+        {
+          for (int i = 1; i < stackElements.length; i++)
+          {
+            message.append(' ');
+            message.append(stackElements[i].getFileName());
+            message.append(":");
+            message.append(stackElements[i].getLineNumber());
+          }
+        }
+      }
+      else
+      {
+        message.append(t.getMessage());
+      }
+
+      message.append(")");
+
+      return LocalizableMessage.raw(message.toString());
+    }
+  }
+
+
+
+  /**
+   * Converts the provided hexadecimal string to a byte array.
+   *
+   * @param hexString
+   *          The hexadecimal string to convert to a byte array.
+   * @return The byte array containing the binary representation of the provided
+   *         hex string.
+   * @throws java.text.ParseException
+   *           If the provided string contains invalid hexadecimal digits or
+   *           does not contain an even number of digits.
+   */
+  public static byte[] hexStringToByteArray(final String hexString)
+      throws ParseException
+  {
+    int length;
+    if (hexString == null || (length = hexString.length()) == 0)
+    {
+      return new byte[0];
+    }
+
+    if (length % 2 != 0)
+    {
+      final LocalizableMessage message = ERR_HEX_DECODE_INVALID_LENGTH
+          .get(hexString);
+      throw new ParseException(message.toString(), 0);
+    }
+
+    final int arrayLength = length / 2;
+    final byte[] returnArray = new byte[arrayLength];
+    for (int i = 0; i < arrayLength; i++)
+    {
+      returnArray[i] = hexToByte(hexString.charAt(i * 2), hexString
+          .charAt(i * 2 + 1));
+    }
+
+    return returnArray;
+  }
+
+
+
+  /**
+   * Converts the provided pair of characters to a byte.
+   *
+   * @param c1
+   *          The first hexadecimal character.
+   * @param c2
+   *          The second hexadecimal character.
+   * @return The byte containing the binary representation of the provided hex
+   *         characters.
+   * @throws ParseException
+   *           If the provided string contains invalid hexadecimal digits or
+   *           does not contain an even number of digits.
+   */
+  public static byte hexToByte(final char c1, final char c2)
+      throws ParseException
+  {
+    byte b;
+    switch (c1)
+    {
+    case '0':
+      b = 0x00;
+      break;
+    case '1':
+      b = 0x10;
+      break;
+    case '2':
+      b = 0x20;
+      break;
+    case '3':
+      b = 0x30;
+      break;
+    case '4':
+      b = 0x40;
+      break;
+    case '5':
+      b = 0x50;
+      break;
+    case '6':
+      b = 0x60;
+      break;
+    case '7':
+      b = 0x70;
+      break;
+    case '8':
+      b = (byte) 0x80;
+      break;
+    case '9':
+      b = (byte) 0x90;
+      break;
+    case 'A':
+    case 'a':
+      b = (byte) 0xA0;
+      break;
+    case 'B':
+    case 'b':
+      b = (byte) 0xB0;
+      break;
+    case 'C':
+    case 'c':
+      b = (byte) 0xC0;
+      break;
+    case 'D':
+    case 'd':
+      b = (byte) 0xD0;
+      break;
+    case 'E':
+    case 'e':
+      b = (byte) 0xE0;
+      break;
+    case 'F':
+    case 'f':
+      b = (byte) 0xF0;
+      break;
+    default:
+      final LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get(
+          new String(new char[] { c1, c2 }), c1);
+      throw new ParseException(message.toString(), 0);
+    }
+
+    switch (c2)
+    {
+    case '0':
+      // No action required.
+      break;
+    case '1':
+      b |= 0x01;
+      break;
+    case '2':
+      b |= 0x02;
+      break;
+    case '3':
+      b |= 0x03;
+      break;
+    case '4':
+      b |= 0x04;
+      break;
+    case '5':
+      b |= 0x05;
+      break;
+    case '6':
+      b |= 0x06;
+      break;
+    case '7':
+      b |= 0x07;
+      break;
+    case '8':
+      b |= 0x08;
+      break;
+    case '9':
+      b |= 0x09;
+      break;
+    case 'A':
+    case 'a':
+      b |= 0x0A;
+      break;
+    case 'B':
+    case 'b':
+      b |= 0x0B;
+      break;
+    case 'C':
+    case 'c':
+      b |= 0x0C;
+      break;
+    case 'D':
+    case 'd':
+      b |= 0x0D;
+      break;
+    case 'E':
+    case 'e':
+      b |= 0x0E;
+      break;
+    case 'F':
+    case 'f':
+      b |= 0x0F;
+      break;
+    default:
+      final LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get(
+          new String(new char[] { c1, c2 }), c1);
+      throw new ParseException(message.toString(), 0);
+    }
+
+    return b;
+  }
+
+
+
+  /**
+   * Indicates whether the provided character is an ASCII alphabetic character.
+   *
+   * @param c
+   *          The character for which to make the determination.
+   * @return <CODE>true</CODE> if the provided value is an uppercase or
+   *         lowercase ASCII alphabetic character, or <CODE>false</CODE> if it
+   *         is not.
+   */
+  public static boolean isAlpha(final char c)
+  {
+    final ASCIICharProp cp = ASCIICharProp.valueOf(c);
+    return cp != null ? cp.isLetter() : false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided character is a numeric digit.
+   *
+   * @param c
+   *          The character for which to make the determination.
+   * @return <CODE>true</CODE> if the provided character represents a numeric
+   *         digit, or <CODE>false</CODE> if not.
+   */
+  public static boolean isDigit(final char c)
+  {
+    final ASCIICharProp cp = ASCIICharProp.valueOf(c);
+    return cp != null ? cp.isDigit() : false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided character is a hexadecimal digit.
+   *
+   * @param c
+   *          The character for which to make the determination.
+   * @return <CODE>true</CODE> if the provided character represents a
+   *         hexadecimal digit, or <CODE>false</CODE> if not.
+   */
+  public static boolean isHexDigit(final char c)
+  {
+    final ASCIICharProp cp = ASCIICharProp.valueOf(c);
+    return cp != null ? cp.isHexDigit() : false;
+  }
+
+
+
+  /**
+   * Returns a string whose content is the string representation of the objects
+   * contained in the provided collection concatenated together using the
+   * provided separator.
+   *
+   * @param c
+   *          The collection whose elements are to be joined.
+   * @param separator
+   *          The separator string.
+   * @return A string whose content is the string representation of the objects
+   *         contained in the provided collection concatenated together using
+   *         the provided separator.
+   * @throws NullPointerException
+   *           If {@code c} or {@code separator} were {@code null}.
+   */
+  public static String joinCollection(Collection<?> c, String separator)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(c, separator);
+
+    switch (c.size())
+    {
+    case 0:
+      return "";
+    case 1:
+      return String.valueOf(c.iterator().next());
+    default:
+      StringBuilder builder = new StringBuilder();
+      Iterator<?> i = c.iterator();
+      builder.append(i.next());
+      while (i.hasNext())
+      {
+        builder.append(separator);
+        builder.append(i.next());
+      }
+      String s = builder.toString();
+      return s;
+    }
+  }
+
+
+
+
+  /**
+   * Creates a new thread factory which will create threads using the specified
+   * thread group, naming template, and daemon status.
+   *
+   * @param group
+   *          The thread group, which may be {@code null}.
+   * @param nameTemplate
+   *          The thread name format string which may contain a "%d" format
+   *          option which will be substituted with the thread count.
+   * @param isDaemon
+   *          Indicates whether or not threads should be daemon threads.
+   * @return The new thread factory.
+   */
+  public static ThreadFactory newThreadFactory(final ThreadGroup group,
+      final String nameTemplate, final boolean isDaemon)
+  {
+    return new ThreadFactory()
+    {
+      private final AtomicInteger count = new AtomicInteger();
+
+
+
+      public Thread newThread(Runnable r)
+      {
+        final String name = String
+            .format(nameTemplate, count.getAndIncrement());
+        final Thread t = new Thread(group, r, name);
+        t.setDaemon(isDaemon);
+        return t;
+      }
+    };
+  }
+
+
+  /**
+   * Returns a string representation of the contents of the provided byte
+   * sequence using hexadecimal characters and a space between each byte.
+   *
+   * @param bytes
+   *          The byte sequence.
+   * @return A string representation of the contents of the provided byte
+   *         sequence using hexadecimal characters.
+   */
+  public static String toHex(final ByteSequence bytes)
+  {
+    return toHex(bytes, new StringBuilder((bytes.length() - 1) * 3 + 2))
+        .toString();
+  }
+
+
+
+  /**
+   * Appends the string representation of the contents of the provided byte
+   * sequence to a string builder using hexadecimal characters and a space
+   * between each byte.
+   *
+   * @param bytes
+   *          The byte sequence.
+   * @param builder
+   *          The string builder to which the hexadecimal representation of
+   *          {@code bytes} should be appended.
+   * @return The string builder.
+   */
+  public static StringBuilder toHex(final ByteSequence bytes,
+      final StringBuilder builder)
+  {
+    final int length = bytes.length();
+    builder.ensureCapacity(builder.length() + (length - 1) * 3 + 2);
+    builder.append(StaticUtils.byteToHex(bytes.byteAt(0)));
+    for (int i = 1; i < length; i++)
+    {
+      builder.append(" ");
+      builder.append(StaticUtils.byteToHex(bytes.byteAt(i)));
+    }
+    return builder;
+  }
+
+
+
+  /**
+   * Appends a string representation of the data in the provided byte sequence
+   * to the given string builder using the specified indent.
+   * <p>
+   * The data will be formatted with sixteen hex bytes in a row followed by the
+   * ASCII representation, then wrapping to a new line as necessary. The state
+   * of the byte buffer is not changed.
+   *
+   * @param bytes
+   *          The byte sequence.
+   * @param builder
+   *          The string builder to which the information is to be appended.
+   * @param indent
+   *          The number of spaces to indent the output.
+   * @return The string builder.
+   */
+  public static StringBuilder toHexPlusAscii(final ByteSequence bytes,
+      final StringBuilder builder, final int indent)
+  {
+    final StringBuilder indentBuf = new StringBuilder(indent);
+    for (int i = 0; i < indent; i++)
+    {
+      indentBuf.append(' ');
+    }
+
+    final int length = bytes.length();
+    int pos = 0;
+    while (length - pos >= 16)
+    {
+      final StringBuilder asciiBuf = new StringBuilder(17);
+
+      byte currentByte = bytes.byteAt(pos);
+      builder.append(indentBuf);
+      builder.append(StaticUtils.byteToHex(currentByte));
+      asciiBuf.append(byteToASCII(currentByte));
+      pos++;
+
+      for (int i = 1; i < 16; i++, pos++)
+      {
+        currentByte = bytes.byteAt(pos);
+        builder.append(' ');
+        builder.append(StaticUtils.byteToHex(currentByte));
+        asciiBuf.append(byteToASCII(currentByte));
+
+        if (i == 7)
+        {
+          builder.append("  ");
+          asciiBuf.append(' ');
+        }
+      }
+
+      builder.append("  ");
+      builder.append(asciiBuf);
+      builder.append(EOL);
+    }
+
+    final int remaining = length - pos;
+    if (remaining > 0)
+    {
+      final StringBuilder asciiBuf = new StringBuilder(remaining + 1);
+
+      byte currentByte = bytes.byteAt(pos);
+      builder.append(indentBuf);
+      builder.append(StaticUtils.byteToHex(currentByte));
+      asciiBuf.append(byteToASCII(currentByte));
+      pos++;
+
+      for (int i = 1; i < 16; i++, pos++)
+      {
+        builder.append(' ');
+
+        if (i < remaining)
+        {
+          currentByte = bytes.byteAt(pos);
+          builder.append(StaticUtils.byteToHex(currentByte));
+          asciiBuf.append(byteToASCII(currentByte));
+        }
+        else
+        {
+          builder.append("  ");
+        }
+
+        if (i == 7)
+        {
+          builder.append("  ");
+
+          if (i < remaining)
+          {
+            asciiBuf.append(' ');
+          }
+        }
+      }
+
+      builder.append("  ");
+      builder.append(asciiBuf);
+      builder.append(EOL);
+    }
+
+    return builder;
+  }
+
+
+
+  /**
+   * Appends a lowercase string representation of the contents of the given byte
+   * array to the provided buffer. This implementation presumes that the
+   * provided string will contain only ASCII characters and is optimized for
+   * that case. However, if a non-ASCII character is encountered it will fall
+   * back on a more expensive algorithm that will work properly for non-ASCII
+   * characters.
+   *
+   * @param b
+   *          The byte array for which to obtain the lowercase string
+   *          representation.
+   * @param builder
+   *          The buffer to which the lowercase form of the string should be
+   *          appended.
+   * @return The updated {@code StringBuilder}.
+   */
+  public static StringBuilder toLowerCase(final ByteSequence b,
+      final StringBuilder builder)
+  {
+    Validator.ensureNotNull(b, builder);
+
+    // FIXME: What locale should we use for non-ASCII characters? I
+    // think we should use default to the Unicode StringPrep.
+
+    final int origBufferLen = builder.length();
+    final int length = b.length();
+
+    for (int i = 0; i < length; i++)
+    {
+      final int c = b.byteAt(i);
+
+      if (c < 0)
+      {
+        builder.replace(origBufferLen, builder.length(), b.toString()
+            .toLowerCase(Locale.ENGLISH));
+        return builder;
+      }
+
+      // At this point 0 <= 'c' <= 128.
+      final ASCIICharProp cp = ASCIICharProp.valueOf(c);
+      builder.append(cp.toLowerCase());
+    }
+
+    return builder;
+  }
+
+
+
+  /**
+   * Retrieves a lower-case representation of the given string. This
+   * implementation presumes that the provided string will contain only ASCII
+   * characters and is optimized for that case. However, if a non-ASCII
+   * character is encountered it will fall back on a more expensive algorithm
+   * that will work properly for non-ASCII characters.
+   *
+   * @param s
+   *          The string for which to obtain the lower-case representation.
+   * @return The lower-case representation of the given string.
+   */
+  public static String toLowerCase(final String s)
+  {
+    Validator.ensureNotNull(s);
+
+    // FIXME: What locale should we use for non-ASCII characters? I
+    // think we should use default to the Unicode StringPrep.
+
+    // This code is optimized for the case where the input string 's'
+    // has already been converted to lowercase.
+    final int length = s.length();
+    int i = 0;
+    ASCIICharProp cp = null;
+
+    // Scan for non lowercase ASCII.
+    while (i < length)
+    {
+      cp = ASCIICharProp.valueOf(s.charAt(i));
+      if (cp == null || cp.isUpperCase())
+      {
+        break;
+      }
+      i++;
+    }
+
+    if (i == length)
+    {
+      // String was already lowercase ASCII.
+      return s;
+    }
+
+    // Found non lowercase ASCII.
+    final StringBuilder builder = new StringBuilder(length);
+    builder.append(s, 0, i);
+
+    if (cp != null)
+    {
+      // Upper-case ASCII.
+      builder.append(cp.toLowerCase());
+      i++;
+      while (i < length)
+      {
+        cp = ASCIICharProp.valueOf(s.charAt(i));
+        if (cp == null)
+        {
+          break;
+        }
+        builder.append(cp.toLowerCase());
+        i++;
+      }
+    }
+
+    if (i < length)
+    {
+      builder.append(s.substring(i).toLowerCase(Locale.ENGLISH));
+    }
+
+    return builder.toString();
+  }
+
+
+
+  /**
+   * Appends a lower-case representation of the given string to the provided
+   * buffer. This implementation presumes that the provided string will contain
+   * only ASCII characters and is optimized for that case. However, if a
+   * non-ASCII character is encountered it will fall back on a more expensive
+   * algorithm that will work properly for non-ASCII characters.
+   *
+   * @param s
+   *          The string for which to obtain the lower-case representation.
+   * @param builder
+   *          The {@code StringBuilder} to which the lower-case form of the
+   *          string should be appended.
+   * @return The updated {@code StringBuilder}.
+   */
+  public static StringBuilder toLowerCase(final String s,
+      final StringBuilder builder)
+  {
+    Validator.ensureNotNull(s, builder);
+
+    // FIXME: What locale should we use for non-ASCII characters? I
+    // think we should use default to the Unicode StringPrep.
+
+    final int length = s.length();
+    builder.ensureCapacity(builder.length() + length);
+
+    for (int i = 0; i < length; i++)
+    {
+      final ASCIICharProp cp = ASCIICharProp.valueOf(s.charAt(i));
+      if (cp != null)
+      {
+        builder.append(cp.toLowerCase());
+      }
+      else
+      {
+        // Non-ASCII.
+        builder.append(s.substring(i).toLowerCase(Locale.ENGLISH));
+        return builder;
+      }
+    }
+
+    return builder;
+  }
+
+
+
+  /**
+   * Attempts to uncompress the data in the provided source array into the given
+   * destination array. If the uncompressed data will fit into the given
+   * destination array, then this method will return the number of bytes of
+   * uncompressed data written into the destination buffer. Otherwise, it will
+   * return a negative value to indicate that the destination buffer was not
+   * large enough. The absolute value of that negative return value will
+   * indicate the buffer size required to fully decompress the data. Note that
+   * if a negative value is returned, then the data in the destination array
+   * should be considered invalid.
+   *
+   * @param src
+   *          The array containing the raw data to compress.
+   * @param srcOff
+   *          The start offset of the source data.
+   * @param srcLen
+   *          The maximum number of source data bytes to compress.
+   * @param dst
+   *          The array into which the compressed data should be written.
+   * @param dstOff
+   *          The start offset of the compressed data.
+   * @param dstLen
+   *          The maximum number of bytes of compressed data.
+   * @return A positive value containing the number of bytes of uncompressed
+   *         data written into the destination buffer, or a negative value whose
+   *         absolute value is the size of the destination buffer required to
+   *         fully decompress the provided data.
+   * @throws java.util.zip.DataFormatException
+   *           If a problem occurs while attempting to uncompress the data.
+   */
+  public static int uncompress(final byte[] src, final int srcOff,
+      final int srcLen, final byte[] dst, final int dstOff, final int dstLen)
+      throws DataFormatException
+  {
+    final Inflater inflater = new Inflater();
+    try
+    {
+      inflater.setInput(src, srcOff, srcLen);
+
+      final int decompressedLength = inflater.inflate(dst, dstOff, dstLen);
+      if (inflater.finished())
+      {
+        return decompressedLength;
+      }
+      else
+      {
+        int totalLength = decompressedLength;
+
+        while (!inflater.finished())
+        {
+          totalLength += inflater.inflate(dst, dstOff, dstLen);
+        }
+
+        return -totalLength;
+      }
+    }
+    finally
+    {
+      inflater.end();
+    }
+  }
+
+
+
+  /**
+   * Attempts to uncompress the data in the provided byte sequence into the
+   * provided byte string builder. Note that if uncompression was not
+   * successful, then the data in the destination buffer should be considered
+   * invalid.
+   *
+   * @param input
+   *          The source data to be uncompressed.
+   * @param output
+   *          The destination buffer to which the uncompressed data will be
+   *          appended.
+   * @param uncompressedSize
+   *          The uncompressed size of the data if known or 0 otherwise.
+   * @return <code>true</code> if decompression was successful or
+   *         <code>false</code> otherwise.
+   * @throws java.util.zip.DataFormatException
+   *           If a problem occurs while attempting to uncompress the data.
+   */
+  public static boolean uncompress(final ByteSequence input,
+      final ByteStringBuilder output, final int uncompressedSize)
+      throws DataFormatException
+  {
+    final byte[] inputBytes = input.toByteArray();
+    byte[] outputBytes = new byte[uncompressedSize > 0 ? uncompressedSize : 0];
+
+    int decompressResult = uncompress(inputBytes, 0, inputBytes.length,
+        outputBytes, 0, outputBytes.length);
+
+    if (decompressResult < 0)
+    {
+      // The destination buffer wasn't big enough. Resize and retry.
+      outputBytes = new byte[-decompressResult];
+      decompressResult = uncompress(inputBytes, 0, inputBytes.length,
+          outputBytes, 0, outputBytes.length);
+    }
+
+    if (decompressResult >= 0)
+    {
+      // It was successful.
+      output.append(outputBytes, 0, decompressResult);
+      return true;
+    }
+
+    // Still unsuccessful. Give up.
+    return false;
+  }
+
+
+
+  /**
+   * Retrieves the printable ASCII representation of the provided byte.
+   *
+   * @param b
+   *          The byte for which to retrieve the printable ASCII representation.
+   * @return The printable ASCII representation of the provided byte, or a space
+   *         if the provided byte does not have printable ASCII representation.
+   */
+  private static char byteToASCII(final byte b)
+  {
+    if (b >= 32 && b <= 126)
+    {
+      return (char) b;
+    }
+
+    return ' ';
+  }
+
+
+
+  // Prevent instantiation.
+  private StaticUtils()
+  {
+    // No implementation required.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StringPrepProfile.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StringPrepProfile.java
new file mode 100644
index 0000000..78d3e39
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/StringPrepProfile.java
@@ -0,0 +1,587 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package com.sun.opends.sdk.util;
+
+
+
+import static com.sun.opends.sdk.util.Validator.ensureNotNull;
+
+import java.text.Normalizer;
+import java.text.Normalizer.Form;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.opends.sdk.ByteSequence;
+
+
+
+/**
+ * This class defines the "stringprep" profile as defined in RFC 4518. It must
+ * be used by all the matching rules that support unicode characters. For a
+ * complete list of such rules, refer to Section 4.2, RFC 4517.
+ */
+public final class StringPrepProfile
+{
+  /**
+   * A Table defining the mapped code-points as per RFC 3454.
+   */
+  private static final class MappingTable
+  {
+    // Set of chars which are deleted from the incoming value.
+    private final static HashSet<Character> MAP_2_NULL = new HashSet<Character>();
+
+    // Set of chars which are replaced by a SPACE when found.
+    private final static HashSet<Character> MAP_2_SPACE = new HashSet<Character>();
+
+    // Table for case-folding. Map of Character and String containing
+    // uppercase and lowercase value as the key-value pair.
+    private final static HashMap<Character, String> CASE_MAP_TABLE =
+      new HashMap<Character, String>();
+
+    static
+    {
+      // Appendix B.1 RFC 3454.
+      final char[][] mapped2null = new char[][] { { '\u0000', '\u0008' },
+          { '\u000E', '\u001F' }, { '\u007F', '\u0084' },
+          { '\u0086', '\u009F' }, { '\u00AD' }, { '\u034F' }, { '\u06DD' },
+          { '\u070F' }, { '\u1806' }, { '\u180B', '\u180E' },
+          { '\u200C', '\u200F' }, { '\u202A', '\u202E' },
+          { '\u2060', '\u2063' }, { '\u206A', '\u206F' },
+          { '\uFE00', '\uFE0F' }, { '\uFEFF' }, { '\uFFF9', '\uFFFC' } };
+
+      for (final char[] element : mapped2null)
+      {
+        if (element.length == 1)
+        {
+          MAP_2_NULL.add(element[0]);
+        }
+        else
+        {
+          // Contains a range of values.
+          for (char c = element[0]; c <= element[1]; c++)
+          {
+            MAP_2_NULL.add(c);
+          }
+        }
+      }
+
+      final char[] mapped2Space = new char[] { '\u0009', 0xA, '\u000B',
+          '\u000C', 0xD, '\u0085', '\u00A0', '\u1680', '\u2000', '\u2001',
+          '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008',
+          '\u2009', '\u200A', '\u2028', '\u2029', '\u202F', '\u205F', '\u3000' };
+
+      for (final char c : mapped2Space)
+      {
+        MAP_2_SPACE.add(c);
+      }
+
+      // Appendix B.2 RFC 3454.
+      // Build an uppercase array and a lowercase array and create a map
+      // of both
+      // values.
+      final char[] upperCaseArr = new char[] { '\u0041', '\u0042', '\u0043',
+          '\u0044', '\u0045', '\u0046', '\u0047', '\u0048', '\u0049', '\u004A',
+          '\u004B', '\u004C', '\u004D', '\u004E', '\u004F', '\u0050', '\u0051',
+          '\u0052', '\u0053', '\u0054', '\u0055', '\u0056', '\u0057', '\u0058',
+          '\u0059', '\u005A', '\u00B5', '\u00C0', '\u00C1', '\u00C2', '\u00C3',
+          '\u00C4', '\u00C5', '\u00C6', '\u00C7', '\u00C8', '\u00C9', '\u00CA',
+          '\u00CB', '\u00CC', '\u00CD', '\u00CE', '\u00CF', '\u00D0', '\u00D1',
+          '\u00D2', '\u00D3', '\u00D4', '\u00D5', '\u00D6', '\u00D8', '\u00D9',
+          '\u00DA', '\u00DB', '\u00DC', '\u00DD', '\u00DE', '\u00DF', '\u0100',
+          '\u0102', '\u0104', '\u0106', '\u0108', '\u010A', '\u010C', '\u010E',
+          '\u0110', '\u0112', '\u0114', '\u0116', '\u0118', '\u011A', '\u011C',
+          '\u011E', '\u0120', '\u0122', '\u0124', '\u0126', '\u0128', '\u012A',
+          '\u012C', '\u012E', '\u0130', '\u0132', '\u0134', '\u0136', '\u0139',
+          '\u013B', '\u013D', '\u013F', '\u0141', '\u0143', '\u0145', '\u0147',
+          '\u0149', '\u014A', '\u014C', '\u014E', '\u0150', '\u0152', '\u0154',
+          '\u0156', '\u0158', '\u015A', '\u015C', '\u015E', '\u0160', '\u0162',
+          '\u0164', '\u0166', '\u0168', '\u016A', '\u016C', '\u016E', '\u0170',
+          '\u0172', '\u0174', '\u0176', '\u0178', '\u0179', '\u017B', '\u017D',
+          '\u017F', '\u0181', '\u0182', '\u0184', '\u0186', '\u0187', '\u0189',
+          '\u018A', '\u018B', '\u018E', '\u018F', '\u0190', '\u0191', '\u0193',
+          '\u0194', '\u0196', '\u0197', '\u0198', '\u019C', '\u019D', '\u019F',
+          '\u01A0', '\u01A2', '\u01A4', '\u01A6', '\u01A7', '\u01A9', '\u01AC',
+          '\u01AE', '\u01AF', '\u01B1', '\u01B2', '\u01B3', '\u01B5', '\u01B7',
+          '\u01B8', '\u01BC', '\u01C4', '\u01C5', '\u01C7', '\u01C8', '\u01CA',
+          '\u01CB', '\u01CD', '\u01CF', '\u01D1', '\u01D3', '\u01D5', '\u01D7',
+          '\u01D9', '\u01DB', '\u01DE', '\u01E0', '\u01E2', '\u01E4', '\u01E6',
+          '\u01E8', '\u01EA', '\u01EC', '\u01EE', '\u01F0', '\u01F1', '\u01F2',
+          '\u01F4', '\u01F6', '\u01F7', '\u01F8', '\u01FA', '\u01FC', '\u01FE',
+          '\u0200', '\u0202', '\u0204', '\u0206', '\u0208', '\u020A', '\u020C',
+          '\u020E', '\u0210', '\u0212', '\u0214', '\u0216', '\u0218', '\u021A',
+          '\u021C', '\u021E', '\u0220', '\u0222', '\u0224', '\u0226', '\u0228',
+          '\u022A', '\u022C', '\u022E', '\u0230', '\u0232', '\u0345', '\u037A',
+          '\u0386', '\u0388', '\u0389', '\u038A', '\u038C', '\u038E', '\u038F',
+          '\u0390', '\u0391', '\u0392', '\u0393', '\u0394', '\u0395', '\u0396',
+          '\u0397', '\u0398', '\u0399', '\u039A', '\u039B', '\u039C', '\u039D',
+          '\u039E', '\u039F', '\u03A0', '\u03A1', '\u03A3', '\u03A4', '\u03A5',
+          '\u03A6', '\u03A7', '\u03A8', '\u03A9', '\u03AA', '\u03AB', '\u03B0',
+          '\u03C2', '\u03D0', '\u03D1', '\u03D2', '\u03D3', '\u03D4', '\u03D5',
+          '\u03D6', '\u03D8', '\u03DA', '\u03DC', '\u03DE', '\u03E0', '\u03E2',
+          '\u03E4', '\u03E6', '\u03E8', '\u03EA', '\u03EC', '\u03EE', '\u03F0',
+          '\u03F1', '\u03F2', '\u03F4', '\u03F5', '\u0400', '\u0401', '\u0402',
+          '\u0403', '\u0404', '\u0405', '\u0406', '\u0407', '\u0408', '\u0409',
+          '\u040A', '\u040B', '\u040C', '\u040D', '\u040E', '\u040F', '\u0410',
+          '\u0411', '\u0412', '\u0413', '\u0414', '\u0415', '\u0416', '\u0417',
+          '\u0418', '\u0419', '\u041A', '\u041B', '\u041C', '\u041D', '\u041E',
+          '\u041F', '\u0420', '\u0421', '\u0422', '\u0423', '\u0424', '\u0425',
+          '\u0426', '\u0427', '\u0428', '\u0429', '\u042A', '\u042B', '\u042C',
+          '\u042D', '\u042E', '\u042F', '\u0460', '\u0462', '\u0464', '\u0466',
+          '\u0468', '\u046A', '\u046C', '\u046E', '\u0470', '\u0472', '\u0474',
+          '\u0476', '\u0478', '\u047A', '\u047C', '\u047E', '\u0480', '\u048A',
+          '\u048C', '\u048E', '\u0490', '\u0492', '\u0494', '\u0496', '\u0498',
+          '\u049A', '\u049C', '\u049E', '\u04A0', '\u04A2', '\u04A4', '\u04A6',
+          '\u04A8', '\u04AA', '\u04AC', '\u04AE', '\u04B0', '\u04B2', '\u04B4',
+          '\u04B6', '\u04B8', '\u04BA', '\u04BC', '\u04BE', '\u04C1', '\u04C3',
+          '\u04C5', '\u04C7', '\u04C9', '\u04CB', '\u04CD', '\u04D0', '\u04D2',
+          '\u04D4', '\u04D6', '\u04D8', '\u04DA', '\u04DC', '\u04DE', '\u04E0',
+          '\u04E2', '\u04E4', '\u04E6', '\u04E8', '\u04EA', '\u04EC', '\u04EE',
+          '\u04F0', '\u04F2', '\u04F4', '\u04F8', '\u0500', '\u0502', '\u0504',
+          '\u0506', '\u0508', '\u050A', '\u050C', '\u050E', '\u0531', '\u0532',
+          '\u0533', '\u0534', '\u0535', '\u0536', '\u0537', '\u0538', '\u0539',
+          '\u053A', '\u053B', '\u053C', '\u053D', '\u053E', '\u053F', '\u0540',
+          '\u0541', '\u0542', '\u0543', '\u0544', '\u0545', '\u0546', '\u0547',
+          '\u0548', '\u0549', '\u054A', '\u054B', '\u054C', '\u054D', '\u054E',
+          '\u054F', '\u0550', '\u0551', '\u0552', '\u0553', '\u0554', '\u0555',
+          '\u0556', '\u0587', '\u1E00', '\u1E02', '\u1E04', '\u1E06', '\u1E08',
+          '\u1E0A', '\u1E0C', '\u1E0E', '\u1E10', '\u1E12', '\u1E14', '\u1E16',
+          '\u1E18', '\u1E1A', '\u1E1C', '\u1E1E', '\u1E20', '\u1E22', '\u1E24',
+          '\u1E26', '\u1E28', '\u1E2A', '\u1E2C', '\u1E2E', '\u1E30', '\u1E32',
+          '\u1E34', '\u1E36', '\u1E38', '\u1E3A', '\u1E3C', '\u1E3E', '\u1E40',
+          '\u1E42', '\u1E44', '\u1E46', '\u1E48', '\u1E4A', '\u1E4C', '\u1E4E',
+          '\u1E50', '\u1E52', '\u1E54', '\u1E56', '\u1E58', '\u1E5A', '\u1E5C',
+          '\u1E5E', '\u1E60', '\u1E62', '\u1E64', '\u1E66', '\u1E68', '\u1E6A',
+          '\u1E6C', '\u1E6E', '\u1E70', '\u1E72', '\u1E74', '\u1E76', '\u1E78',
+          '\u1E7A', '\u1E7C', '\u1E7E', '\u1E80', '\u1E82', '\u1E84', '\u1E86',
+          '\u1E88', '\u1E8A', '\u1E8C', '\u1E8E', '\u1E90', '\u1E92', '\u1E94',
+          '\u1E96', '\u1E97', '\u1E98', '\u1E99', '\u1E9A', '\u1E9B', '\u1EA0',
+          '\u1EA2', '\u1EA4', '\u1EA6', '\u1EA8', '\u1EAA', '\u1EAC', '\u1EAE',
+          '\u1EB0', '\u1EB2', '\u1EB4', '\u1EB6', '\u1EB8', '\u1EBA', '\u1EBC',
+          '\u1EBE', '\u1EC0', '\u1EC2', '\u1EC4', '\u1EC6', '\u1EC8', '\u1ECA',
+          '\u1ECC', '\u1ECE', '\u1ED0', '\u1ED2', '\u1ED4', '\u1ED6', '\u1ED8',
+          '\u1EDA', '\u1EDC', '\u1EDE', '\u1EE0', '\u1EE2', '\u1EE4', '\u1EE6',
+          '\u1EE8', '\u1EEA', '\u1EEC', '\u1EEE', '\u1EF0', '\u1EF2', '\u1EF4',
+          '\u1EF6', '\u1EF8', '\u1F08', '\u1F09', '\u1F0A', '\u1F0B', '\u1F0C',
+          '\u1F0D', '\u1F0E', '\u1F0F', '\u1F18', '\u1F19', '\u1F1A', '\u1F1B',
+          '\u1F1C', '\u1F1D', '\u1F28', '\u1F29', '\u1F2A', '\u1F2B', '\u1F2C',
+          '\u1F2D', '\u1F2E', '\u1F2F', '\u1F38', '\u1F39', '\u1F3A', '\u1F3B',
+          '\u1F3C', '\u1F3D', '\u1F3E', '\u1F3F', '\u1F48', '\u1F49', '\u1F4A',
+          '\u1F4B', '\u1F4C', '\u1F4D', '\u1F50', '\u1F52', '\u1F54', '\u1F56',
+          '\u1F59', '\u1F5B', '\u1F5D', '\u1F5F', '\u1F68', '\u1F69', '\u1F6A',
+          '\u1F6B', '\u1F6C', '\u1F6D', '\u1F6E', '\u1F6F', '\u1F80', '\u1F81',
+          '\u1F82', '\u1F83', '\u1F84', '\u1F85', '\u1F86', '\u1F87', '\u1F88',
+          '\u1F89', '\u1F8A', '\u1F8B', '\u1F8C', '\u1F8D', '\u1F8E', '\u1F8F',
+          '\u1F90', '\u1F91', '\u1F92', '\u1F93', '\u1F94', '\u1F95', '\u1F96',
+          '\u1F97', '\u1F98', '\u1F99', '\u1F9A', '\u1F9B', '\u1F9C', '\u1F9D',
+          '\u1F9E', '\u1F9F', '\u1FA0', '\u1FA1', '\u1FA2', '\u1FA3', '\u1FA4',
+          '\u1FA5', '\u1FA6', '\u1FA7', '\u1FA8', '\u1FA9', '\u1FAA', '\u1FAB',
+          '\u1FAC', '\u1FAD', '\u1FAE', '\u1FAF', '\u1FB2', '\u1FB3', '\u1FB4',
+          '\u1FB6', '\u1FB7', '\u1FB8', '\u1FB9', '\u1FBA', '\u1FBB', '\u1FBC',
+          '\u1FBE', '\u1FC2', '\u1FC3', '\u1FC4', '\u1FC6', '\u1FC7', '\u1FC8',
+          '\u1FC9', '\u1FCA', '\u1FCB', '\u1FCC', '\u1FD2', '\u1FD3', '\u1FD6',
+          '\u1FD7', '\u1FD8', '\u1FD9', '\u1FDA', '\u1FDB', '\u1FE2', '\u1FE3',
+          '\u1FE4', '\u1FE6', '\u1FE7', '\u1FE8', '\u1FE9', '\u1FEA', '\u1FEB',
+          '\u1FEC', '\u1FF2', '\u1FF3', '\u1FF4', '\u1FF6', '\u1FF7', '\u1FF8',
+          '\u1FF9', '\u1FFA', '\u1FFB', '\u1FFC', '\u20A8', '\u2102', '\u2103',
+          '\u2107', '\u2109', '\u210B', '\u210C', '\u210D', '\u2110', '\u2111',
+          '\u2112', '\u2115', '\u2116', '\u2119', '\u211A', '\u211B', '\u211C',
+          '\u211D', '\u2120', '\u2121', '\u2122', '\u2124', '\u2126', '\u2128',
+          '\u212A', '\u212B', '\u212C', '\u212D', '\u2130', '\u2131', '\u2133',
+          '\u213E', '\u213F', '\u2145', '\u2160', '\u2161', '\u2162', '\u2163',
+          '\u2164', '\u2165', '\u2166', '\u2167', '\u2168', '\u2169', '\u216A',
+          '\u216B', '\u216C', '\u216D', '\u216E', '\u216F', '\u24B6', '\u24B7',
+          '\u24B8', '\u24B9', '\u24BA', '\u24BB', '\u24BC', '\u24BD', '\u24BE',
+          '\u24BF', '\u24C0', '\u24C1', '\u24C2', '\u24C3', '\u24C4', '\u24C5',
+          '\u24C6', '\u24C7', '\u24C8', '\u24C9', '\u24CA', '\u24CB', '\u24CC',
+          '\u24CD', '\u24CE', '\u24CF', '\u3371', '\u3373', '\u3375', '\u3380',
+          '\u3381', '\u3382', '\u3383', '\u3384', '\u3385', '\u3386', '\u3387',
+          '\u338A', '\u338B', '\u338C', '\u3390', '\u3391', '\u3392', '\u3393',
+          '\u3394', '\u33A9', '\u33AA', '\u33AB', '\u33AC', '\u33B4', '\u33B5',
+          '\u33B6', '\u33B7', '\u33B8', '\u33B9', '\u33BA', '\u33BB', '\u33BC',
+          '\u33BD', '\u33BE', '\u33BF', '\u33C0', '\u33C1', '\u33C3', '\u33C6',
+          '\u33C7', '\u33C8', '\u33C9', '\u33CB', '\u33CD', '\u33CE', '\u33D7',
+          '\u33D9', '\u33DA', '\u33DC', '\u33DD', '\uFB00', '\uFB01', '\uFB02',
+          '\uFB03', '\uFB04', '\uFB05', '\uFB06', '\uFB13', '\uFB14', '\uFB15',
+          '\uFB16', '\uFB17', '\uFF21', '\uFF22', '\uFF23', '\uFF24', '\uFF25',
+          '\uFF26', '\uFF27', '\uFF28', '\uFF29', '\uFF2A', '\uFF2B', '\uFF2C',
+          '\uFF2D', '\uFF2E', '\uFF2F', '\uFF30', '\uFF31', '\uFF32', '\uFF33',
+          '\uFF34', '\uFF35', '\uFF36', '\uFF37', '\uFF38', '\uFF39', '\uFF3A' };
+      final String[] lowerCaseFoldedArr = new String[] { "\u0061", "\u0062",
+          "\u0063", "\u0064", "\u0065", "\u0066", "\u0067", "\u0068", "\u0069",
+          "\u006A", "\u006B", "\u006C", "\u006D", "\u006E", "\u006F", "\u0070",
+          "\u0071", "\u0072", "\u0073", "\u0074", "\u0075", "\u0076", "\u0077",
+          "\u0078", "\u0079", "\u007A", "\u03BC", "\u00E0", "\u00E1", "\u00E2",
+          "\u00E3", "\u00E4", "\u00E5", "\u00E6", "\u00E7", "\u00E8", "\u00E9",
+          "\u00EA", "\u00EB", "\u00EC", "\u00ED", "\u00EE", "\u00EF", "\u00F0",
+          "\u00F1", "\u00F2", "\u00F3", "\u00F4", "\u00F5", "\u00F6", "\u00F8",
+          "\u00F9", "\u00FA", "\u00FB", "\u00FC", "\u00FD", "\u00FE",
+          "\u0073\u0073", "\u0101", "\u0103", "\u0105", "\u0107", "\u0109",
+          "\u010B", "\u010D", "\u010F", "\u0111", "\u0113", "\u0115", "\u0117",
+          "\u0119", "\u011B", "\u011D", "\u011F", "\u0121", "\u0123", "\u0125",
+          "\u0127", "\u0129", "\u012B", "\u012D", "\u012F", "\u0069\u0307",
+          "\u0133", "\u0135", "\u0137", "\u013A", "\u013C", "\u013E", "\u0140",
+          "\u0142", "\u0144", "\u0146", "\u0148", "\u02BC\u006E", "\u014B",
+          "\u014D", "\u014F", "\u0151", "\u0153", "\u0155", "\u0157", "\u0159",
+          "\u015B", "\u015D", "\u015F", "\u0161", "\u0163", "\u0165", "\u0167",
+          "\u0169", "\u016B", "\u016D", "\u016F", "\u0171", "\u0173", "\u0175",
+          "\u0177", "\u00FF", "\u017A", "\u017C", "\u017E", "\u0073", "\u0253",
+          "\u0183", "\u0185", "\u0254", "\u0188", "\u0256", "\u0257", "\u018C",
+          "\u01DD", "\u0259", "\u025B", "\u0192", "\u0260", "\u0263", "\u0269",
+          "\u0268", "\u0199", "\u026F", "\u0272", "\u0275", "\u01A1", "\u01A3",
+          "\u01A5", "\u0280", "\u01A8", "\u0283", "\u01AD", "\u0288", "\u01B0",
+          "\u028A", "\u028B", "\u01B4", "\u01B6", "\u0292", "\u01B9", "\u01BD",
+          "\u01C6", "\u01C6", "\u01C9", "\u01C9", "\u01CC", "\u01CC", "\u01CE",
+          "\u01D0", "\u01D2", "\u01D4", "\u01D6", "\u01D8", "\u01DA", "\u01DC",
+          "\u01DF", "\u01E1", "\u01E3", "\u01E5", "\u01E7", "\u01E9", "\u01EB",
+          "\u01ED", "\u01EF", "\u006A\u030C", "\u01F3", "\u01F3", "\u01F5",
+          "\u0195", "\u01BF", "\u01F9", "\u01FB", "\u01FD", "\u01FF", "\u0201",
+          "\u0203", "\u0205", "\u0207", "\u0209", "\u020B", "\u020D", "\u020F",
+          "\u0211", "\u0213", "\u0215", "\u0217", "\u0219", "\u021B", "\u021D",
+          "\u021F", "\u019E", "\u0223", "\u0225", "\u0227", "\u0229", "\u022B",
+          "\u022D", "\u022F", "\u0231", "\u0233", "\u03B9", "\u0020\u03B9",
+          "\u03AC", "\u03AD", "\u03AE", "\u03AF", "\u03CC", "\u03CD", "\u03CE",
+          "\u03B9\u0308\u0301", "\u03B1", "\u03B2", "\u03B3", "\u03B4",
+          "\u03B5", "\u03B6", "\u03B7", "\u03B8", "\u03B9", "\u03BA", "\u03BB",
+          "\u03BC", "\u03BD", "\u03BE", "\u03BF", "\u03C0", "\u03C1", "\u03C3",
+          "\u03C4", "\u03C5", "\u03C6", "\u03C7", "\u03C8", "\u03C9", "\u03CA",
+          "\u03CB", "\u03C5\u0308\u0301", "\u03C3", "\u03B2", "\u03B8",
+          "\u03C5", "\u03CD", "\u03CB", "\u03C6", "\u03C0", "\u03D9", "\u03DB",
+          "\u03DD", "\u03DF", "\u03E1", "\u03E3", "\u03E5", "\u03E7", "\u03E9",
+          "\u03EB", "\u03ED", "\u03EF", "\u03BA", "\u03C1", "\u03C3", "\u03B8",
+          "\u03B5", "\u0450", "\u0451", "\u0452", "\u0453", "\u0454", "\u0455",
+          "\u0456", "\u0457", "\u0458", "\u0459", "\u045A", "\u045B", "\u045C",
+          "\u045D", "\u045E", "\u045F", "\u0430", "\u0431", "\u0432", "\u0433",
+          "\u0434", "\u0435", "\u0436", "\u0437", "\u0438", "\u0439", "\u043A",
+          "\u043B", "\u043C", "\u043D", "\u043E", "\u043F", "\u0440", "\u0441",
+          "\u0442", "\u0443", "\u0444", "\u0445", "\u0446", "\u0447", "\u0448",
+          "\u0449", "\u044A", "\u044B", "\u044C", "\u044D", "\u044E", "\u044F",
+          "\u0461", "\u0463", "\u0465", "\u0467", "\u0469", "\u046B", "\u046D",
+          "\u046F", "\u0471", "\u0473", "\u0475", "\u0477", "\u0479", "\u047B",
+          "\u047D", "\u047F", "\u0481", "\u048B", "\u048D", "\u048F", "\u0491",
+          "\u0493", "\u0495", "\u0497", "\u0499", "\u049B", "\u049D", "\u049F",
+          "\u04A1", "\u04A3", "\u04A5", "\u04A7", "\u04A9", "\u04AB", "\u04AD",
+          "\u04AF", "\u04B1", "\u04B3", "\u04B5", "\u04B7", "\u04B9", "\u04BB",
+          "\u04BD", "\u04BF", "\u04C2", "\u04C4", "\u04C6", "\u04C8", "\u04CA",
+          "\u04CC", "\u04CE", "\u04D1", "\u04D3", "\u04D5", "\u04D7", "\u04D9",
+          "\u04DB", "\u04DD", "\u04DF", "\u04E1", "\u04E3", "\u04E5", "\u04E7",
+          "\u04E9", "\u04EB", "\u04ED", "\u04EF", "\u04F1", "\u04F3", "\u04F5",
+          "\u04F9", "\u0501", "\u0503", "\u0505", "\u0507", "\u0509", "\u050B",
+          "\u050D", "\u050F", "\u0561", "\u0562", "\u0563", "\u0564", "\u0565",
+          "\u0566", "\u0567", "\u0568", "\u0569", "\u056A", "\u056B", "\u056C",
+          "\u056D", "\u056E", "\u056F", "\u0570", "\u0571", "\u0572", "\u0573",
+          "\u0574", "\u0575", "\u0576", "\u0577", "\u0578", "\u0579", "\u057A",
+          "\u057B", "\u057C", "\u057D", "\u057E", "\u057F", "\u0580", "\u0581",
+          "\u0582", "\u0583", "\u0584", "\u0585", "\u0586", "\u0565\u0582",
+          "\u1E01", "\u1E03", "\u1E05", "\u1E07", "\u1E09", "\u1E0B", "\u1E0D",
+          "\u1E0F", "\u1E11", "\u1E13", "\u1E15", "\u1E17", "\u1E19", "\u1E1B",
+          "\u1E1D", "\u1E1F", "\u1E21", "\u1E23", "\u1E25", "\u1E27", "\u1E29",
+          "\u1E2B", "\u1E2D", "\u1E2F", "\u1E31", "\u1E33", "\u1E35", "\u1E37",
+          "\u1E39", "\u1E3B", "\u1E3D", "\u1E3F", "\u1E41", "\u1E43", "\u1E45",
+          "\u1E47", "\u1E49", "\u1E4B", "\u1E4D", "\u1E4F", "\u1E51", "\u1E53",
+          "\u1E55", "\u1E57", "\u1E59", "\u1E5B", "\u1E5D", "\u1E5F", "\u1E61",
+          "\u1E63", "\u1E65", "\u1E67", "\u1E69", "\u1E6B", "\u1E6D", "\u1E6F",
+          "\u1E71", "\u1E73", "\u1E75", "\u1E77", "\u1E79", "\u1E7B", "\u1E7D",
+          "\u1E7F", "\u1E81", "\u1E83", "\u1E85", "\u1E87", "\u1E89", "\u1E8B",
+          "\u1E8D", "\u1E8F", "\u1E91", "\u1E93", "\u1E95", "\u0068\u0331",
+          "\u0074\u0308", "\u0077\u030A", "\u0079\u030A", "\u0061\u02BE",
+          "\u1E61", "\u1EA1", "\u1EA3", "\u1EA5", "\u1EA7", "\u1EA9", "\u1EAB",
+          "\u1EAD", "\u1EAF", "\u1EB1", "\u1EB3", "\u1EB5", "\u1EB7", "\u1EB9",
+          "\u1EBB", "\u1EBD", "\u1EBF", "\u1EC1", "\u1EC3", "\u1EC5", "\u1EC7",
+          "\u1EC9", "\u1ECB", "\u1ECD", "\u1ECF", "\u1ED1", "\u1ED3", "\u1ED5",
+          "\u1ED7", "\u1ED9", "\u1EDB", "\u1EDD", "\u1EDF", "\u1EE1", "\u1EE3",
+          "\u1EE5", "\u1EE7", "\u1EE9", "\u1EEB", "\u1EED", "\u1EEF", "\u1EF1",
+          "\u1EF3", "\u1EF5", "\u1EF7", "\u1EF9", "\u1F00", "\u1F01", "\u1F02",
+          "\u1F03", "\u1F04", "\u1F05", "\u1F06", "\u1F07", "\u1F10", "\u1F11",
+          "\u1F12", "\u1F13", "\u1F14", "\u1F15", "\u1F20", "\u1F21", "\u1F22",
+          "\u1F23", "\u1F24", "\u1F25", "\u1F26", "\u1F27", "\u1F30", "\u1F31",
+          "\u1F32", "\u1F33", "\u1F34", "\u1F35", "\u1F36", "\u1F37", "\u1F40",
+          "\u1F41", "\u1F42", "\u1F43", "\u1F44", "\u1F45", "\u03C5\u0313",
+          "\u03C5\u0313\u0300", "\u03C5\u0313\u0301", "\u03C5\u0313\u0342",
+          "\u1F51", "\u1F53", "\u1F55", "\u1F57", "\u1F60", "\u1F61", "\u1F62",
+          "\u1F63", "\u1F64", "\u1F65", "\u1F66", "\u1F67", "\u1F00\u03B9",
+          "\u1F01\u03B9", "\u1F02\u03B9", "\u1F03\u03B9", "\u1F04\u03B9",
+          "\u1F05\u03B9", "\u1F06\u03B9", "\u1F07\u03B9", "\u1F00\u03B9",
+          "\u1F01\u03B9", "\u1F02\u03B9", "\u1F03\u03B9", "\u1F04\u03B9",
+          "\u1F05\u03B9", "\u1F06\u03B9", "\u1F07\u03B9", "\u1F20\u03B9",
+          "\u1F21\u03B9", "\u1F22\u03B9", "\u1F23\u03B9", "\u1F24\u03B9",
+          "\u1F25\u03B9", "\u1F26\u03B9", "\u1F27\u03B9", "\u1F20\u03B9",
+          "\u1F21\u03B9", "\u1F22\u03B9", "\u1F23\u03B9", "\u1F24\u03B9",
+          "\u1F25\u03B9", "\u1F26\u03B9", "\u1F27\u03B9", "\u1F60\u03B9",
+          "\u1F61\u03B9", "\u1F62\u03B9", "\u1F63\u03B9", "\u1F64\u03B9",
+          "\u1F65\u03B9", "\u1F66\u03B9", "\u1F67\u03B9", "\u1F60\u03B9",
+          "\u1F61\u03B9", "\u1F62\u03B9", "\u1F63\u03B9", "\u1F64\u03B9",
+          "\u1F65\u03B9", "\u1F66\u03B9", "\u1F67\u03B9", "\u1F70\u03B9",
+          "\u03B1\u03B9", "\u03AC\u03B9", "\u03B1\u0342", "\u03B1\u0342\u03B9",
+          "\u1FB0", "\u1FB1", "\u1F70", "\u1F71", "\u03B1\u03B9", "\u03B9",
+          "\u1F74\u03B9", "\u03B7\u03B9", "\u03AE\u03B9", "\u03B7\u0342",
+          "\u03B7\u0342\u03B9", "\u1F72", "\u1F73", "\u1F74", "\u1F75",
+          "\u03B7\u03B9", "\u03B9\u0308\u0300", "\u03B9\u0308\u0301",
+          "\u03B9\u0342", "\u03B9\u0308\u0342", "\u1FD0", "\u1FD1", "\u1F76",
+          "\u1F77", "\u03C5\u0308\u0300", "\u03C5\u0308\u0301", "\u03C1\u0313",
+          "\u03C5\u0342", "\u03C5\u0308\u0342", "\u1FE0", "\u1FE1", "\u1F7A",
+          "\u1F7B", "\u1FE5", "\u1F7C\u03B9", "\u03C9\u03B9", "\u03CE\u03B9",
+          "\u03C9\u0342", "\u03C9\u0342\u03B9", "\u1F78", "\u1F79", "\u1F7C",
+          "\u1F7D", "\u03C9\u03B9", "\u0072\u0073", "\u0063", "\u00B0\u0063",
+          "\u025B", "\u00B0\u0066", "\u0068", "\u0068", "\u0068", "\u0069",
+          "\u0069", "\u006C", "\u006E", "\u006E\u006F", "\u0070", "\u0071",
+          "\u0072", "\u0072", "\u0072", "\u0073\u006D", "\u0074\u0065\u006C",
+          "\u0074\u006D", "\u007A", "\u03C9", "\u007A", "\u006B", "\u00E5",
+          "\u0062", "\u0063", "\u0065", "\u0066", "\u006D", "\u03B3", "\u03C0",
+          "\u0064", "\u2170", "\u2171", "\u2172", "\u2173", "\u2174", "\u2175",
+          "\u2176", "\u2177", "\u2178", "\u2179", "\u217A", "\u217B", "\u217C",
+          "\u217D", "\u217E", "\u217F", "\u24D0", "\u24D1", "\u24D2", "\u24D3",
+          "\u24D4", "\u24D5", "\u24D6", "\u24D7", "\u24D8", "\u24D9", "\u24DA",
+          "\u24DB", "\u24DC", "\u24DD", "\u24DE", "\u24DF", "\u24E0", "\u24E1",
+          "\u24E2", "\u24E3", "\u24E4", "\u24E5", "\u24E6", "\u24E7", "\u24E8",
+          "\u24E9", "\u0068\u0070\u0061", "\u0061\u0075", "\u006F\u0076",
+          "\u0070\u0061", "\u006E\u0061", "\u03BC\u0061", "\u006D\u0061",
+          "\u006B\u0061", "\u006B\u0062", "\u006D\u0062", "\u0067\u0062",
+          "\u0070\u0066", "\u006E\u0066", "\u03BC\u0066", "\u0068\u007A",
+          "\u006B\u0068\u007A", "\u006D\u0068\u007A", "\u0067\u0068\u007A",
+          "\u0074\u0068\u007A", "\u0070\u0061", "\u006B\u0070\u0061",
+          "\u006D\u0070\u0061", "\u0067\u0070\u0061", "\u0070\u0076",
+          "\u006E\u0076", "\u03BC\u0076", "\u006D\u0076", "\u006B\u0076",
+          "\u006D\u0076", "\u0070\u0077", "\u006E\u0077", "\u03BC\u0077",
+          "\u006D\u0077", "\u006B\u0077", "\u006D\u0077", "\u006B\u03C9",
+          "\u006D\u03C9", "\u0062\u0071", "\u0063\u2215\u006B\u0067",
+          "\u0063\u006F\u002E", "\u0064\u0062", "\u0067\u0079", "\u0068\u0070",
+          "\u006B\u006B", "\u006B\u006D", "\u0070\u0068", "\u0070\u0070\u006D",
+          "\u0070\u0072", "\u0073\u0076", "\u0077\u0062", "\u0066\u0066",
+          "\u0066\u0069", "\u0066\u006C", "\u0066\u0066\u0069",
+          "\u0066\u0066\u006C", "\u0073\u0074", "\u0073\u0074", "\u0574\u0576",
+          "\u0574\u0565", "\u0574\u056B", "\u057E\u0576", "\u0574\u056D",
+          "\uFF41", "\uFF42", "\uFF43", "\uFF44", "\uFF45", "\uFF46", "\uFF47",
+          "\uFF48", "\uFF49", "\uFF4A", "\uFF4B", "\uFF4C", "\uFF4D", "\uFF4E",
+          "\uFF4F", "\uFF50", "\uFF51", "\uFF52", "\uFF53", "\uFF54", "\uFF55",
+          "\uFF56", "\uFF57", "\uFF58", "\uFF59", "\uFF5A" };
+      for (int count = 0; count < upperCaseArr.length; count++)
+      {
+        CASE_MAP_TABLE.put(upperCaseArr[count], lowerCaseFoldedArr[count]);
+      }
+    }
+
+
+
+    // Gets the mapped String.
+    private static void map(final StringBuilder buffer,
+        final ByteSequence sequence, final boolean trim, final boolean foldCase)
+    {
+      final String value = sequence.toString();
+      for (int i = 0; i < value.length(); i++)
+      {
+        final char c = value.charAt(i);
+        if (MAP_2_NULL.contains(c))
+        {
+          continue;
+        }
+
+        if (MAP_2_SPACE.contains(c))
+        {
+          final int buffLen = buffer.length();
+          if (trim && buffLen == 0 || buffLen > 0
+              && buffer.charAt(buffLen - 1) == SPACE_CHAR)
+          {
+            /**
+             * Do not map this character into a space if: a . trimming is wanted
+             * and this was the first char. b. The last character was a space.
+             **/
+            continue;
+          }
+          buffer.append(SPACE_CHAR);
+          continue;
+        }
+
+        if (foldCase)
+        {
+          final String mapping = CASE_MAP_TABLE.get(c);
+          if (mapping != null)
+          {
+            buffer.append(mapping);
+            continue;
+          }
+        }
+        // It came here so no match was found.
+        buffer.append(c);
+      }
+    }
+
+
+
+    private MappingTable()
+    {
+      // Prevent instantiation.
+    }
+  }
+
+
+
+  /**
+   * Defines SPACE character.
+   */
+  private static final char SPACE_CHAR = '\u0020';
+
+  /**
+   * Indicates whether case should be folded during string preparation.
+   */
+  public static final boolean CASE_FOLD = true;
+
+  /**
+   * Indicates whether case should not be folded during string preparation.
+   */
+  public static final boolean NO_CASE_FOLD = false;
+
+  /**
+   * Indicates whether leading and trailing spaces should be trimmed during
+   * string preparation.
+   */
+  public static final boolean TRIM = true;
+
+
+
+  /**
+   * Prepares an attribute or assertion value as per stringprep algorithm
+   * defined in RFC 4518.
+   *
+   * @param buffer
+   *          The buffer to which the prepared form of the string should be
+   *          appended.
+   * @param sequence
+   *          The {@link org.opends.sdk.ByteSequence} that needs preparation.
+   * @param trim
+   *          Indicates whether leading and trailing spaces should be omitted
+   *          from the string representation.
+   * @param foldCase
+   *          Indicates whether the case will be folded during mapping.
+   * @see <a href="http://www.rfc-editor.org/rfc/rfc4518.txt"> Internationalized
+   *      String Preparation</a>
+   */
+  public static void prepareUnicode(final StringBuilder buffer,
+      final ByteSequence sequence, final boolean trim, final boolean foldCase)
+  {
+    ensureNotNull(buffer);
+    ensureNotNull(sequence);
+    // Optimize in the case of purely ascii characters which is the most
+    // common case.
+    final int length = sequence.length();
+    for (int i = 0; i < length; i++)
+    {
+      if ((sequence.byteAt(i) & 0x7F) != sequence.byteAt(i))
+      {
+        // Map the attribute value.
+        map(buffer, sequence.subSequence(i, length), trim, foldCase);
+        // Normalize the attribute value.
+        String normalizedForm = Normalizer.normalize(buffer, Form.NFKD);
+        buffer.setLength(0);
+        buffer.append(normalizedForm);
+        break;
+      }
+      int buffLen = buffer.length();
+      switch (sequence.byteAt(i))
+      {
+      case ' ':
+        if (trim && buffLen == 0 || buffLen > 0
+            && buffer.charAt(buffLen - 1) == SPACE_CHAR)
+        {
+          break;
+        }
+        buffer.append(' ');
+        break;
+      default:
+        final byte b = sequence.byteAt(i);
+        // Perform mapping.
+        if (b >= '\u0009' && b < '\u000E')
+        {
+          // These characters are mapped to a SPACE.
+          buffLen = buffer.length();
+          if (trim && buffLen == 0 || buffLen > 0
+              && buffer.charAt(buffLen - 1) == ' ')
+          {
+            /**
+             * Do not map this character into a space if: a . trimming is
+             * desired and this was the leading char. b. The last character was
+             * a space.
+             **/
+            break;
+          }
+          else
+          {
+            buffer.append(SPACE_CHAR);
+          }
+        }
+        else if (b >= '\u0000' && b <= '\u0008' || b >= '\u000E'
+            && b <= '\u001F' || b == '\u007F')
+        {
+          // These characters are mapped to nothing and hence not copied
+          // over..
+          break;
+        }
+        else if (foldCase && b >= 65 && b <= 90)
+        {
+          // If case-folding is allowed then map to the lower case.
+          buffer.append((char) (b + 32));
+        }
+        else
+        {
+          buffer.append((char) b);
+        }
+        break;
+      }
+    }
+    if (trim)
+    {
+      // Strip off any trailing spaces.
+      for (int i = buffer.length() - 1; i > 0; i--)
+      {
+        if (buffer.charAt(i) == SPACE_CHAR)
+        {
+          buffer.delete(i, i + 1);
+        }
+        else
+        {
+          break;
+        }
+      }
+    }
+  }
+
+
+
+  // Checks each character and replaces it with its mapping.
+  private static void map(final StringBuilder buffer, final ByteSequence value,
+      final boolean trim, final boolean foldCase)
+  {
+    MappingTable.map(buffer, value, trim, foldCase);
+  }
+
+
+
+  // Prevent instantiation.
+  private StringPrepProfile()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SubstringReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SubstringReader.java
new file mode 100644
index 0000000..04d46d6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/SubstringReader.java
@@ -0,0 +1,184 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+/**
+ * A sub-string reader.
+ */
+public class SubstringReader
+{
+  // The source string.
+  private final String source;
+  // The current position.
+  private int pos;
+  // The marked position.
+  private int mark;
+  // The length of the source.
+  private final int length;
+
+
+
+  /**
+   * Creates an instance of SubstringReader.
+   *
+   * @param s
+   *          the source of the reader.
+   */
+  public SubstringReader(final String s)
+  {
+    Validator.ensureNotNull(s);
+    source = s;
+    length = s.length();
+    pos = 0;
+    mark = 0;
+  }
+
+
+
+  /**
+   * Returns the source string.
+   *
+   * @return source string.
+   */
+  public String getString()
+  {
+    return source;
+  }
+
+
+
+  /**
+   * Marks the present position in the stream. Subsequent calls to reset() will
+   * reposition the stream to this point.
+   */
+  public void mark()
+  {
+    mark = pos;
+  }
+
+
+
+  /**
+   * Returns the current position of the reader.
+   *
+   * @return current position of the reader.
+   */
+  public int pos()
+  {
+    return pos;
+  }
+
+
+
+  /**
+   * Attemps to read a character from the current position. The caller must
+   * ensure that the source string has the data available from the current
+   * position.
+   *
+   * @return The characted at the current position.
+   * @Exception StringIndexOutOfBoundsException if there is no more data
+   *            available to read.
+   */
+  public char read()
+  {
+    if (pos >= length)
+    {
+      throw new StringIndexOutOfBoundsException();
+    }
+    return source.charAt(pos++);
+  }
+
+
+
+  /**
+   * Attemps to read a substring of the specified length from the current
+   * position. The caller must ensure that the requested length is within the
+   * bounds i.e. the requested length from the current position should not
+   * exceed the length of the source string.
+   *
+   * @param length
+   *          The number of characters to read.
+   * @return The substring.
+   * @Exception StringIndexOutOfBoundsException if the length exceeds the
+   *            allowed length.
+   */
+  public String read(final int length)
+  {
+    if (length > this.length || pos + length > this.length)
+    {
+      throw new StringIndexOutOfBoundsException();
+    }
+    final String substring = source.substring(pos, pos + length);
+    pos += length;
+    return substring;
+  }
+
+
+
+  /**
+   * Returns the remaining length of the available data.
+   *
+   * @return remaining length.
+   */
+  public int remaining()
+  {
+    return length - pos;
+  }
+
+
+
+  /**
+   * Resets the stream to the most recent mark, or to the beginning of the
+   * string if it has never been marked.
+   */
+  public void reset()
+  {
+    pos = mark;
+  }
+
+
+
+  /**
+   * Skips the whitespace characters and advances the reader to the next non
+   * whitespace character.
+   *
+   * @return number of whitespace characters skipped.
+   */
+  public int skipWhitespaces()
+  {
+    int skipped = 0;
+    while (pos < length && source.charAt(pos) == ' ')
+    {
+      skipped++;
+      pos++;
+    }
+    return skipped;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Validator.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Validator.java
new file mode 100644
index 0000000..11718c4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/Validator.java
@@ -0,0 +1,213 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+/**
+ * Common methods for validating method arguments.
+ */
+public final class Validator
+{
+
+  /**
+   * Throws a {@code NullPointerException} if any of the provided arguments are
+   * {@code null}.
+   *
+   * @param objects
+   *          The objects to test.
+   * @throws NullPointerException
+   *           If any of the provided arguments are {@code null}.
+   */
+  public static void ensureNotNull(final Object... objects)
+      throws NullPointerException
+  {
+    for (final Object o : objects)
+    {
+      if (o == null)
+      {
+        throw new NullPointerException();
+      }
+    }
+  }
+
+
+
+  /**
+   * Throws a {@code NullPointerException} if any of the provided arguments are
+   * {@code null}.
+   *
+   * @param o1
+   *          The first object to test.
+   * @param o2
+   *          The second object to test.
+   * @throws NullPointerException
+   *           If any of the provided arguments are {@code null}.
+   */
+  public static void ensureNotNull(final Object o1, final Object o2)
+      throws NullPointerException
+  {
+    if (o1 == null || o2 == null)
+    {
+      throw new NullPointerException();
+    }
+  }
+
+
+
+  /**
+   * Throws a {@code NullPointerException} if any of the provided arguments are
+   * {@code null}.
+   *
+   * @param o1
+   *          The first object to test.
+   * @param o2
+   *          The second object to test.
+   * @param o3
+   *          The third object to test.
+   * @throws NullPointerException
+   *           If any of the provided arguments are {@code null}.
+   */
+  public static void ensureNotNull(final Object o1, final Object o2,
+      final Object o3) throws NullPointerException
+  {
+    if (o1 == null || o2 == null || o3 == null)
+    {
+      throw new NullPointerException();
+    }
+  }
+
+
+
+  /**
+   * Throws a {@code NullPointerException} if any of the provided arguments are
+   * {@code null}.
+   *
+   * @param o1
+   *          The first object to test.
+   * @param o2
+   *          The second object to test.
+   * @param o3
+   *          The third object to test.
+   * @param o4
+   *          The fourth object to test.
+   * @throws NullPointerException
+   *           If any of the provided arguments are {@code null}.
+   */
+  public static void ensureNotNull(final Object o1, final Object o2,
+      final Object o3, final Object o4) throws NullPointerException
+  {
+    if (o1 == null || o2 == null || o3 == null || o4 == null)
+    {
+      throw new NullPointerException();
+    }
+  }
+
+
+
+  /**
+   * Throws a {@code NullPointerException} if any of the provided arguments are
+   * {@code null}.
+   *
+   * @param o1
+   *          The first object to test.
+   * @param o2
+   *          The second object to test.
+   * @param o3
+   *          The third object to test.
+   * @param o4
+   *          The fourth object to test.
+   * @param o5
+   *          The fifth object to test.
+   * @throws NullPointerException
+   *           If any of the provided arguments are {@code null}.
+   */
+  public static void ensureNotNull(final Object o1, final Object o2,
+      final Object o3, final Object o4, final Object o5)
+      throws NullPointerException
+  {
+    if (o1 == null || o2 == null || o3 == null || o4 == null || o5 == null)
+    {
+      throw new NullPointerException();
+    }
+  }
+
+
+
+  /**
+   * Throws a {@code NullPointerException} if the provided argument is {@code
+   * null}. This method returns a reference to its single parameter so that it
+   * can be easily used in constructors.
+   *
+   * @param <T>
+   *          The type of {@code o1}.
+   * @param o1
+   *          The object to test.
+   * @return A reference to {@code o1}.
+   * @throws NullPointerException
+   *           If the provided argument is {@code null}.
+   */
+  public static <T> T ensureNotNull(final T o1) throws NullPointerException
+  {
+    if (o1 == null)
+    {
+      throw new NullPointerException();
+    }
+    return o1;
+  }
+
+
+
+  /**
+   * Throws an {@code IllegalArgumentException} if the provided condition is
+   * {@code false}.
+   *
+   * @param condition
+   *          The condition, which must be {@code true} to avoid an exception.
+   * @param message
+   *          The error message to include in the exception if it is thrown.
+   * @throws IllegalArgumentException
+   *           If {@code condition} was {@code false}.
+   */
+  public static void ensureTrue(final boolean condition, final String message)
+      throws IllegalArgumentException
+  {
+    if (!condition)
+    {
+      throw new IllegalArgumentException(message);
+    }
+  }
+
+
+
+  // Prevent instantiation.
+  private Validator()
+  {
+    // No implementation required.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/package-info.java
new file mode 100644
index 0000000..25ebe0f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/com/sun/opends/sdk/util/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes providing utility functionality.
+ */
+package com.sun.opends.sdk.util;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AVA.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AVA.java
new file mode 100644
index 0000000..70c5784
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AVA.java
@@ -0,0 +1,977 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.*;
+
+import java.util.Comparator;
+
+import org.opends.sdk.schema.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An attribute value assertion (AVA) as defined in RFC 4512 section 2.3
+ * consists of an attribute description with zero options and an attribute
+ * value.
+ * <p>
+ * The following are examples of string representations of AVAs:
+ *
+ * <pre>
+ * uid=12345
+ * ou=Engineering
+ * cn=Kurt Zeilenga
+ * </pre>
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4512#section-2.3">RFC 4512 -
+ *      Lightweight Directory Access Protocol (LDAP): Directory Information
+ *      Models </a>
+ */
+public final class AVA implements Comparable<AVA>
+{
+  /**
+   * Parses the provided LDAP string representation of an AVA using the default
+   * schema.
+   *
+   * @param ava
+   *          The LDAP string representation of an AVA.
+   * @return The parsed RDN.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ava} is not a valid LDAP string representation of a
+   *           AVA.
+   * @throws NullPointerException
+   *           If {@code ava} was {@code null}.
+   */
+  public static AVA valueOf(final String ava)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return valueOf(ava, Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of an AVA using the provided
+   * schema.
+   *
+   * @param ava
+   *          The LDAP string representation of a AVA.
+   * @param schema
+   *          The schema to use when parsing the AVA.
+   * @return The parsed AVA.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ava} is not a valid LDAP string representation of a
+   *           AVA.
+   * @throws NullPointerException
+   *           If {@code ava} or {@code schema} was {@code null}.
+   */
+  public static AVA valueOf(final String ava, final Schema schema)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    final SubstringReader reader = new SubstringReader(ava);
+    try
+    {
+      return decode(reader, schema);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      final LocalizableMessage message = ERR_RDN_TYPE_NOT_FOUND.get(ava,
+          e.getMessageObject());
+      throw new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  static AVA decode(final SubstringReader reader, final Schema schema)
+      throws LocalizedIllegalArgumentException, UnknownSchemaElementException
+  {
+    // Skip over any spaces at the beginning.
+    reader.skipWhitespaces();
+
+    final AttributeType attribute = readAttributeName(reader, schema);
+
+    // Make sure that we're not at the end of the DN string because
+    // that would be invalid.
+    if (reader.remaining() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME
+          .get(reader.getString(), attribute.getNameOrOID());
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Skip over any spaces if we have.
+    reader.skipWhitespaces();
+
+    // The next character must be an equal sign. If it is not, then
+    // that's an error.
+    char c;
+    if ((c = reader.read()) != '=')
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(
+          reader.getString(), attribute.getNameOrOID(), c);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Skip over any spaces after the equal sign.
+    reader.skipWhitespaces();
+
+    // Parse the value for this RDN component.
+    final ByteString value = readAttributeValue(reader);
+
+    return new AVA(attribute, value);
+  }
+
+
+
+  private static void appendHexChars(final SubstringReader reader,
+      final StringBuilder valueBuffer, final StringBuilder hexBuffer)
+      throws DecodeException
+  {
+    final int length = hexBuffer.length();
+    if (length == 0)
+    {
+      return;
+    }
+
+    if ((length % 2) != 0)
+    {
+      final LocalizableMessage message = ERR_HEX_DECODE_INVALID_LENGTH
+          .get(hexBuffer);
+      DecodeException.error(message);
+    }
+
+    int pos = 0;
+    final int arrayLength = (length / 2);
+    final byte[] hexArray = new byte[arrayLength];
+    for (int i = 0; i < arrayLength; i++)
+    {
+      switch (hexBuffer.charAt(pos++))
+      {
+      case '0':
+        hexArray[i] = 0x00;
+        break;
+      case '1':
+        hexArray[i] = 0x10;
+        break;
+      case '2':
+        hexArray[i] = 0x20;
+        break;
+      case '3':
+        hexArray[i] = 0x30;
+        break;
+      case '4':
+        hexArray[i] = 0x40;
+        break;
+      case '5':
+        hexArray[i] = 0x50;
+        break;
+      case '6':
+        hexArray[i] = 0x60;
+        break;
+      case '7':
+        hexArray[i] = 0x70;
+        break;
+      case '8':
+        hexArray[i] = (byte) 0x80;
+        break;
+      case '9':
+        hexArray[i] = (byte) 0x90;
+        break;
+      case 'A':
+      case 'a':
+        hexArray[i] = (byte) 0xA0;
+        break;
+      case 'B':
+      case 'b':
+        hexArray[i] = (byte) 0xB0;
+        break;
+      case 'C':
+      case 'c':
+        hexArray[i] = (byte) 0xC0;
+        break;
+      case 'D':
+      case 'd':
+        hexArray[i] = (byte) 0xD0;
+        break;
+      case 'E':
+      case 'e':
+        hexArray[i] = (byte) 0xE0;
+        break;
+      case 'F':
+      case 'f':
+        hexArray[i] = (byte) 0xF0;
+        break;
+      default:
+        final LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER
+            .get(hexBuffer, hexBuffer.charAt(pos - 1));
+        throw DecodeException.error(message);
+      }
+
+      switch (hexBuffer.charAt(pos++))
+      {
+      case '0':
+        // No action required.
+        break;
+      case '1':
+        hexArray[i] |= 0x01;
+        break;
+      case '2':
+        hexArray[i] |= 0x02;
+        break;
+      case '3':
+        hexArray[i] |= 0x03;
+        break;
+      case '4':
+        hexArray[i] |= 0x04;
+        break;
+      case '5':
+        hexArray[i] |= 0x05;
+        break;
+      case '6':
+        hexArray[i] |= 0x06;
+        break;
+      case '7':
+        hexArray[i] |= 0x07;
+        break;
+      case '8':
+        hexArray[i] |= 0x08;
+        break;
+      case '9':
+        hexArray[i] |= 0x09;
+        break;
+      case 'A':
+      case 'a':
+        hexArray[i] |= 0x0A;
+        break;
+      case 'B':
+      case 'b':
+        hexArray[i] |= 0x0B;
+        break;
+      case 'C':
+      case 'c':
+        hexArray[i] |= 0x0C;
+        break;
+      case 'D':
+      case 'd':
+        hexArray[i] |= 0x0D;
+        break;
+      case 'E':
+      case 'e':
+        hexArray[i] |= 0x0E;
+        break;
+      case 'F':
+      case 'f':
+        hexArray[i] |= 0x0F;
+        break;
+      default:
+        final LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER
+            .get(hexBuffer, hexBuffer.charAt(pos - 1));
+        throw DecodeException.error(message);
+      }
+    }
+    try
+    {
+      valueBuffer.append(new String(hexArray, "UTF-8"));
+    }
+    catch (final Exception e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE
+          .get(reader.getString(), String.valueOf(e));
+      throw DecodeException.error(message);
+    }
+    // Clean up the hex buffer.
+    hexBuffer.setLength(0);
+  }
+
+
+
+  private static ByteString delimitAndEvaluateEscape(
+      final SubstringReader reader) throws DecodeException
+  {
+    char c = '\u0000';
+    final StringBuilder valueBuffer = new StringBuilder();
+    final StringBuilder hexBuffer = new StringBuilder();
+    reader.skipWhitespaces();
+
+    boolean escaped = false;
+    while (reader.remaining() > 0)
+    {
+      c = reader.read();
+      if (escaped)
+      {
+        // This character is escaped.
+        if (isHexDigit(c))
+        {
+          // Unicode characters.
+          if (!(reader.remaining() > 0))
+          {
+            final LocalizableMessage msg = ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID
+                .get(reader.getString());
+            DecodeException.error(msg);
+          }
+          // Check the next byte for hex.
+          final char c2 = reader.read();
+          if (isHexDigit(c2))
+          {
+            hexBuffer.append(c);
+            hexBuffer.append(c2);
+            // We may be at the end.
+            if (reader.remaining() == 0)
+            {
+              appendHexChars(reader, valueBuffer, hexBuffer);
+            }
+          }
+          else
+          {
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID
+                .get(reader.getString());
+            DecodeException.error(message);
+          }
+        }
+        else
+        {
+          appendHexChars(reader, valueBuffer, hexBuffer);
+          valueBuffer.append(c);
+        }
+        escaped = false;
+      }
+      else if (c == 0x5C) // The backslash character
+      {
+        // We found an escape.
+        escaped = true;
+      }
+      else
+      {
+        // Check for delimited chars.
+        if (c == '+' || c == ',' || c == ';')
+        {
+          reader.reset();
+          // Return what we have got here so far.
+          appendHexChars(reader, valueBuffer, hexBuffer);
+          return ByteString.valueOf(valueBuffer.toString());
+        }
+        // It is definitely not a delimiter at this point.
+        appendHexChars(reader, valueBuffer, hexBuffer);
+        valueBuffer.append(c);
+        // reader.mark();
+      }
+      reader.mark();
+    }
+
+    reader.reset();
+    return ByteString.valueOf(valueBuffer.toString());
+  }
+
+
+
+  private static AttributeType readAttributeName(final SubstringReader reader,
+      final Schema schema) throws LocalizedIllegalArgumentException,
+      UnknownSchemaElementException
+  {
+    int length = 1;
+    reader.mark();
+
+    // The next character must be either numeric (for an OID) or
+    // alphabetic (for an attribute description).
+    char c = reader.read();
+    if (isDigit(c))
+    {
+      boolean lastWasPeriod = false;
+      while (reader.remaining() > 0 && (c = reader.read()) != '=')
+      {
+        if (c == '.')
+        {
+          if (lastWasPeriod)
+          {
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS
+                .get(reader.getString(), reader.pos() - 1);
+            throw new LocalizedIllegalArgumentException(message);
+          }
+          else
+          {
+            lastWasPeriod = true;
+          }
+        }
+        else if (!isDigit(c))
+        {
+          // This must have been an illegal character.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER
+              .get(reader.getString(), reader.pos() - 1);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+        else
+        {
+          lastWasPeriod = false;
+        }
+        length++;
+      }
+    }
+    else if (isAlpha(c))
+    {
+      // This must be an attribute description. In this case, we will
+      // only accept alphabetic characters, numeric digits, and the hyphen.
+      while (reader.remaining() > 0)
+      {
+        c = reader.read();
+        if (length == 0 && !isAlpha(c))
+        {
+          // This is an illegal character.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR
+              .get(reader.getString(), c, reader.pos() - 1);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        if (c == '=')
+        {
+          // End of the attribute.
+          break;
+        }
+        else if (c == ' ')
+        {
+          // Got a whitespace.It MUST be the end of the attribute
+          // Make sure that the next non-whitespace character is '='.
+          reader.skipWhitespaces();
+          // Read back the next char.
+          c = reader.read();
+          if (c == '=')
+          {
+            break;
+          }
+          else
+          {
+            // This is an illegal character.
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR
+                .get(reader.getString(), c, reader.pos() - 1);
+            throw new LocalizedIllegalArgumentException(message);
+          }
+        }
+        else if (!isAlpha(c) && !isDigit(c) && c != '-')
+        {
+          // This is an illegal character.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR
+              .get(reader.getString(), c, reader.pos() - 1);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        length++;
+      }
+    }
+    else
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR
+          .get(reader.getString(), c, reader.pos() - 1);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    reader.reset();
+
+    // Return the position of the first non-space character after the
+    // token.
+
+    return schema.getAttributeType(reader.read(length));
+  }
+
+
+
+  private static ByteString readAttributeValue(final SubstringReader reader)
+      throws LocalizedIllegalArgumentException
+  {
+    // All leading spaces have already been stripped so we can start
+    // reading the value. However, it may be empty so check for that.
+    if (reader.remaining() == 0)
+    {
+      return ByteString.empty();
+    }
+
+    reader.mark();
+
+    // Look at the first character. If it is an octothorpe (#), then
+    // that means that the value should be a hex string.
+    char c = reader.read();
+    int length = 0;
+    if (c == '#')
+    {
+      // The first two characters must be hex characters.
+      reader.mark();
+      if (reader.remaining() < 2)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT
+            .get(reader.getString());
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      for (int i = 0; i < 2; i++)
+      {
+        c = reader.read();
+        if (isHexDigit(c))
+        {
+          length++;
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT
+              .get(reader.getString(), c);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      // The rest of the value must be a multiple of two hex
+      // characters. The end of the value may be designated by the
+      // end of the DN, a comma or semicolon, or a space.
+      while (reader.remaining() > 0)
+      {
+        c = reader.read();
+        if (isHexDigit(c))
+        {
+          length++;
+
+          if (reader.remaining() > 0)
+          {
+            c = reader.read();
+            if (isHexDigit(c))
+            {
+              length++;
+            }
+            else
+            {
+              final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT
+                  .get(reader.getString(), c);
+              throw new LocalizedIllegalArgumentException(message);
+            }
+          }
+          else
+          {
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT
+                .get(reader.getString());
+            throw new LocalizedIllegalArgumentException(message);
+          }
+        }
+        else if ((c == ' ') || (c == ',') || (c == ';'))
+        {
+          // This denotes the end of the value.
+          break;
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT
+              .get(reader.getString(), c);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      // At this point, we should have a valid hex string. Convert it
+      // to a byte array and set that as the value of the provided
+      // octet string.
+      try
+      {
+        reader.reset();
+        return ByteString.wrap(hexStringToByteArray(reader.read(length)));
+      }
+      catch (final Exception e)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE
+            .get(reader.getString(), String.valueOf(e));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+    }
+
+    // If the first character is a quotation mark, then the value
+    // should continue until the corresponding closing quotation mark.
+    else if (c == '"')
+    {
+      reader.mark();
+      while (true)
+      {
+        if (reader.remaining() <= 0)
+        {
+          // We hit the end of the AVA before the closing quote.
+          // That's an error.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE
+              .get(reader.getString());
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        if (reader.read() == '"')
+        {
+          // This is the end of the value.
+          break;
+        }
+        length++;
+      }
+      reader.reset();
+      final ByteString retString = ByteString.valueOf(reader.read(length));
+      reader.read();
+      return retString;
+    }
+
+    // Otherwise, use general parsing to find the end of the value.
+    else
+    {
+      reader.reset();
+      ByteString bytes;
+      try
+      {
+        bytes = delimitAndEvaluateEscape(reader);
+      }
+      catch (final DecodeException e)
+      {
+        throw new LocalizedIllegalArgumentException(e.getMessageObject());
+      }
+      if (bytes.length() == 0)
+      {
+        // We don't allow an empty attribute value.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR
+            .get(reader.getString(), reader.pos());
+        throw new LocalizedIllegalArgumentException(message);
+      }
+      return bytes;
+    }
+  }
+
+
+
+  private final AttributeType attributeType;
+
+  private final ByteString attributeValue;
+
+  // Cached normalized value using equality matching rule.
+  private ByteString equalityNormalizedAttributeValue = null;
+
+  // Cached normalized value using ordering matching rule.
+  private ByteString orderingNormalizedAttributeValue = null;
+
+
+
+  /**
+   * Creates a new attribute value assertion (AVA) using the provided attribute
+   * type and value.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @param attributeValue
+   *          The attribute value.
+   * @throws NullPointerException
+   *           If {@code attributeType} or {@code attributeValue} was
+   *           {@code null}.
+   */
+  public AVA(final AttributeType attributeType, final ByteString attributeValue)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeType, attributeValue);
+
+    this.attributeType = attributeType;
+    this.attributeValue = attributeValue;
+  }
+
+
+
+  /**
+   * Creates a new attribute value assertion (AVA) using the provided attribute
+   * type and value decoded using the default schema.
+   * <p>
+   * If {@code attributeValue} is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @param attributeValue
+   *          The attribute value.
+   * @throws UnknownSchemaElementException
+   *           If {@code attributeType} was not found in the default schema.
+   * @throws NullPointerException
+   *           If {@code attributeType} or {@code attributeValue} was
+   *           {@code null}.
+   */
+  public AVA(final String attributeType, final Object attributeValue)
+      throws UnknownSchemaElementException, NullPointerException
+  {
+    Validator.ensureNotNull(attributeType, attributeValue);
+
+    this.attributeType = Schema.getDefaultSchema().getAttributeType(
+        attributeType);
+    this.attributeValue = ByteString.valueOf(attributeValue);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int compareTo(final AVA ava)
+  {
+    final int result = attributeType.compareTo(ava.attributeType);
+    if (result != 0)
+    {
+      return result > 0 ? 1 : -1;
+    }
+
+    final ByteString normalizedValue = getOrderingNormalizedValue();
+    final ByteString otherNormalizedValue = ava.getOrderingNormalizedValue();
+    final MatchingRule rule = attributeType.getOrderingMatchingRule();
+    if (rule != null)
+    {
+      final Comparator<ByteSequence> comparator = rule.comparator();
+      return comparator.compare(normalizedValue, otherNormalizedValue);
+    }
+    else
+    {
+      return normalizedValue.compareTo(otherNormalizedValue);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    else if (obj instanceof AVA)
+    {
+      final AVA ava = (AVA) obj;
+
+      if (!attributeType.equals(ava.attributeType))
+      {
+        return false;
+      }
+
+      final ByteString normalizedValue = getEqualityNormalizedValue();
+      final ByteString otherNormalizedValue = ava.getEqualityNormalizedValue();
+      final MatchingRule rule = attributeType.getEqualityMatchingRule();
+      if (rule != null)
+      {
+        final Comparator<ByteSequence> comparator = rule.comparator();
+        return comparator.compare(normalizedValue, otherNormalizedValue) != 0 ? false
+            : true;
+      }
+      else
+      {
+        return normalizedValue.equals(otherNormalizedValue);
+      }
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Returns the attribute type associated with this AVA.
+   *
+   * @return The attribute type associated with this AVA.
+   */
+  public AttributeType getAttributeType()
+  {
+    return attributeType;
+  }
+
+
+
+  /**
+   * Returns the attribute value associated with this AVA.
+   *
+   * @return The attribute value associated with this AVA.
+   */
+  public ByteString getAttributeValue()
+  {
+    return attributeValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return attributeType.hashCode() * 31
+        + getEqualityNormalizedValue().hashCode();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    return toString(builder).toString();
+  }
+
+
+
+  StringBuilder toString(final StringBuilder builder)
+  {
+    if (!attributeType.getNames().iterator().hasNext())
+    {
+      builder.append(attributeType.getOID());
+      builder.append("=#");
+      StaticUtils.toHex(attributeValue, builder);
+    }
+    else
+    {
+      final String name = attributeType.getNameOrOID();
+      builder.append(name);
+      builder.append("=");
+
+      final Syntax syntax = attributeType.getSyntax();
+      if (!syntax.isHumanReadable())
+      {
+        builder.append("#");
+        StaticUtils.toHex(attributeValue, builder);
+      }
+      else
+      {
+        final String str = attributeValue.toString();
+        if (str.length() == 0)
+        {
+          return builder;
+        }
+        char c = str.charAt(0);
+        int startPos = 0;
+        if ((c == ' ') || (c == '#'))
+        {
+          builder.append('\\');
+          builder.append(c);
+          startPos = 1;
+        }
+        final int length = str.length();
+        for (int si = startPos; si < length; si++)
+        {
+          c = str.charAt(si);
+          if (c < ' ')
+          {
+            for (final byte b : getBytes(String.valueOf(c)))
+            {
+              builder.append('\\');
+              builder.append(StaticUtils.byteToLowerHex(b));
+            }
+          }
+          else
+          {
+            if ((c == ' ' && si == length - 1)
+                || (c == '"' || c == '+' || c == ',' || c == ';' || c == '<'
+                    || c == '=' || c == '>' || c == '\\' || c == '\u0000'))
+            {
+              builder.append('\\');
+            }
+            builder.append(c);
+          }
+        }
+      }
+    }
+    return builder;
+  }
+
+
+
+  private ByteString getEqualityNormalizedValue()
+  {
+    final ByteString normalizedValue = equalityNormalizedAttributeValue;
+
+    if (normalizedValue != null)
+    {
+      return normalizedValue;
+    }
+
+    final MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
+    if (matchingRule != null)
+    {
+      try
+      {
+        equalityNormalizedAttributeValue = matchingRule
+            .normalizeAttributeValue(attributeValue);
+      }
+      catch (final DecodeException de)
+      {
+        // Unable to normalize, so default to byte-wise comparison.
+        equalityNormalizedAttributeValue = attributeValue;
+      }
+    }
+    else
+    {
+      // No matching rule, so default to byte-wise comparison.
+      equalityNormalizedAttributeValue = attributeValue;
+    }
+
+    return equalityNormalizedAttributeValue;
+  }
+
+
+
+  private ByteString getOrderingNormalizedValue()
+  {
+    final ByteString normalizedValue = orderingNormalizedAttributeValue;
+
+    if (normalizedValue != null)
+    {
+      return normalizedValue;
+    }
+
+    final MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
+    if (matchingRule != null)
+    {
+      try
+      {
+        orderingNormalizedAttributeValue = matchingRule
+            .normalizeAttributeValue(attributeValue);
+      }
+      catch (final DecodeException de)
+      {
+        // Unable to normalize, so default to equality matching.
+        orderingNormalizedAttributeValue = getEqualityNormalizedValue();
+      }
+    }
+    else
+    {
+      // No matching rule, so default to equality matching.
+      orderingNormalizedAttributeValue = getEqualityNormalizedValue();
+    }
+
+    return orderingNormalizedAttributeValue;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAsynchronousConnection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAsynchronousConnection.java
new file mode 100644
index 0000000..685567d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAsynchronousConnection.java
@@ -0,0 +1,430 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_NO_SEARCH_RESULT_ENTRIES;
+import static com.sun.opends.sdk.messages.Messages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES;
+import static com.sun.opends.sdk.messages.Messages.ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * This class provides a skeletal implementation of the
+ * {@code AsynchronousConnection} interface, to minimize the effort required to
+ * implement this interface.
+ */
+public abstract class AbstractAsynchronousConnection implements
+    AsynchronousConnection
+{
+
+  private static final class SingleEntryFuture implements
+      FutureResult<SearchResultEntry>, SearchResultHandler
+  {
+    private final ResultHandler<? super SearchResultEntry> handler;
+
+    private volatile SearchResultEntry firstEntry = null;
+
+    private volatile SearchResultReference firstReference = null;
+
+    private volatile int entryCount = 0;
+
+    private volatile FutureResult<Result> future = null;
+
+
+
+    private SingleEntryFuture(
+        final ResultHandler<? super SearchResultEntry> handler)
+    {
+      this.handler = handler;
+    }
+
+
+
+    public boolean cancel(final boolean mayInterruptIfRunning)
+    {
+      return future.cancel(mayInterruptIfRunning);
+    }
+
+
+
+    public SearchResultEntry get() throws ErrorResultException,
+        InterruptedException
+    {
+      future.get();
+      return get0();
+    }
+
+
+
+    public SearchResultEntry get(final long timeout, final TimeUnit unit)
+        throws ErrorResultException, TimeoutException, InterruptedException
+    {
+      future.get(timeout, unit);
+      return get0();
+    }
+
+
+
+    public int getRequestID()
+    {
+      return future.getRequestID();
+    }
+
+
+
+    public boolean handleEntry(final SearchResultEntry entry)
+    {
+      if (firstEntry == null)
+      {
+        firstEntry = entry;
+      }
+      entryCount++;
+      return true;
+    }
+
+
+
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      if (handler != null)
+      {
+        handler.handleErrorResult(error);
+      }
+    }
+
+
+
+    public boolean handleReference(final SearchResultReference reference)
+    {
+      if (firstReference == null)
+      {
+        firstReference = reference;
+      }
+      return true;
+    }
+
+
+
+    public void handleResult(final Result result)
+    {
+      if (handler != null)
+      {
+        try
+        {
+          handler.handleResult(get0());
+        }
+        catch (final ErrorResultException e)
+        {
+          handler.handleErrorResult(e);
+        }
+      }
+    }
+
+
+
+    public boolean isCancelled()
+    {
+      return future.isCancelled();
+    }
+
+
+
+    public boolean isDone()
+    {
+      return future.isDone();
+    }
+
+
+
+    private SearchResultEntry get0() throws ErrorResultException
+    {
+      if (entryCount == 0)
+      {
+        // Did not find any entries.
+        final Result result = Responses.newResult(
+            ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage(
+            ERR_NO_SEARCH_RESULT_ENTRIES.get().toString());
+        throw ErrorResultException.wrap(result);
+      }
+      else if (entryCount > 1)
+      {
+        // Got more entries than expected.
+        final Result result = Responses
+            .newResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+            .setDiagnosticMessage(
+                ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(entryCount).toString());
+        throw ErrorResultException.wrap(result);
+      }
+      else if (firstReference != null)
+      {
+        // Got an unexpected search result reference.
+        final Result result = Responses.newResult(
+            ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+            .setDiagnosticMessage(
+                ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
+                    firstReference.getURIs().iterator().next()).toString());
+        throw ErrorResultException.wrap(result);
+      }
+      else
+      {
+        return firstEntry;
+      }
+    }
+
+
+
+    private void setResultFuture(final FutureResult<Result> future)
+    {
+      this.future = future;
+    }
+  }
+
+
+
+  /**
+   * Creates a new abstract connection.
+   */
+  protected AbstractAsynchronousConnection()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> add(final AddRequest request,
+      final ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return add(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<BindResult> bind(final BindRequest request,
+      final ResultHandler<? super BindResult> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return bind(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close()
+  {
+    close(Requests.newUnbindRequest(), null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<CompareResult> compare(final CompareRequest request,
+      final ResultHandler<? super CompareResult> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return compare(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> delete(final DeleteRequest request,
+      final ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return delete(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R extends ExtendedResult> FutureResult<R> extendedRequest(
+      final ExtendedRequest<R> request, final ResultHandler<? super R> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return extendedRequest(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Connection getSynchronousConnection()
+  {
+    return new SynchronousConnection(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> modify(final ModifyRequest request,
+      final ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return modify(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> modifyDN(final ModifyDNRequest request,
+      final ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return modifyDN(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<SearchResultEntry> readEntry(final DN name,
+      final Collection<String> attributeDescriptions,
+      final ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = Requests.newSearchRequest(name,
+        SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter());
+    request.getAttributes().addAll(attributeDescriptions);
+    return searchSingleEntry(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<RootDSE> readRootDSE(
+      final ResultHandler<? super RootDSE> handler)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return RootDSE.readRootDSE(this, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Schema> readSchema(final DN name,
+      final ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return Schema.readSchema(this, name, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Schema> readSchemaForEntry(final DN name,
+      final ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException
+  {
+    return Schema.readSchema(this, name, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<Result> search(final SearchRequest request,
+      final SearchResultHandler handler) throws UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return search(request, handler, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public FutureResult<SearchResultEntry> searchSingleEntry(
+      final SearchRequest request,
+      final ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SingleEntryFuture innerFuture = new SingleEntryFuture(handler);
+    final FutureResult<Result> future = search(request, innerFuture);
+    innerFuture.setResultFuture(future);
+    return innerFuture;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * Sub-classes should provide an implementation which returns an appropriate
+   * description of the connection which may be used for debugging purposes.
+   */
+  public abstract String toString();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAttribute.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAttribute.java
new file mode 100644
index 0000000..7d8ecfa
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractAttribute.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.*;
+
+import org.opends.sdk.schema.AttributeType;
+import org.opends.sdk.schema.MatchingRule;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class provides a skeletal implementation of the {@code Attribute}
+ * interface, to minimize the effort required to implement this interface.
+ */
+public abstract class AbstractAttribute extends AbstractSet<ByteString>
+    implements Attribute
+{
+
+  /**
+   * Returns {@code true} if {@code object} is an attribute which is equal to
+   * {@code attribute}. Two attributes are considered equal if their attribute
+   * descriptions are equal, they both have the same number of attribute values,
+   * and every attribute value contained in the first attribute is also
+   * contained in the second attribute.
+   *
+   * @param attribute
+   *          The attribute to be tested for equality.
+   * @param object
+   *          The object to be tested for equality with the attribute.
+   * @return {@code true} if {@code object} is an attribute which is equal to
+   *         {@code attribute}, or {@code false} if not.
+   */
+  static boolean equals(final Attribute attribute, final Object object)
+  {
+    if (attribute == object)
+    {
+      return true;
+    }
+
+    if (!(object instanceof Attribute))
+    {
+      return false;
+    }
+
+    final Attribute other = (Attribute) object;
+    if (!attribute.getAttributeDescription().equals(
+        other.getAttributeDescription()))
+    {
+      return false;
+    }
+
+    // Attribute description is the same, compare values.
+    if (attribute.size() != other.size())
+    {
+      return false;
+    }
+
+    return attribute.containsAll(other);
+  }
+
+
+
+  /**
+   * Returns the hash code for {@code attribute}. It will be calculated as the
+   * sum of the hash codes of the attribute description and all of the attribute
+   * values.
+   *
+   * @param attribute
+   *          The attribute whose hash code should be calculated.
+   * @return The hash code for {@code attribute}.
+   */
+  static int hashCode(final Attribute attribute)
+  {
+    int hashCode = attribute.getAttributeDescription().hashCode();
+    for (final ByteString value : attribute)
+    {
+      hashCode += normalizeValue(attribute, value).hashCode();
+    }
+    return hashCode;
+  }
+
+
+
+  /**
+   * Returns the normalized form of {@code value} normalized using {@code
+   * attribute}'s equality matching rule.
+   *
+   * @param attribute
+   *          The attribute whose equality matching rule should be used for
+   *          normalization.
+   * @param value
+   *          The attribute value to be normalized.
+   * @return The normalized form of {@code value} normalized using {@code
+   *         attribute}'s equality matching rule.
+   */
+  static ByteString normalizeValue(final Attribute attribute,
+      final ByteString value)
+  {
+    final AttributeDescription attributeDescription = attribute
+        .getAttributeDescription();
+    final AttributeType attributeType = attributeDescription.getAttributeType();
+    final MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
+
+    try
+    {
+      return matchingRule.normalizeAttributeValue(value);
+    }
+    catch (final Exception e)
+    {
+      // Fall back to provided value.
+      return value;
+    }
+  }
+
+
+
+  /**
+   * Returns a string representation of {@code attribute}.
+   *
+   * @param attribute
+   *          The attribute whose string representation should be returned.
+   * @return The string representation of {@code attribute}.
+   */
+  static String toString(final Attribute attribute)
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("Attribute(");
+    builder.append(attribute.getAttributeDescriptionAsString());
+    builder.append(", {");
+
+    boolean firstValue = true;
+    for (final ByteString value : attribute)
+    {
+      if (!firstValue)
+      {
+        builder.append(", ");
+      }
+
+      builder.append(value);
+      firstValue = false;
+    }
+
+    builder.append("})");
+    return builder.toString();
+  }
+
+
+
+  /**
+   * Sole constructor.
+   */
+  protected AbstractAttribute()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public abstract boolean add(ByteString value)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean add(final Object firstValue, final Object... remainingValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(firstValue);
+
+    boolean modified = add(ByteString.valueOf(firstValue));
+    if (remainingValues != null)
+    {
+      for (final Object value : remainingValues)
+      {
+        modified |= add(ByteString.valueOf(value));
+      }
+    }
+    return modified;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean addAll(final Collection<? extends ByteString> values)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return addAll(values, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean addAll(final Collection<? extends ByteString> values,
+      final Collection<? super ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    boolean modified = false;
+    for (final ByteString value : values)
+    {
+      if (add(value))
+      {
+        modified = true;
+      }
+      else if (duplicateValues != null)
+      {
+        duplicateValues.add(value);
+      }
+    }
+    return modified;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public abstract boolean contains(Object value) throws NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean containsAll(final Collection<?> values)
+      throws NullPointerException
+  {
+    for (final Object value : values)
+    {
+      if (!contains(value))
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object object)
+  {
+    return equals(this, object);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString firstValue() throws NoSuchElementException
+  {
+    return iterator().next();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String firstValueAsString() throws NoSuchElementException
+  {
+    return firstValue().toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract AttributeDescription getAttributeDescription();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getAttributeDescriptionAsString()
+  {
+    return getAttributeDescription().toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return hashCode(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public abstract Iterator<ByteString> iterator();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public abstract boolean remove(Object value)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean removeAll(final Collection<?> values)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return removeAll(values, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <T> boolean removeAll(final Collection<T> values,
+      final Collection<? super T> missingValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    boolean modified = false;
+    for (final T value : values)
+    {
+      if (remove(value))
+      {
+        modified = true;
+      }
+      else if (missingValues != null)
+      {
+        missingValues.add(value);
+      }
+    }
+    return modified;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean retainAll(final Collection<?> values)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return retainAll(values, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <T> boolean retainAll(final Collection<T> values,
+      final Collection<? super T> missingValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    if (values.isEmpty())
+    {
+      if (isEmpty())
+      {
+        return false;
+      }
+      else
+      {
+        clear();
+        return true;
+      }
+    }
+
+    if (isEmpty())
+    {
+      if (missingValues != null)
+      {
+        for (final T value : values)
+        {
+          missingValues.add(value);
+        }
+      }
+      return false;
+    }
+
+    final Map<ByteString, T> valuesToRetain = new HashMap<ByteString, T>(values
+        .size());
+    for (final T value : values)
+    {
+      valuesToRetain
+          .put(normalizeValue(this, ByteString.valueOf(value)), value);
+    }
+
+    boolean modified = false;
+    final Iterator<ByteString> iterator = iterator();
+    while (iterator.hasNext())
+    {
+      final ByteString value = iterator.next();
+      final ByteString normalizedValue = normalizeValue(this, value);
+      if (valuesToRetain.remove(normalizedValue) == null)
+      {
+        modified = true;
+        iterator.remove();
+      }
+    }
+
+    if (missingValues != null)
+    {
+      missingValues.addAll(valuesToRetain.values());
+    }
+
+    return modified;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public abstract int size();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString[] toArray()
+  {
+    return toArray(new ByteString[size()]);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return toString(this);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnection.java
new file mode 100644
index 0000000..9bd409e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnection.java
@@ -0,0 +1,494 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_NO_SEARCH_RESULT_ENTRIES;
+import static com.sun.opends.sdk.messages.Messages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES;
+import static com.sun.opends.sdk.messages.Messages.ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES;
+
+import java.util.Collection;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.opends.sdk.ldif.ConnectionEntryReader;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class provides a skeletal implementation of the {@code Connection}
+ * interface, to minimize the effort required to implement this interface.
+ */
+public abstract class AbstractConnection implements Connection
+{
+
+  private static final class SingleEntryHandler implements SearchResultHandler
+  {
+    private volatile SearchResultEntry firstEntry = null;
+
+    private volatile SearchResultReference firstReference = null;
+
+    private volatile int entryCount = 0;
+
+
+
+    public boolean handleEntry(final SearchResultEntry entry)
+    {
+      if (firstEntry == null)
+      {
+        firstEntry = entry;
+      }
+      entryCount++;
+      return true;
+    }
+
+
+
+    public boolean handleReference(final SearchResultReference reference)
+    {
+      if (firstReference == null)
+      {
+        firstReference = reference;
+      }
+      return true;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleErrorResult(ErrorResultException error)
+    {
+      // Ignore.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleResult(Result result)
+    {
+      // Ignore.
+    }
+
+  }
+
+
+
+  /**
+   * Creates a new abstract connection.
+   */
+  protected AbstractConnection()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result add(final Entry entry) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return add(Requests.newAddRequest(entry));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result add(final String... ldifLines) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      LocalizedIllegalArgumentException, IllegalStateException,
+      NullPointerException
+  {
+    return add(Requests.newAddRequest(ldifLines));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public BindResult bind(final String name, final char[] password)
+      throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return bind(Requests.newSimpleBindRequest(name, password));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareResult compare(final String name,
+      final String attributeDescription, final String assertionValue)
+      throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return compare(Requests.newCompareRequest(name, attributeDescription,
+        assertionValue));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result delete(final String name) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return delete(Requests.newDeleteRequest(name));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericExtendedResult extendedRequest(final String requestName,
+      final ByteString requestValue) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return extendedRequest(Requests.newGenericExtendedRequest(requestName,
+        requestValue));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result modify(final String... ldifLines) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      LocalizedIllegalArgumentException, IllegalStateException,
+      NullPointerException
+  {
+    return modify(Requests.newModifyRequest(ldifLines));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result modifyDN(final String name, final String newRDN)
+      throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return modifyDN(Requests.newModifyDNRequest(name, newRDN));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry readEntry(final DN baseObject,
+      final String... attributeDescriptions) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final SearchRequest request = Requests.newSearchRequest(baseObject,
+        SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter(),
+        attributeDescriptions);
+    return searchSingleEntry(request);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry readEntry(final String baseObject,
+      final String... attributeDescriptions) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return readEntry(DN.valueOf(baseObject));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public RootDSE readRootDSE() throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return RootDSE.readRootDSE(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchema(final DN name) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return Schema.readSchema(this, name);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchema(final String name) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException
+  {
+    return readSchema(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchemaForEntry(final DN name) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return Schema.readSchemaForEntry(this, name);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchemaForEntry(final String name)
+      throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return readSchemaForEntry(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Schema readSchemaForRootDSE() throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    return readSchemaForEntry(DN.rootDN());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result search(final SearchRequest request,
+      final Collection<? super SearchResultEntry> entries)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return search(request, entries, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result search(final SearchRequest request,
+      final Collection<? super SearchResultEntry> entries,
+      final Collection<? super SearchResultReference> references)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(request, entries);
+
+    // FIXME: does this need to be thread safe?
+    final SearchResultHandler handler = new SearchResultHandler()
+    {
+
+      public boolean handleEntry(final SearchResultEntry entry)
+      {
+        entries.add(entry);
+        return true;
+      }
+
+
+
+      public boolean handleReference(final SearchResultReference reference)
+      {
+        if (references != null)
+        {
+          references.add(reference);
+        }
+        return true;
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      public void handleErrorResult(ErrorResultException error)
+      {
+        // Ignore.
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      public void handleResult(Result result)
+      {
+        // Ignore.
+      }
+    };
+
+    return search(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ConnectionEntryReader search(final String baseObject,
+      final SearchScope scope, final String filter,
+      final String... attributeDescriptions)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final BlockingQueue<Response> entries = new LinkedBlockingQueue<Response>();
+    final SearchRequest request = Requests.newSearchRequest(baseObject, scope,
+        filter, attributeDescriptions);
+    return search(request, entries);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry searchSingleEntry(final SearchRequest request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SingleEntryHandler handler = new SingleEntryHandler();
+    search(request, handler);
+
+    if (handler.entryCount == 0)
+    {
+      // Did not find any entries.
+      final Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage(
+          ERR_NO_SEARCH_RESULT_ENTRIES.get().toString());
+      throw ErrorResultException.wrap(result);
+    }
+    else if (handler.entryCount > 1)
+    {
+      // Got more entries than expected.
+      final Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+          .setDiagnosticMessage(
+              ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(handler.entryCount)
+                  .toString());
+      throw ErrorResultException.wrap(result);
+    }
+    else if (handler.firstReference != null)
+    {
+      // Got an unexpected search result reference.
+      final Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+          .setDiagnosticMessage(
+              ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
+                  handler.firstReference.getURIs().iterator().next())
+                  .toString());
+      throw ErrorResultException.wrap(result);
+    }
+    else
+    {
+      return handler.firstEntry;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry searchSingleEntry(final String baseObject,
+      final SearchScope scope, final String filter,
+      final String... attributeDescriptions) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = Requests.newSearchRequest(baseObject, scope,
+        filter, attributeDescriptions);
+    return searchSingleEntry(request);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * Sub-classes should provide an implementation which returns an appropriate
+   * description of the connection which may be used for debugging purposes.
+   */
+  public abstract String toString();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnectionFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnectionFactory.java
new file mode 100644
index 0000000..a951488
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractConnectionFactory.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * This class provides a skeletal implementation of the {@code
+ * ConnectionFactory} interface, to minimize the effort required to implement
+ * this interface.
+ */
+public abstract class AbstractConnectionFactory implements ConnectionFactory
+{
+  /**
+   * Creates a new abstract connection factory.
+   */
+  protected AbstractConnectionFactory()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      ResultHandler<? super AsynchronousConnection> handler);
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to convert the asynchronous connection
+   * returned from {@code blockingGetAsynchronousConnection()} to a synchronous
+   * connection using a {@link SynchronousConnection} as per the following code:
+   *
+   * <pre>
+   * return new SynchronousConnection(blockingGetAsynchronousConnection());
+   * </pre>
+   *
+   * Implementations should override this method if they wish to return a
+   * different type of synchronous connection.
+   *
+   * @return A connection to the Directory Server associated with this
+   *         connection factory.
+   * @throws ErrorResultException
+   *           If the connection request failed for some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   */
+  public Connection getConnection() throws ErrorResultException,
+      InterruptedException
+  {
+    return getAsynchronousConnection(null).get().getSynchronousConnection();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract String toString();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractEntry.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractEntry.java
new file mode 100644
index 0000000..a266c2d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractEntry.java
@@ -0,0 +1,387 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+
+import com.sun.opends.sdk.util.Iterables;
+import com.sun.opends.sdk.util.Predicate;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class provides a skeletal implementation of the {@code Entry} interface,
+ * to minimize the effort required to implement this interface.
+ */
+public abstract class AbstractEntry implements Entry
+{
+
+  // Predicate used for findAttributes.
+  private static final Predicate<Attribute, AttributeDescription>
+    FIND_ATTRIBUTES_PREDICATE = new Predicate<Attribute, AttributeDescription>()
+  {
+
+    public boolean matches(final Attribute value, final AttributeDescription p)
+    {
+      return value.getAttributeDescription().isSubTypeOf(p);
+    }
+
+  };
+
+
+
+  /**
+   * Returns {@code true} if {@code object} is an entry which is equal to
+   * {@code entry}. Two entry are considered equal if their distinguished names
+   * are equal, they both have the same number of attributes, and every
+   * attribute contained in the first entry is also contained in the second
+   * entry.
+   *
+   * @param entry
+   *          The entry to be tested for equality.
+   * @param object
+   *          The object to be tested for equality with the entry.
+   * @return {@code true} if {@code object} is an entry which is equal to
+   *         {@code entry}, or {@code false} if not.
+   */
+  static boolean equals(final Entry entry, final Object object)
+  {
+    if (entry == object)
+    {
+      return true;
+    }
+
+    if (!(object instanceof Entry))
+    {
+      return false;
+    }
+
+    final Entry other = (Entry) object;
+    if (!entry.getName().equals(other.getName()))
+    {
+      return false;
+    }
+
+    // Distinguished name is the same, compare attributes.
+    if (entry.getAttributeCount() != other.getAttributeCount())
+    {
+      return false;
+    }
+
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      final Attribute otherAttribute = other.getAttribute(attribute
+          .getAttributeDescription());
+
+      if (!attribute.equals(otherAttribute))
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+
+
+  /**
+   * Returns the hash code for {@code entry}. It will be calculated as the sum
+   * of the hash codes of the distinguished name and all of the attributes.
+   *
+   * @param entry
+   *          The entry whose hash code should be calculated.
+   * @return The hash code for {@code entry}.
+   */
+  static int hashCode(final Entry entry)
+  {
+    int hashCode = entry.getName().hashCode();
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      hashCode += attribute.hashCode();
+    }
+    return hashCode;
+  }
+
+
+
+  /**
+   * Returns a string representation of {@code entry}.
+   *
+   * @param entry
+   *          The entry whose string representation should be returned.
+   * @return The string representation of {@code entry}.
+   */
+  static String toString(final Entry entry)
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("Entry(");
+    builder.append(entry.getName());
+    builder.append(", {");
+
+    boolean firstValue = true;
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      if (!firstValue)
+      {
+        builder.append(", ");
+      }
+
+      builder.append(attribute);
+      firstValue = false;
+    }
+
+    builder.append("})");
+    return builder.toString();
+  }
+
+
+
+  /**
+   * Sole constructor.
+   */
+  protected AbstractEntry()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean addAttribute(final Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return addAttribute(attribute, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Entry addAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    addAttribute(new LinkedAttribute(attributeDescription, values), null);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean containsAttribute(final Attribute attribute,
+      final Collection<ByteString> missingValues) throws NullPointerException
+  {
+    final Attribute a = getAttribute(attribute.getAttributeDescription());
+    if (a == null)
+    {
+      if (missingValues != null)
+      {
+        missingValues.addAll(attribute);
+      }
+      return false;
+    }
+    else
+    {
+      boolean result = true;
+      for (final ByteString value : attribute)
+      {
+        if (!a.contains(value))
+        {
+          if (missingValues != null)
+          {
+            missingValues.add(value);
+          }
+          result = false;
+        }
+      }
+      return result;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean containsAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    return containsAttribute(new LinkedAttribute(attributeDescription, values),
+        null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object object)
+  {
+    return equals(this, object);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes(
+      final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription);
+
+    return Iterables.filteredIterable(getAllAttributes(), FIND_ATTRIBUTES_PREDICATE,
+        attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return getAllAttributes(AttributeDescription.valueOf(attributeDescription));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Attribute getAttribute(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return getAttribute(AttributeDescription.valueOf(attributeDescription));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return hashCode(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean removeAttribute(final AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return removeAttribute(
+        Attributes.emptyAttribute(attributeDescription), null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Entry removeAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    removeAttribute(new LinkedAttribute(attributeDescription, values), null);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean replaceAttribute(final Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    if (attribute.isEmpty())
+    {
+      return removeAttribute(attribute.getAttributeDescription());
+    }
+    else
+    {
+      removeAttribute(attribute.getAttributeDescription());
+      addAttribute(attribute, null);
+      return true;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Entry replaceAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    replaceAttribute(new LinkedAttribute(attributeDescription, values));
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Entry setName(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    return setName(DN.valueOf(dn));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return toString(this);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractFilterVisitor.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractFilterVisitor.java
new file mode 100644
index 0000000..71aba58
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractFilterVisitor.java
@@ -0,0 +1,220 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.List;
+
+
+
+/**
+ * An abstract filter visitor whose default implementation for all {@code
+ * Visitor} methods is to invoke {@link #visitDefaultFilter(Object)}.
+ * <p>
+ * Implementations can override the methods on a case by case 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 AbstractFilterVisitor<R, P> implements
+    FilterVisitor<R, P>
+{
+
+  /**
+   * Default constructor.
+   */
+  protected AbstractFilterVisitor()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitAndFilter(final P p, final List<Filter> subFilters)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitApproxMatchFilter(final P p, final String attributeDescription,
+      final ByteString assertionValue)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * Visits any filters which are not explicitly handled by other visitor
+   * methods.
+   * <p>
+   * The default implementation of this method is to return {@code null}.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @return A visitor specified result.
+   */
+  public R visitDefaultFilter(final P p)
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitEqualityMatchFilter(final P p,
+      final String attributeDescription, final ByteString assertionValue)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitExtensibleMatchFilter(final P p, final String matchingRule,
+      final String attributeDescription, final ByteString assertionValue,
+      final boolean dnAttributes)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitGreaterOrEqualFilter(final P p,
+      final String attributeDescription, final ByteString assertionValue)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitLessOrEqualFilter(final P p, final String attributeDescription,
+      final ByteString assertionValue)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitNotFilter(final P p, final Filter subFilter)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitOrFilter(final P p, final List<Filter> subFilters)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitPresentFilter(final P p, final String attributeDescription)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitSubstringsFilter(final P p, final String attributeDescription,
+      final ByteString initialSubstring, final List<ByteString> anySubstrings,
+      final ByteString finalSubstring)
+  {
+    return visitDefaultFilter(p);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * The default implementation is to call {@link #visitDefaultFilter(Object)}.
+   */
+  public R visitUnrecognizedFilter(final P p, final byte filterTag,
+      final ByteString filterBytes)
+  {
+    return visitDefaultFilter(p);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractLoadBalancingAlgorithm.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractLoadBalancingAlgorithm.java
new file mode 100644
index 0000000..47f6d88
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractLoadBalancingAlgorithm.java
@@ -0,0 +1,446 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+
+import org.opends.sdk.responses.Responses;
+
+import com.sun.opends.sdk.util.AsynchronousFutureResult;
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An abstract load balancing algorithm providing monitoring and failover
+ * capabilities.
+ * <p>
+ * Implementations should override the method
+ * {@code getInitialConnectionFactoryIndex()} in order to provide the policy for
+ * selecting the first connection factory to use for each connection request.
+ */
+abstract class AbstractLoadBalancingAlgorithm implements LoadBalancingAlgorithm
+{
+  private final class MonitoredConnectionFactory extends
+      AbstractConnectionFactory implements
+      ResultHandler<AsynchronousConnection>
+  {
+
+    private final ConnectionFactory factory;
+
+    private final AtomicBoolean isOperational = new AtomicBoolean(true);
+
+    private volatile FutureResult<?> pendingConnectFuture = null;
+
+    private final int index;
+
+
+
+    private MonitoredConnectionFactory(final ConnectionFactory factory,
+        final int index)
+    {
+      this.factory = factory;
+      this.index = index;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+        final ResultHandler<? super AsynchronousConnection> resultHandler)
+    {
+      final AsynchronousFutureResult<AsynchronousConnection> future =
+        new AsynchronousFutureResult<AsynchronousConnection>(resultHandler);
+
+      final ResultHandler<AsynchronousConnection> failoverHandler =
+        new ResultHandler<AsynchronousConnection>()
+      {
+        @Override
+        public void handleErrorResult(final ErrorResultException error)
+        {
+          // Attempt failed - try next factory.
+          notifyOffline(error);
+
+          final int nextIndex = (index + 1) % monitoredFactories.size();
+          try
+          {
+            final MonitoredConnectionFactory nextFactory =
+              getMonitoredConnectionFactory(nextIndex);
+            nextFactory.getAsynchronousConnection(future);
+          }
+          catch (final ErrorResultException e)
+          {
+            future.handleErrorResult(e);
+          }
+        }
+
+
+
+        @Override
+        public void handleResult(final AsynchronousConnection result)
+        {
+          notifyOnline();
+          future.handleResult(result);
+        }
+      };
+
+      factory.getAsynchronousConnection(failoverHandler);
+      return future;
+    }
+
+
+
+    /**
+     * Handle monitoring connection request failure.
+     */
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      notifyOffline(error);
+    }
+
+
+
+    /**
+     * Handle monitoring connection request success.
+     */
+    @Override
+    public void handleResult(final AsynchronousConnection connection)
+    {
+      notifyOnline();
+
+      // The connection is not going to be used, so close it immediately.
+      connection.close();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+      return factory.toString();
+    }
+
+
+
+    /**
+     * Attempt to connect to the factory if it is offline and there is no
+     * pending monitoring request.
+     */
+    private synchronized void checkIfAvailable()
+    {
+      if (!isOperational.get()
+          && (pendingConnectFuture == null || pendingConnectFuture.isDone()))
+      {
+        if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+        {
+          StaticUtils.DEBUG_LOG.fine(String
+              .format("Attempting reconnect to offline factory " + this));
+        }
+        pendingConnectFuture = factory.getAsynchronousConnection(this);
+      }
+    }
+
+
+
+    private void notifyOffline(final ErrorResultException error)
+    {
+      if (isOperational.getAndSet(false))
+      {
+        // Transition from online to offline.
+        if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          StaticUtils.DEBUG_LOG.warning(String.format("Connection factory "
+              + factory + " is no longer operational: " + error.getMessage()));
+        }
+
+        synchronized (stateLock)
+        {
+          offlineFactoriesCount++;
+          if (offlineFactoriesCount == 1)
+          {
+            // Enable monitoring.
+            if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+            {
+              StaticUtils.DEBUG_LOG.fine(String
+                  .format("Starting monitoring thread"));
+            }
+
+            monitoringFuture = scheduler.scheduleWithFixedDelay(
+                new MonitorRunnable(), 0, monitoringInterval,
+                monitoringIntervalTimeUnit);
+          }
+        }
+      }
+    }
+
+
+
+    private void notifyOnline()
+    {
+      if (!isOperational.getAndSet(true))
+      {
+        // Transition from offline to online.
+        if (StaticUtils.DEBUG_LOG.isLoggable(Level.INFO))
+        {
+          StaticUtils.DEBUG_LOG.info(String.format("Connection factory "
+              + factory + " is now operational"));
+        }
+
+        synchronized (stateLock)
+        {
+          offlineFactoriesCount--;
+          if (offlineFactoriesCount == 0)
+          {
+            if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+            {
+              StaticUtils.DEBUG_LOG.fine(String
+                  .format("Stopping monitoring thread"));
+            }
+
+            monitoringFuture.cancel(false);
+            monitoringFuture = null;
+          }
+        }
+      }
+    }
+  }
+
+
+
+  private final class MonitorRunnable implements Runnable
+  {
+    private MonitorRunnable()
+    {
+      // Nothing to do.
+    }
+
+
+
+    @Override
+    public void run()
+    {
+      for (final MonitoredConnectionFactory factory : monitoredFactories)
+      {
+        factory.checkIfAvailable();
+      }
+    }
+  }
+
+
+
+  private final List<MonitoredConnectionFactory> monitoredFactories;
+
+  private final ScheduledExecutorService scheduler;
+
+  private final Object stateLock = new Object();
+
+  // Guarded by stateLock.
+  private int offlineFactoriesCount = 0;
+
+  private final long monitoringInterval;
+
+  private final TimeUnit monitoringIntervalTimeUnit;
+
+  // Guarded by stateLock.
+  private ScheduledFuture<?> monitoringFuture;
+
+
+
+  /**
+   * Creates a new abstract load balancing algorithm which will monitor offline
+   * connection factories every second using the default scheduler.
+   *
+   * @param factories
+   *          The connection factories.
+   */
+  AbstractLoadBalancingAlgorithm(final Collection<ConnectionFactory> factories)
+  {
+    this(factories, 1, TimeUnit.SECONDS, StaticUtils.getDefaultScheduler());
+  }
+
+
+
+  /**
+   * Creates a new abstract load balancing algorithm which will monitor offline
+   * connection factories using the specified frequency using the default
+   * scheduler.
+   *
+   * @param factories
+   *          The connection factories.
+   * @param interval
+   *          The interval between attempts to poll offline factories.
+   * @param unit
+   *          The time unit for the interval between attempts to poll offline
+   *          factories.
+   */
+  AbstractLoadBalancingAlgorithm(final Collection<ConnectionFactory> factories,
+      final long interval, final TimeUnit unit)
+  {
+    this(factories, interval, unit, StaticUtils.getDefaultScheduler());
+  }
+
+
+
+  /**
+   * Creates a new abstract load balancing algorithm which will monitor offline
+   * connection factories using the specified frequency and scheduler.
+   *
+   * @param factories
+   *          The connection factories.
+   * @param interval
+   *          The interval between attempts to poll offline factories.
+   * @param unit
+   *          The time unit for the interval between attempts to poll offline
+   *          factories.
+   * @param scheduler
+   *          The scheduler which should for periodically monitoring dead
+   *          connection factories to see if they are usable again.
+   */
+  AbstractLoadBalancingAlgorithm(final Collection<ConnectionFactory> factories,
+      final long interval, final TimeUnit unit,
+      final ScheduledExecutorService scheduler)
+  {
+    Validator.ensureNotNull(factories, scheduler, unit);
+
+    this.monitoredFactories = new ArrayList<MonitoredConnectionFactory>(
+        factories.size());
+    int i = 0;
+    for (final ConnectionFactory f : factories)
+    {
+      this.monitoredFactories.add(new MonitoredConnectionFactory(f, i++));
+    }
+    this.scheduler = scheduler;
+    this.monitoringInterval = interval;
+    this.monitoringIntervalTimeUnit = unit;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final ConnectionFactory getConnectionFactory()
+      throws ErrorResultException
+  {
+    final int index = getInitialConnectionFactoryIndex();
+    return getMonitoredConnectionFactory(index);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append(getAlgorithmName());
+    builder.append('(');
+    boolean isFirst = true;
+    for (final ConnectionFactory factory : monitoredFactories)
+    {
+      if (!isFirst)
+      {
+        builder.append(',');
+      }
+      else
+      {
+        isFirst = false;
+      }
+      builder.append(factory);
+    }
+    builder.append(')');
+    return builder.toString();
+  }
+
+
+
+  /**
+   * Returns the name of this load balancing algorithm.
+   *
+   * @return The name of this load balancing algorithm.
+   */
+  abstract String getAlgorithmName();
+
+
+
+  /**
+   * Returns the index of the first connection factory which should be used in
+   * order to satisfy the next connection request.
+   *
+   * @return The index of the first connection factory which should be used in
+   *         order to satisfy the next connection request.
+   */
+  abstract int getInitialConnectionFactoryIndex();
+
+
+
+  // Return the first factory after index which is operational.
+  private MonitoredConnectionFactory getMonitoredConnectionFactory(
+      final int initialIndex) throws ErrorResultException
+  {
+    int index = initialIndex;
+    final int maxIndex = monitoredFactories.size();
+    do
+    {
+      final MonitoredConnectionFactory factory = monitoredFactories.get(index);
+      if (factory.isOperational.get())
+      {
+        return factory;
+      }
+      index = (index + 1) % maxIndex;
+    }
+    while (index != initialIndex);
+
+    // All factories are offline so give up. We could have a
+    // configurable policy here such as waiting indefinitely, or for a
+    // configurable timeout period.
+    throw ErrorResultException.wrap(Responses.newResult(
+        ResultCode.CLIENT_SIDE_CONNECT_ERROR).setDiagnosticMessage(
+        "No operational connection factories available"));
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractMapEntry.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractMapEntry.java
new file mode 100644
index 0000000..6dcfc77
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AbstractMapEntry.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Abstract implementation for {@code Map} based entries.
+ */
+abstract class AbstractMapEntry extends AbstractEntry
+{
+  private final Map<AttributeDescription, Attribute> attributes;
+
+  private DN name;
+
+
+
+  /**
+   * Creates an empty entry using the provided distinguished name and {@code
+   * Map}.
+   *
+   * @param name
+   *          The distinguished name of this entry.
+   * @param attributes
+   *          The attribute map.
+   */
+  AbstractMapEntry(final DN name,
+      final Map<AttributeDescription, Attribute> attributes)
+      throws NullPointerException
+  {
+    this.name = name;
+    this.attributes = attributes;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean addAttribute(final Attribute attribute,
+      final Collection<ByteString> duplicateValues) throws NullPointerException
+  {
+    Validator.ensureNotNull(attribute);
+
+    final AttributeDescription attributeDescription = attribute
+        .getAttributeDescription();
+    final Attribute oldAttribute = attributes.get(attributeDescription);
+    if (oldAttribute != null)
+    {
+      return oldAttribute.addAll(attribute, duplicateValues);
+    }
+    else
+    {
+      attributes.put(attributeDescription, attribute);
+      return true;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final Entry clearAttributes()
+  {
+    attributes.clear();
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final Iterable<Attribute> getAllAttributes()
+  {
+    return attributes.values();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final Attribute getAttribute(
+      final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription);
+
+    return attributes.get(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final int getAttributeCount()
+  {
+    return attributes.size();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final DN getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean removeAttribute(final Attribute attribute,
+      final Collection<ByteString> missingValues) throws NullPointerException
+  {
+    Validator.ensureNotNull(attribute);
+
+    final AttributeDescription attributeDescription = attribute
+        .getAttributeDescription();
+
+    if (attribute.isEmpty())
+    {
+      return attributes.remove(attributeDescription) != null;
+    }
+    else
+    {
+      final Attribute oldAttribute = attributes.get(attributeDescription);
+      if (oldAttribute != null)
+      {
+        final boolean modified = oldAttribute.removeAll(attribute,
+            missingValues);
+        if (oldAttribute.isEmpty())
+        {
+          attributes.remove(attributeDescription);
+          return true;
+        }
+        return modified;
+      }
+      else
+      {
+        if (missingValues != null)
+        {
+          missingValues.addAll(attribute);
+        }
+        return false;
+      }
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final Entry setName(final DN dn) throws NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = dn;
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Assertion.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Assertion.java
new file mode 100644
index 0000000..2037281
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Assertion.java
@@ -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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * A compiled attribute value assertion.
+ */
+public interface Assertion
+{
+  /**
+   * Indicates whether the provided attribute value should be considered a match
+   * for this assertion value according to the matching rule.
+   *
+   * @param attributeValue
+   *          The attribute value.
+   * @return {@code TRUE} if the attribute value should be considered a match
+   *         for the provided assertion value, {@code FALSE} if it does not
+   *         match, or {@code UNDEFINED} if the result is undefined.
+   */
+  public abstract ConditionResult matches(ByteSequence attributeValue);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AssertionFailureException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AssertionFailureException.java
new file mode 100644
index 0000000..32c5432
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AssertionFailureException.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * failed because the filter contained in an assertion control failed to match
+ * the target entry. More specifically, this exception is used for the
+ * {@link ResultCode#ASSERTION_FAILED ASSERTION_FAILED} result code.
+ */
+@SuppressWarnings("serial")
+public class AssertionFailureException extends ErrorResultException
+{
+  AssertionFailureException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AsynchronousConnection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AsynchronousConnection.java
new file mode 100644
index 0000000..4c0f60f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AsynchronousConnection.java
@@ -0,0 +1,850 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.Closeable;
+import java.util.Collection;
+
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * An asynchronous connection with a Directory Server over which read and update
+ * operations may be performed. See RFC 4511 for the LDAPv3 protocol
+ * specification and more information about the types of operations defined in
+ * LDAP.
+ * <p>
+ * <h3>Operation processing</h3>
+ * <p>
+ * All operations are performed asynchronously and return a {@link FutureResult}
+ * or sub-type thereof which can be used for retrieving the result using the
+ * {@link FutureResult#get} method. Operation failures, for whatever reason, are
+ * signalled by the {@link FutureResult#get()} method throwing an
+ * {@link ErrorResultException}.
+ * <p>
+ * Synchronous operations are easily simulated by immediately getting the
+ * result:
+ *
+ * <pre>
+ * Connection connection = ...;
+ * AddRequest request = ...;
+ * // Will block until operation completes, and
+ * // throws exception on failure.
+ * connection.add(request).get();
+ * </pre>
+ *
+ * Operations can be performed in parallel while taking advantage of the
+ * simplicity of a synchronous application design:
+ *
+ * <pre>
+ * Connection connection1 = ...;
+ * Connection connection2 = ...;
+ * AddRequest request = ...;
+ * // Add the entry to the first server (don't block).
+ * FutureResult future1 = connection1.add(request);
+ * // Add the entry to the second server (in parallel).
+ * FutureResult future2 = connection2.add(request);
+ * // Total time = is O(1) instead of O(n).
+ * future1.get();
+ * future2.get();
+ * </pre>
+ *
+ * More complex client applications can take advantage of a fully asynchronous
+ * event driven design using {@link ResultHandler}s:
+ *
+ * <pre>
+ * Connection connection = ...;
+ * SearchRequest request = ...;
+ * // Process results in the search result handler
+ * // in a separate thread.
+ * SearchResponseHandler handle = ...;
+ * connection.search(request, handler);
+ * </pre>
+ * <p>
+ * <h3>Closing connections</h3>
+ * <p>
+ * Applications must ensure that a connection is closed by calling
+ * {@link #close()} even if a fatal error occurs on the connection. Once a
+ * connection has been closed by the client application, any attempts to
+ * continue to use the connection will result in an
+ * {@link IllegalStateException} being thrown. Note that, if a fatal error is
+ * encountered on the connection, then the application can continue to use the
+ * connection. In this case all requests subsequent to the failure will fail
+ * with an appropriate {@link ErrorResultException} when their result is
+ * retrieved.
+ * <p>
+ * <h3>Event notification</h3>
+ * <p>
+ * Applications can choose to be notified when a connection is closed by the
+ * application, receives an unsolicited notification, or experiences a fatal
+ * error by registering a {@link ConnectionEventListener} with the connection
+ * using the {@link #addConnectionEventListener} method.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight
+ *      Directory Access Protocol (LDAP): The Protocol </a>
+ */
+public interface AsynchronousConnection extends Closeable
+{
+
+  /**
+   * Abandons the unfinished operation identified in the provided abandon
+   * request.
+   * <p>
+   * Since abandon requests do not have a response, invoking the method
+   * {@code get()} on the returned future will not block, nor return anything
+   * (it is {@code Void}), but may throw an exception if a problem occurred
+   * while sending the abandon request.
+   * <p>
+   * <b>Note:</b> a more convenient approach to abandoning unfinished operations
+   * is provided via the {@link FutureResult#cancel(boolean)} method.
+   *
+   * @param request
+   *          The request identifying the operation to be abandoned.
+   * @return An future whose result is {@code Void}.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support abandon operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Void> abandon(AbandonRequest request)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Adds an entry to the Directory Server using the provided add request. Any
+   * intermediate responses will be ignored.
+   *
+   * @param request
+   *          The add request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support add operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> add(AddRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Adds an entry to the Directory Server using the provided add request.
+   *
+   * @param request
+   *          The add request.
+   * @param resultHandler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support add operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> add(AddRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Registers the provided connection event listener so that it will be
+   * notified when this connection is closed by the application, receives an
+   * unsolicited notification, or experiences a fatal error.
+   *
+   * @param listener
+   *          The listener which wants to be notified when events occur on this
+   *          connection.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code listener} was {@code null}.
+   */
+  void addConnectionEventListener(ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Authenticates to the Directory Server using the provided bind request. Any
+   * intermediate responses will be ignored.
+   *
+   * @param request
+   *          The bind request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support bind operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<BindResult> bind(BindRequest request,
+      ResultHandler<? super BindResult> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Authenticates to the Directory Server using the provided bind request.
+   *
+   * @param request
+   *          The bind request.
+   * @param resultHandler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support bind operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<BindResult> bind(BindRequest request,
+      ResultHandler<? super BindResult> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Releases any resources associated with this connection. For physical
+   * connections to a Directory Server this will mean that an unbind request is
+   * sent and the underlying socket is closed.
+   * <p>
+   * Other connection implementations may behave differently, and may choose not
+   * to send an unbind request if its use is inappropriate (for example a pooled
+   * connection will be released and returned to its connection pool without
+   * ever issuing an unbind request).
+   * <p>
+   * This method is semantically equivalent to the following code:
+   *
+   * <pre>
+   * UnbindRequest request = Requests.newUnbindRequest();
+   * connection.close(request);
+   * </pre>
+   *
+   * Calling {@code close} on a connection that is already closed has no effect.
+   */
+  void close();
+
+
+
+  /**
+   * Releases any resources associated with this connection. For physical
+   * connections to a Directory Server this will mean that the provided unbind
+   * request is sent and the underlying socket is closed.
+   * <p>
+   * Other connection implementations may behave differently, and may choose to
+   * ignore the provided unbind request if its use is inappropriate (for example
+   * a pooled connection will be released and returned to its connection pool
+   * without ever issuing an unbind request).
+   * <p>
+   * Calling {@code close} on a connection that is already closed has no effect.
+   *
+   * @param request
+   *          The unbind request to use in the case where a physical connection
+   *          is closed.
+   * @param reason
+   *          A reason describing why the connection was closed.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  void close(UnbindRequest request, String reason) throws NullPointerException;
+
+
+
+  /**
+   * Compares an entry in the Directory Server using the provided compare
+   * request. Any intermediate responses will be ignored.
+   *
+   * @param request
+   *          The compare request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support compare operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<CompareResult> compare(CompareRequest request,
+      ResultHandler<? super CompareResult> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Compares an entry in the Directory Server using the provided compare
+   * request.
+   *
+   * @param request
+   *          The compare request.
+   * @param resultHandler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support compare operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<CompareResult> compare(CompareRequest request,
+      ResultHandler<? super CompareResult> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Deletes an entry from the Directory Server using the provided delete
+   * request. Any intermediate responses will be ignored.
+   *
+   * @param request
+   *          The delete request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support delete operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> delete(DeleteRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Deletes an entry from the Directory Server using the provided delete
+   * request.
+   *
+   * @param request
+   *          The delete request.
+   * @param resultHandler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support delete operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> delete(DeleteRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Requests that the Directory Server performs the provided extended request.
+   * Any intermediate responses will be ignored.
+   *
+   * @param <R>
+   *          The type of result returned by the extended request.
+   * @param request
+   *          The extended request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support extended operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  <R extends ExtendedResult> FutureResult<R> extendedRequest(
+      ExtendedRequest<R> request, ResultHandler<? super R> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Requests that the Directory Server performs the provided extended request.
+   *
+   * @param <R>
+   *          The type of result returned by the extended request.
+   * @param request
+   *          The extended request.
+   * @param resultHandler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support extended operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  <R extends ExtendedResult> FutureResult<R> extendedRequest(
+      ExtendedRequest<R> request, ResultHandler<? super R> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Returns a synchronous connection sharing the same underlying network
+   * connection as this asynchronous connection.
+   *
+   * @return A synchronous connection sharing the same underlying network
+   *         connection as this asynchronous connection.
+   */
+  Connection getSynchronousConnection();
+
+
+
+  /**
+   * Indicates whether or not this connection has been explicitly closed by
+   * calling {@code close}. This method will not return {@code true} if a fatal
+   * error has occurred on the connection unless {@code close} has been called.
+   *
+   * @return {@code true} if this connection has been explicitly closed by
+   *         calling {@code close}, or {@code false} otherwise.
+   */
+  boolean isClosed();
+
+
+
+  /**
+   * Returns {@code true} if this connection has not been closed and no fatal
+   * errors have been detected. This method is guaranteed to return
+   * {@code false} only when it is called after the method {@code close} has
+   * been called.
+   *
+   * @return {@code true} if the connection is valid, {@code false} otherwise.
+   */
+  boolean isValid();
+
+
+
+  /**
+   * Modifies an entry in the Directory Server using the provided modify
+   * request. Any intermediate responses will be ignored.
+   *
+   * @param request
+   *          The modify request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> modify(ModifyRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Modifies an entry in the Directory Server using the provided modify
+   * request.
+   *
+   * @param request
+   *          The modify request.
+   * @param resultHandler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> modify(ModifyRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Renames an entry in the Directory Server using the provided modify DN
+   * request. Any intermediate responses will be ignored.
+   *
+   * @param request
+   *          The modify DN request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify DN operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> modifyDN(ModifyDNRequest request,
+      ResultHandler<? super Result> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Renames an entry in the Directory Server using the provided modify DN
+   * request.
+   *
+   * @param request
+   *          The modify DN request.
+   * @param resultHandler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify DN operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> modifyDN(ModifyDNRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Reads the named entry from the Directory Server.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * SearchRequest request = new SearchRequest(name, SearchScope.BASE_OBJECT,
+   *     &quot;(objectClass=*)&quot;, attributeDescriptions);
+   * connection.searchSingleEntry(request, resultHandler, p);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be read.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with the entry, which
+   *          may be {@code null} or empty indicating that all user attributes
+   *          should be returned.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code name} was {@code null}.
+   */
+  FutureResult<SearchResultEntry> readEntry(DN name,
+      Collection<String> attributeDescriptions,
+      ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the request
+   * will fail with an {@link EntryNotFoundException}. More specifically, the
+   * returned future will never return {@code null}.
+   *
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  FutureResult<RootDSE> readRootDSE(ResultHandler<? super RootDSE> handler)
+      throws UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named subschema
+   * sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}.
+   * <p>
+   * Implementations may choose to perform optimizations such as caching.
+   *
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  FutureResult<Schema> readSchema(DN name, ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the named
+   * entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by the
+   * Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, the returned future will
+   * never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code subschemaSubentry}
+   * attribute of the entry in order to locate the schema. However,
+   * implementations may choose to perform other optimizations, such as caching.
+   *
+   * @param name
+   *          The distinguished name of the entry whose schema is to be located.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   *          Optional additional handler parameter.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   */
+  FutureResult<Schema> readSchemaForEntry(DN name,
+      ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Removes the provided connection event listener from this connection so that
+   * it will no longer be notified when this connection is closed by the
+   * application, receives an unsolicited notification, or experiences a fatal
+   * error.
+   *
+   * @param listener
+   *          The listener which no longer wants to be notified when events
+   *          occur on this connection.
+   * @throws NullPointerException
+   *           If the {@code listener} was {@code null}.
+   */
+  void removeConnectionEventListener(ConnectionEventListener listener)
+      throws NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server using the provided search request. Any
+   * intermediate responses will be ignored.
+   *
+   * @param request
+   *          The search request.
+   * @param handler
+   *          A search result handler which can be used to asynchronously
+   *          process the search result entries and references as they are
+   *          received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> search(SearchRequest request,
+      SearchResultHandler handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server using the provided search request.
+   *
+   * @param request
+   *          The search request.
+   * @param resultHandler
+   *          A search result handler which can be used to asynchronously
+   *          process the search result entries and references as they are
+   *          received, may be {@code null}.
+   * @param intermediateResponseHandler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  FutureResult<Result> search(SearchRequest request,
+      SearchResultHandler resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server for a single entry using the provided search
+   * request.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}. If
+   * multiple matching entries are returned by the Directory Server then the
+   * request will fail with an {@link MultipleEntriesFoundException}.
+   *
+   * @param request
+   *          The search request.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if
+   *           {@code isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code request} was {@code null}.
+   */
+  FutureResult<SearchResultEntry> searchSingleEntry(SearchRequest request,
+      ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attribute.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attribute.java
new file mode 100644
index 0000000..42d2439
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attribute.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+
+
+/**
+ * An attribute, comprising of an attribute description and zero or more
+ * attribute values.
+ * <p>
+ * Any methods which perform comparisons between attribute values use the
+ * equality matching rule associated with the attribute description.
+ * <p>
+ * Any methods which accept {@code Object} based attribute values convert the
+ * attribute values to instances of {@code ByteString} as follows:
+ *
+ * <pre>
+ * Object object = ...;
+ * ByteString value = null;
+ * if (object instanceof ByteSequence)
+ * {
+ *   value = ((ByteSequence)object).toByteString();
+ * }
+ * else
+ * {
+ *   value = ByteString.valueOf(object.toString());
+ * }
+ * </pre>
+ * <p>
+ * TODO: matching against attribute value assertions.
+ */
+public interface Attribute extends Set<ByteString>
+{
+  /**
+   * Adds {@code value} to this attribute if it is not already present (optional
+   * operation). If this attribute already contains {@code value}, the call
+   * leaves the attribute unchanged and returns {@code false}.
+   *
+   * @param value
+   *          The attribute value to be added to this attribute.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support addition of attribute values.
+   * @throws NullPointerException
+   *           If {@code value} was {@code null}.
+   */
+  boolean add(ByteString value) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Adds all of the provided attribute values to this attribute if they are not
+   * already present (optional operation).
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param firstValue
+   *          The first attribute value to be added to this attribute.
+   * @param remainingValues
+   *          The remaining attribute values to be added to this attribute.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support addition of attribute values.
+   * @throws NullPointerException
+   *           If {@code firstValue} was {@code null}.
+   */
+  boolean add(Object firstValue, Object... remainingValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Adds all of the attribute values contained in {@code values} to this
+   * attribute if they are not already present (optional operation).
+   * <p>
+   * An invocation of this method is equivalent to:
+   *
+   * <pre>
+   * attribute.addAll(values, null);
+   * </pre>
+   *
+   * @param values
+   *          The attribute values to be added to this attribute.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support addition of attribute values.
+   * @throws NullPointerException
+   *           If {@code values} was {@code null}.
+   */
+  boolean addAll(Collection<? extends ByteString> values)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Adds all of the attribute values contained in {@code values} to this
+   * attribute if they are not already present (optional operation). Any
+   * attribute values which are already present will be added to {@code
+   * duplicateValues} if specified.
+   *
+   * @param values
+   *          The attribute values to be added to this attribute.
+   * @param duplicateValues
+   *          A collection into which duplicate values will be added, or {@code
+   *          null} if duplicate values should not be saved.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support addition of attribute values.
+   * @throws NullPointerException
+   *           If {@code values} was {@code null}.
+   */
+  boolean addAll(Collection<? extends ByteString> values,
+      Collection<? super ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Removes all of the attribute values from this attribute (optional
+   * operation). This attribute will be empty after this call returns.
+   *
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support removal of attribute values.
+   */
+  void clear() throws UnsupportedOperationException;
+
+
+
+  /**
+   * Returns {@code true} if this attribute contains {@code value}.
+   * <p>
+   * If {@code value} is not an instance of {@code ByteString} then it will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param value
+   *          The attribute value whose presence in this attribute is to be
+   *          tested.
+   * @return {@code true} if this attribute contains {@code value}, or {@code
+   *         false} if not.
+   * @throws NullPointerException
+   *           If {@code value} was {@code null}.
+   */
+  boolean contains(Object value) throws NullPointerException;
+
+
+
+  /**
+   * Returns {@code true} if this attribute contains all of the attribute values
+   * contained in {@code values}.
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param values
+   *          The attribute values whose presence in this attribute is to be
+   *          tested.
+   * @return {@code true} if this attribute contains all of the attribute values
+   *         contained in {@code values}, or {@code false} if not.
+   * @throws NullPointerException
+   *           If {@code values} was {@code null}.
+   */
+  boolean containsAll(Collection<?> values) throws NullPointerException;
+
+
+
+  /**
+   * Returns {@code true} if {@code object} is an attribute which is equal to
+   * this attribute. Two attributes are considered equal if their attribute
+   * descriptions are equal, they both have the same number of attribute values,
+   * and every attribute value contained in the first attribute is also
+   * contained in the second attribute.
+   *
+   * @param object
+   *          The object to be tested for equality with this attribute.
+   * @return {@code true} if {@code object} is an attribute which is equal to
+   *         this attribute, or {@code false} if not.
+   */
+  boolean equals(Object object);
+
+
+
+  /**
+   * Returns the first attribute value in this attribute.
+   *
+   * @return The first attribute value in this attribute.
+   * @throws NoSuchElementException
+   *           If this attribute is empty.
+   */
+  ByteString firstValue() throws NoSuchElementException;
+
+
+
+  /**
+   * Returns the first attribute value in this attribute decoded as a UTF-8
+   * string.
+   *
+   * @return The first attribute value in this attribute decoded as a UTF-8
+   *         string.
+   * @throws NoSuchElementException
+   *           If this attribute is empty.
+   */
+  String firstValueAsString() throws NoSuchElementException;
+
+
+
+  /**
+   * Returns the attribute description of this attribute, which includes its
+   * attribute type and any options.
+   *
+   * @return The attribute description.
+   */
+  AttributeDescription getAttributeDescription();
+
+
+
+  /**
+   * Returns the string representation of the attribute description of this
+   * attribute, which includes its attribute type and any options.
+   *
+   * @return The string representation of the attribute description.
+   */
+  String getAttributeDescriptionAsString();
+
+
+
+  /**
+   * Returns the hash code for this attribute. It will be calculated as the sum
+   * of the hash codes of the attribute description and all of the attribute
+   * values.
+   *
+   * @return The hash code for this attribute.
+   */
+  int hashCode();
+
+
+
+  /**
+   * Returns {@code true} if this attribute contains no attribute values.
+   *
+   * @return {@code true} if this attribute contains no attribute values.
+   */
+  boolean isEmpty();
+
+
+
+  /**
+   * Returns an iterator over the attribute values in this attribute. The
+   * attribute values are returned in no particular order, unless the
+   * implementation of this attribute provides such a guarantee.
+   *
+   * @return An iterator over the attribute values in this attribute.
+   */
+  Iterator<ByteString> iterator();
+
+
+
+  /**
+   * Removes {@code value} from this attribute if it is present (optional
+   * operation). If this attribute does not contain {@code value}, the call
+   * leaves the attribute unchanged and returns {@code false}.
+   * <p>
+   * If {@code value} is not an instance of {@code ByteString} then it will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param value
+   *          The attribute value to be removed from this attribute.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support removal of attribute values.
+   * @throws NullPointerException
+   *           If {@code value} was {@code null}.
+   */
+  boolean remove(Object value) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Removes all of the attribute values contained in {@code values} from this
+   * attribute if they are present (optional operation).
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   * <p>
+   * An invocation of this method is equivalent to:
+   *
+   * <pre>
+   * attribute.removeAll(values, null);
+   * </pre>
+   *
+   * @param values
+   *          The attribute values to be removed from this attribute.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support removal of attribute values.
+   * @throws NullPointerException
+   *           If {@code values} was {@code null}.
+   */
+  boolean removeAll(Collection<?> values) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Removes all of the attribute values contained in {@code values} from this
+   * attribute if they are present (optional operation). Any attribute values
+   * which are not already present will be added to {@code missingValues} if
+   * specified.
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param <T>
+   *          The type of the attribute value objects being removed.
+   * @param values
+   *          The attribute values to be removed from this attribute.
+   * @param missingValues
+   *          A collection into which missing values will be added, or {@code
+   *          null} if missing values should not be saved.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support removal of attribute values.
+   * @throws NullPointerException
+   *           If {@code values} was {@code null}.
+   */
+  <T> boolean removeAll(Collection<T> values,
+      Collection<? super T> missingValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Retains only the attribute values in this attribute which are contained in
+   * {@code values} (optional operation).
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   * <p>
+   * An invocation of this method is equivalent to:
+   *
+   * <pre>
+   * attribute.retainAll(values, null);
+   * </pre>
+   *
+   * @param values
+   *          The attribute values to be retained in this attribute.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support removal of attribute values.
+   * @throws NullPointerException
+   *           If {@code values} was {@code null}.
+   */
+  boolean retainAll(Collection<?> values) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Retains only the attribute values in this attribute which are contained in
+   * {@code values} (optional operation). Any attribute values which are not
+   * already present will be added to {@code missingValues} if specified.
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param <T>
+   *          The type of the attribute value objects being retained.
+   * @param values
+   *          The attribute values to be retained in this attribute.
+   * @param missingValues
+   *          A collection into which missing values will be added, or {@code
+   *          null} if missing values should not be saved.
+   * @return {@code true} if this attribute changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this attribute does not support removal of attribute values.
+   * @throws NullPointerException
+   *           If {@code values} was {@code null}.
+   */
+  <T> boolean retainAll(Collection<T> values,
+      Collection<? super T> missingValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Returns the number of attribute values in this attribute.
+   *
+   * @return The number of attribute values in this attribute.
+   */
+  int size();
+
+
+
+  /**
+   * Returns an array containing all of the attribute values contained in this
+   * attribute.
+   * <p>
+   * If this attribute makes any guarantees as to what order its attribute
+   * values are returned by its iterator, this method must return the attribute
+   * values in the same order.
+   * <p>
+   * The returned array will be "safe" in that no references to it are
+   * maintained by this attribute. The caller is thus free to modify the
+   * returned array.
+   *
+   * @return An array containing all of the attribute values contained in this
+   *         attribute.
+   */
+  ByteString[] toArray();
+
+
+
+  /**
+   * Returns an array containing all of the attribute values in this attribute;
+   * the runtime type of the returned array is that of the specified array.
+   * <p>
+   * If the set fits in the specified array, it is returned therein. Otherwise,
+   * a new array is allocated with the runtime type of the specified array and
+   * the size of this attribute. If this attribute fits in the specified array
+   * with room to spare (i.e., the array has more elements than this attribute),
+   * the elements in the array immediately following the end of the set is set
+   * to {@code null}.
+   * <p>
+   * If this attribute makes any guarantees as to what order its attribute
+   * values are returned by its iterator, this method must return the attribute
+   * values in the same order.
+   *
+   * @param <T>
+   *          The type of elements contained in {@code array}.
+   * @param array
+   *          An array into which the elements of this attribute should be put.
+   * @return An array containing all of the attribute values contained in this
+   *         attribute.
+   * @throws ArrayStoreException
+   *           If the runtime type of {@code array} is not a supertype of
+   *           {@code ByteString}.
+   * @throws NullPointerException
+   *           If {@code array} was {@code null}.
+   */
+  <T> T[] toArray(T[] array) throws ArrayStoreException, NullPointerException;
+
+
+
+  /**
+   * Returns a string representation of this attribute.
+   *
+   * @return The string representation of this attribute.
+   */
+  String toString();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeDescription.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeDescription.java
new file mode 100644
index 0000000..6367cdb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeDescription.java
@@ -0,0 +1,1478 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+
+import java.util.*;
+
+import org.opends.sdk.schema.AttributeType;
+import org.opends.sdk.schema.Schema;
+import org.opends.sdk.schema.UnknownSchemaElementException;
+
+import com.sun.opends.sdk.util.ASCIICharProp;
+import com.sun.opends.sdk.util.Iterators;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An attribute description as defined in RFC 4512 section 2.5. Attribute
+ * descriptions are used to identify an attribute in an entry and are composed
+ * of an attribute type and a set of zero or more attribute options.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4512#section-2.5">RFC 4512 -
+ *      Lightweight Directory Access Protocol (LDAP): Directory Information
+ *      Models </a>
+ */
+public final class AttributeDescription implements
+    Comparable<AttributeDescription>
+{
+  private static abstract class Impl implements Iterable<String>
+  {
+    protected Impl()
+    {
+      // Nothing to do.
+    }
+
+
+
+    public abstract int compareTo(Impl other);
+
+
+
+    public abstract boolean containsOption(String normalizedOption);
+
+
+
+    public abstract boolean equals(Impl other);
+
+
+
+    public abstract String firstNormalizedOption();
+
+
+
+    @Override
+    public abstract int hashCode();
+
+
+
+    public abstract boolean hasOptions();
+
+
+
+    public abstract boolean isSubTypeOf(Impl other);
+
+
+
+    public abstract boolean isSuperTypeOf(Impl other);
+
+
+
+    public abstract int size();
+
+  }
+
+
+
+  private static final class MultiOptionImpl extends Impl
+  {
+
+    private final String[] normalizedOptions;
+
+    private final String[] options;
+
+
+
+    private MultiOptionImpl(final String[] options,
+        final String[] normalizedOptions)
+    {
+      if (normalizedOptions.length < 2)
+      {
+        throw new AssertionError();
+      }
+
+      this.options = options;
+      this.normalizedOptions = normalizedOptions;
+    }
+
+
+
+    @Override
+    public int compareTo(final Impl other)
+    {
+      final int thisSize = normalizedOptions.length;
+      final int otherSize = other.size();
+
+      if (thisSize < otherSize)
+      {
+        return -1;
+      }
+      else if (thisSize > otherSize)
+      {
+        return 1;
+      }
+      else
+      {
+        // Same number of options.
+        final MultiOptionImpl otherImpl = (MultiOptionImpl) other;
+        for (int i = 0; i < thisSize; i++)
+        {
+          final String o1 = normalizedOptions[i];
+          final String o2 = otherImpl.normalizedOptions[i];
+          final int result = o1.compareTo(o2);
+          if (result != 0)
+          {
+            return result;
+          }
+        }
+
+        // All options the same.
+        return 0;
+      }
+    }
+
+
+
+    @Override
+    public boolean containsOption(final String normalizedOption)
+    {
+      final int sz = normalizedOptions.length;
+      for (int i = 0; i < sz; i++)
+      {
+        if (normalizedOptions[i].equals(normalizedOption))
+        {
+          return true;
+        }
+      }
+      return false;
+    }
+
+
+
+    @Override
+    public boolean equals(final Impl other)
+    {
+      if (other instanceof MultiOptionImpl)
+      {
+        final MultiOptionImpl tmp = (MultiOptionImpl) other;
+        return Arrays.equals(normalizedOptions, tmp.normalizedOptions);
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+
+
+    @Override
+    public String firstNormalizedOption()
+    {
+      return normalizedOptions[0];
+    }
+
+
+
+    @Override
+    public int hashCode()
+    {
+      return Arrays.hashCode(normalizedOptions);
+    }
+
+
+
+    @Override
+    public boolean hasOptions()
+    {
+      return true;
+    }
+
+
+
+    @Override
+    public boolean isSubTypeOf(final Impl other)
+    {
+      // Must contain a super-set of other's options.
+      if (other == ZERO_OPTION_IMPL)
+      {
+        return true;
+      }
+      else if (other.size() == 1)
+      {
+        return containsOption(other.firstNormalizedOption());
+      }
+      else if (other.size() > size())
+      {
+        return false;
+      }
+      else
+      {
+        // Check this contains other's options.
+        //
+        // This could be optimized more if required, but it's probably
+        // not worth it.
+        final MultiOptionImpl tmp = (MultiOptionImpl) other;
+        for (final String normalizedOption : tmp.normalizedOptions)
+        {
+          if (!containsOption(normalizedOption))
+          {
+            return false;
+          }
+        }
+        return true;
+      }
+    }
+
+
+
+    @Override
+    public boolean isSuperTypeOf(final Impl other)
+    {
+      // Must contain a sub-set of other's options.
+      for (final String normalizedOption : normalizedOptions)
+      {
+        if (!other.containsOption(normalizedOption))
+        {
+          return false;
+        }
+      }
+      return true;
+    }
+
+
+
+    public Iterator<String> iterator()
+    {
+      return Iterators.arrayIterator(options);
+    }
+
+
+
+    @Override
+    public int size()
+    {
+      return normalizedOptions.length;
+    }
+
+  }
+
+
+
+  private static final class SingleOptionImpl extends Impl
+  {
+
+    private final String normalizedOption;
+
+    private final String option;
+
+
+
+    private SingleOptionImpl(final String option, final String normalizedOption)
+    {
+      this.option = option;
+      this.normalizedOption = normalizedOption;
+    }
+
+
+
+    @Override
+    public int compareTo(final Impl other)
+    {
+      if (other == ZERO_OPTION_IMPL)
+      {
+        // If other has zero options then this sorts after.
+        return 1;
+      }
+      else if (other.size() == 1)
+      {
+        // Same number of options, so compare.
+        return normalizedOption.compareTo(other.firstNormalizedOption());
+      }
+      else
+      {
+        // Other has more options, so comes after.
+        return -1;
+      }
+    }
+
+
+
+    @Override
+    public boolean containsOption(final String normalizedOption)
+    {
+      return this.normalizedOption.equals(normalizedOption);
+    }
+
+
+
+    @Override
+    public boolean equals(final Impl other)
+    {
+      return other.size() == 1 && other.containsOption(normalizedOption);
+    }
+
+
+
+    @Override
+    public String firstNormalizedOption()
+    {
+      return normalizedOption;
+    }
+
+
+
+    @Override
+    public int hashCode()
+    {
+      return normalizedOption.hashCode();
+    }
+
+
+
+    @Override
+    public boolean hasOptions()
+    {
+      return true;
+    }
+
+
+
+    @Override
+    public boolean isSubTypeOf(final Impl other)
+    {
+      // Other must have no options or the same option.
+      if (other == ZERO_OPTION_IMPL)
+      {
+        return true;
+      }
+      else
+      {
+        return equals(other);
+      }
+    }
+
+
+
+    @Override
+    public boolean isSuperTypeOf(final Impl other)
+    {
+      // Other must have this option.
+      return other.containsOption(normalizedOption);
+    }
+
+
+
+    public Iterator<String> iterator()
+    {
+      return Iterators.singletonIterator(option);
+    }
+
+
+
+    @Override
+    public int size()
+    {
+      return 1;
+    }
+
+  }
+
+
+
+  private static final class ZeroOptionImpl extends Impl
+  {
+    private ZeroOptionImpl()
+    {
+      // Nothing to do.
+    }
+
+
+
+    @Override
+    public int compareTo(final Impl other)
+    {
+      // If other has options then this sorts before.
+      return this == other ? 0 : -1;
+    }
+
+
+
+    @Override
+    public boolean containsOption(final String normalizedOption)
+    {
+      return false;
+    }
+
+
+
+    @Override
+    public boolean equals(final Impl other)
+    {
+      return this == other;
+    }
+
+
+
+    @Override
+    public String firstNormalizedOption()
+    {
+      // No first option.
+      return null;
+    }
+
+
+
+    @Override
+    public int hashCode()
+    {
+      // Use attribute type hash code.
+      return 0;
+    }
+
+
+
+    @Override
+    public boolean hasOptions()
+    {
+      return false;
+    }
+
+
+
+    @Override
+    public boolean isSubTypeOf(final Impl other)
+    {
+      // Can only be a sub-type if other has no options.
+      return this == other;
+    }
+
+
+
+    @Override
+    public boolean isSuperTypeOf(final Impl other)
+    {
+      // Will always be a super-type.
+      return true;
+    }
+
+
+
+    public Iterator<String> iterator()
+    {
+      return Iterators.emptyIterator();
+    }
+
+
+
+    @Override
+    public int size()
+    {
+      return 0;
+    }
+
+  }
+
+
+
+  private static final ThreadLocal<WeakHashMap<
+    Schema, Map<String, AttributeDescription>>> CACHE =
+      new ThreadLocal<WeakHashMap<Schema, Map<String, AttributeDescription>>>()
+  {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected WeakHashMap<Schema, Map<String, AttributeDescription>> initialValue()
+    {
+      return new WeakHashMap<Schema, Map<String, AttributeDescription>>();
+    }
+
+  };
+
+  // Object class attribute description.
+  private static final ZeroOptionImpl ZERO_OPTION_IMPL = new ZeroOptionImpl();
+
+  private static final AttributeDescription OBJECT_CLASS;
+  static
+  {
+    final AttributeType attributeType = Schema.getCoreSchema()
+        .getAttributeType("2.5.4.0");
+    OBJECT_CLASS = new AttributeDescription(attributeType.getNameOrOID(),
+        attributeType, ZERO_OPTION_IMPL);
+  }
+
+  // This is the size of the per-thread per-schema attribute description
+  // cache. We should be conservative here in case there are many
+  // threads.
+  private static final int ATTRIBUTE_DESCRIPTION_CACHE_SIZE = 512;
+
+
+
+  /**
+   * Creates an attribute description having the same attribute type and options
+   * as the provided attribute description and, in addition, the provided list
+   * of options.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param options
+   *          The attribute options.
+   * @return The new attribute description containing {@code options}.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code options} was {@code
+   *           null}.
+   */
+  public static AttributeDescription create(
+      final AttributeDescription attributeDescription, final String... options)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription, options);
+
+    // This should not be called very often, so don't optimize.
+    AttributeDescription newAttributeDescription = attributeDescription;
+    for (final String option : options)
+    {
+      newAttributeDescription = create(newAttributeDescription, option);
+    }
+    return newAttributeDescription;
+  }
+
+
+
+  /**
+   * Creates an attribute description having the same attribute type and options
+   * as the provided attribute description and, in addition, the provided new
+   * option.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param option
+   *          The attribute option.
+   * @return The new attribute description containing {@code option}.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code option} was {@code
+   *           null}.
+   */
+  public static AttributeDescription create(
+      final AttributeDescription attributeDescription, final String option)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription, option);
+
+    final String normalizedOption = toLowerCase(option);
+    if (attributeDescription.pimpl.containsOption(normalizedOption))
+    {
+      return attributeDescription;
+    }
+
+    final String oldAttributeDescription = attributeDescription.attributeDescription;
+    final StringBuilder builder = new StringBuilder(oldAttributeDescription
+        .length()
+        + option.length() + 1);
+    builder.append(oldAttributeDescription);
+    builder.append(';');
+    builder.append(option);
+    final String newAttributeDescription = builder.toString();
+
+    final Impl impl = attributeDescription.pimpl;
+    if (impl instanceof ZeroOptionImpl)
+    {
+      return new AttributeDescription(newAttributeDescription,
+          attributeDescription.attributeType, new SingleOptionImpl(option,
+              normalizedOption));
+
+    }
+    else if (impl instanceof SingleOptionImpl)
+    {
+      final SingleOptionImpl simpl = (SingleOptionImpl) impl;
+
+      final String[] newOptions = new String[2];
+      newOptions[0] = simpl.option;
+      newOptions[1] = option;
+
+      final String[] newNormalizedOptions = new String[2];
+      if (normalizedOption.compareTo(simpl.normalizedOption) < 0)
+      {
+        newNormalizedOptions[0] = normalizedOption;
+        newNormalizedOptions[1] = simpl.normalizedOption;
+      }
+
+      return new AttributeDescription(newAttributeDescription,
+          attributeDescription.attributeType, new MultiOptionImpl(newOptions,
+              newNormalizedOptions));
+    }
+    else
+    {
+      final MultiOptionImpl mimpl = (MultiOptionImpl) impl;
+
+      final int sz1 = mimpl.options.length;
+      final String[] newOptions = new String[sz1 + 1];
+      for (int i = 0; i < sz1; i++)
+      {
+        newOptions[i] = mimpl.options[i];
+      }
+      newOptions[sz1] = option;
+
+      final int sz2 = mimpl.normalizedOptions.length;
+      final String[] newNormalizedOptions = new String[sz2 + 1];
+      boolean inserted = false;
+      for (int i = 0; i < sz2; i++)
+      {
+        if (!inserted)
+        {
+          final String s = mimpl.normalizedOptions[i];
+          if (normalizedOption.compareTo(s) < 0)
+          {
+            newNormalizedOptions[i] = normalizedOption;
+            newNormalizedOptions[i + 1] = s;
+            inserted = true;
+          }
+          else
+          {
+            newNormalizedOptions[i] = s;
+          }
+        }
+        else
+        {
+          newNormalizedOptions[i + 1] = mimpl.normalizedOptions[i];
+        }
+      }
+
+      if (!inserted)
+      {
+        newNormalizedOptions[sz2] = normalizedOption;
+      }
+
+      return new AttributeDescription(newAttributeDescription,
+          attributeDescription.attributeType, new MultiOptionImpl(newOptions,
+              newNormalizedOptions));
+    }
+  }
+
+
+
+  /**
+   * Creates an attribute description having the provided attribute type and no
+   * options.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @return The attribute description.
+   * @throws NullPointerException
+   *           If {@code attributeType} was {@code null}.
+   */
+  public static AttributeDescription create(final AttributeType attributeType)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeType);
+
+    // Use object identity in case attribute type does not come from
+    // core schema.
+    if (attributeType == OBJECT_CLASS.getAttributeType())
+    {
+      return OBJECT_CLASS;
+    }
+    else
+    {
+      return new AttributeDescription(attributeType.getNameOrOID(),
+          attributeType, ZERO_OPTION_IMPL);
+    }
+  }
+
+
+
+  /**
+   * Creates an attribute description having the provided attribute type and
+   * single option.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @param option
+   *          The attribute option.
+   * @return The attribute description.
+   * @throws NullPointerException
+   *           If {@code attributeType} or {@code option} was {@code null}.
+   */
+  public static AttributeDescription create(final AttributeType attributeType,
+      final String option) throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeType, option);
+
+    final String oid = attributeType.getNameOrOID();
+    final StringBuilder builder = new StringBuilder(oid.length()
+        + option.length() + 1);
+    builder.append(oid);
+    builder.append(';');
+    builder.append(option);
+    final String attributeDescription = builder.toString();
+    final String normalizedOption = toLowerCase(option);
+
+    return new AttributeDescription(attributeDescription, attributeType,
+        new SingleOptionImpl(option, normalizedOption));
+  }
+
+
+
+  /**
+   * Creates an attribute description having the provided attribute type and
+   * options.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @param options
+   *          The attribute options.
+   * @return The attribute description.
+   * @throws NullPointerException
+   *           If {@code attributeType} or {@code options} was {@code null}.
+   */
+  public static AttributeDescription create(final AttributeType attributeType,
+      final String... options) throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeType, options);
+
+    switch (options.length)
+    {
+    case 0:
+      return create(attributeType);
+    case 1:
+      return create(attributeType, options[0]);
+    default:
+      final String[] optionsList = new String[options.length];
+      final String[] normalizedOptions = new String[options.length];
+
+      final String oid = attributeType.getNameOrOID();
+      final StringBuilder builder = new StringBuilder(oid.length()
+          + options[0].length() + options[1].length() + 2);
+      builder.append(oid);
+
+      int i = 0;
+      for (final String option : options)
+      {
+        builder.append(';');
+        builder.append(option);
+        optionsList[i] = option;
+        final String normalizedOption = toLowerCase(option);
+        normalizedOptions[i++] = normalizedOption;
+      }
+      Arrays.sort(normalizedOptions);
+
+      final String attributeDescription = builder.toString();
+      return new AttributeDescription(attributeDescription, attributeType,
+          new MultiOptionImpl(optionsList, normalizedOptions));
+    }
+
+  }
+
+
+
+  /**
+   * Returns an attribute description representing the object class attribute
+   * type with no options.
+   *
+   * @return The object class attribute description.
+   */
+  public static AttributeDescription objectClass()
+  {
+    return OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of an attribute description
+   * using the default schema.
+   *
+   * @param attributeDescription
+   *          The LDAP string representation of an attribute description.
+   * @return The parsed attribute description.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} is not a valid LDAP string
+   *           representation of an attribute description.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  public static AttributeDescription valueOf(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return valueOf(attributeDescription, Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of an attribute description
+   * using the provided schema.
+   *
+   * @param attributeDescription
+   *          The LDAP string representation of an attribute description.
+   * @param schema
+   *          The schema to use when parsing the attribute description.
+   * @return The parsed attribute description.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} is not a valid LDAP string
+   *           representation of an attribute description.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code schema} was {@code
+   *           null}.
+   */
+  @SuppressWarnings("serial")
+  public static AttributeDescription valueOf(final String attributeDescription,
+      final Schema schema) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription, schema);
+
+    // First look up the attribute description in the cache.
+    final WeakHashMap<Schema, Map<String, AttributeDescription>> threadLocalMap = CACHE
+        .get();
+    Map<String, AttributeDescription> schemaLocalMap = threadLocalMap
+        .get(schema);
+
+    AttributeDescription ad = null;
+    if (schemaLocalMap == null)
+    {
+      schemaLocalMap = new LinkedHashMap<String, AttributeDescription>(
+          ATTRIBUTE_DESCRIPTION_CACHE_SIZE, 0.75f, true)
+      {
+        @Override
+        protected boolean removeEldestEntry(
+            final Map.Entry<String, AttributeDescription> eldest)
+        {
+          return size() > ATTRIBUTE_DESCRIPTION_CACHE_SIZE;
+        }
+      };
+      threadLocalMap.put(schema, schemaLocalMap);
+    }
+    else
+    {
+      ad = schemaLocalMap.get(attributeDescription);
+    }
+
+    // Cache miss: decode and cache.
+    if (ad == null)
+    {
+      ad = valueOf0(attributeDescription, schema);
+      schemaLocalMap.put(attributeDescription, ad);
+    }
+
+    return ad;
+  }
+
+
+
+  private static int skipTrailingWhiteSpace(final String attributeDescription,
+      int i, final int length) throws LocalizedIllegalArgumentException
+  {
+    char c;
+    while (i < length)
+    {
+      c = attributeDescription.charAt(i);
+      if (c != ' ')
+      {
+        final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_INTERNAL_WHITESPACE
+            .get(attributeDescription);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+      i++;
+    }
+    return i;
+  }
+
+
+
+  // Uncached valueOf implementation.
+  private static AttributeDescription valueOf0(
+      final String attributeDescription, final Schema schema)
+      throws LocalizedIllegalArgumentException
+  {
+    int i = 0;
+    final int length = attributeDescription.length();
+    char c = 0;
+
+    // Skip leading white space.
+    while (i < length)
+    {
+      c = attributeDescription.charAt(i);
+      if (c != ' ')
+      {
+        break;
+      }
+      i++;
+    }
+
+    // If we're already at the end then the attribute description only
+    // contained whitespace.
+    if (i == length)
+    {
+      final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_EMPTY
+          .get(attributeDescription);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Validate the first non-whitespace character.
+    ASCIICharProp cp = ASCIICharProp.valueOf(c);
+    if (cp == null)
+    {
+      final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
+          .get(attributeDescription, c, i);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Mark the attribute type start position.
+    final int attributeTypeStart = i;
+    if (cp.isLetter())
+    {
+      // Non-numeric OID: letter + zero or more keychars.
+      i++;
+      while (i < length)
+      {
+        c = attributeDescription.charAt(i);
+
+        if (c == ';' || c == ' ')
+        {
+          break;
+        }
+
+        cp = ASCIICharProp.valueOf(c);
+        if (!cp.isKeyChar())
+        {
+          final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
+              .get(attributeDescription, c, i);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+        i++;
+      }
+
+      // (charAt(i) == ';' || c == ' ' || i == length)
+    }
+    else if (cp.isDigit())
+    {
+      // Numeric OID: decimal digit + zero or more dots or decimals.
+      i++;
+      while (i < length)
+      {
+        c = attributeDescription.charAt(i);
+        if (c == ';' || c == ' ')
+        {
+          break;
+        }
+
+        cp = ASCIICharProp.valueOf(c);
+        if (c != '.' && !cp.isDigit())
+        {
+          final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
+              .get(attributeDescription, c, i);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+        i++;
+      }
+
+      // (charAt(i) == ';' || charAt(i) == ' ' || i == length)
+    }
+    else
+    {
+      final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
+          .get(attributeDescription, c, i);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Skip trailing white space.
+    final int attributeTypeEnd = i;
+    if (c == ' ')
+    {
+      i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
+    }
+
+    // Determine the portion of the string containing the attribute type
+    // name.
+    String oid;
+    if (attributeTypeStart == 0 && attributeTypeEnd == length)
+    {
+      oid = attributeDescription;
+    }
+    else
+    {
+      oid = attributeDescription
+          .substring(attributeTypeStart, attributeTypeEnd);
+    }
+
+    if (oid.length() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_NO_TYPE
+          .get(attributeDescription);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Get the attribute type from the schema.
+    AttributeType attributeType;
+    try
+    {
+      attributeType = schema.getAttributeType(oid);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_TYPE_NOT_FOUND
+          .get(attributeDescription, e.getMessageObject());
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // If we're already at the end of the attribute description then it
+    // does not contain any options.
+    if (i == length)
+    {
+      // Use object identity in case attribute type does not come from
+      // core schema.
+      if (attributeType == OBJECT_CLASS.getAttributeType()
+          && attributeDescription.equals(OBJECT_CLASS.toString()))
+      {
+        return OBJECT_CLASS;
+      }
+      else
+      {
+        return new AttributeDescription(attributeDescription, attributeType,
+            ZERO_OPTION_IMPL);
+      }
+    }
+
+    // At this point 'i' must point at a semi-colon.
+    i++;
+    StringBuilder builder = null;
+    int optionStart = i;
+    while (i < length)
+    {
+      c = attributeDescription.charAt(i);
+      if (c == ' ' || c == ';')
+      {
+        break;
+      }
+
+      cp = ASCIICharProp.valueOf(c);
+      if (!cp.isKeyChar())
+      {
+        final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
+            .get(attributeDescription, c, i);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      if (builder == null)
+      {
+        if (cp.isUpperCase())
+        {
+          // Need to normalize the option.
+          builder = new StringBuilder(length - optionStart);
+          builder.append(attributeDescription, optionStart, i);
+          builder.append(cp.toLowerCase());
+        }
+      }
+      else
+      {
+        builder.append(cp.toLowerCase());
+      }
+      i++;
+    }
+
+    String option = attributeDescription.substring(optionStart, i);
+    String normalizedOption;
+    if (builder != null)
+    {
+      normalizedOption = builder.toString();
+    }
+    else
+    {
+      normalizedOption = option;
+    }
+
+    if (option.length() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_EMPTY_OPTION
+          .get(attributeDescription);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Skip trailing white space.
+    if (c == ' ')
+    {
+      i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
+    }
+
+    // If we're already at the end of the attribute description then it
+    // only contains a single option.
+    if (i == length)
+    {
+      return new AttributeDescription(attributeDescription, attributeType,
+          new SingleOptionImpl(option, normalizedOption));
+    }
+
+    // Multiple options need sorting and duplicates removed - we could
+    // optimize a bit further here for 2 option attribute descriptions.
+    final List<String> options = new LinkedList<String>();
+    options.add(option);
+
+    final SortedSet<String> normalizedOptions = new TreeSet<String>();
+    normalizedOptions.add(normalizedOption);
+
+    while (i < length)
+    {
+      // At this point 'i' must point at a semi-colon.
+      i++;
+      builder = null;
+      optionStart = i;
+      while (i < length)
+      {
+        c = attributeDescription.charAt(i);
+        if (c == ' ' || c == ';')
+        {
+          break;
+        }
+
+        cp = ASCIICharProp.valueOf(c);
+        if (!cp.isKeyChar())
+        {
+          final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
+              .get(attributeDescription, c, i);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        if (builder == null)
+        {
+          if (cp.isUpperCase())
+          {
+            // Need to normalize the option.
+            builder = new StringBuilder(length - optionStart);
+            builder.append(attributeDescription, optionStart, i);
+            builder.append(cp.toLowerCase());
+          }
+        }
+        else
+        {
+          builder.append(cp.toLowerCase());
+        }
+        i++;
+      }
+
+      option = attributeDescription.substring(optionStart, i);
+      if (builder != null)
+      {
+        normalizedOption = builder.toString();
+      }
+      else
+      {
+        normalizedOption = option;
+      }
+
+      if (option.length() == 0)
+      {
+        final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_EMPTY_OPTION
+            .get(attributeDescription);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip trailing white space.
+      if (c == ' ')
+      {
+        i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
+      }
+
+      options.add(option);
+      normalizedOptions.add(normalizedOption);
+    }
+
+    return new AttributeDescription(attributeDescription, attributeType,
+        new MultiOptionImpl(options.toArray(new String[options.size()]),
+            normalizedOptions.toArray(new String[normalizedOptions.size()])));
+  }
+
+
+
+  private final String attributeDescription;
+
+  private final AttributeType attributeType;
+
+  private final Impl pimpl;
+
+
+
+  // Private constructor.
+  private AttributeDescription(final String attributeDescription,
+      final AttributeType attributeType, final Impl pimpl)
+  {
+    this.attributeDescription = attributeDescription;
+    this.attributeType = attributeType;
+    this.pimpl = pimpl;
+  }
+
+
+
+  /**
+   * Compares this attribute description to the provided attribute description.
+   * The attribute types are compared first and then, if equal, the options are
+   * normalized, sorted, and compared.
+   *
+   * @param other
+   *          The attribute description to be compared.
+   * @return A negative integer, zero, or a positive integer as this attribute
+   *         description is less than, equal to, or greater than the specified
+   *         attribute description.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public int compareTo(final AttributeDescription other)
+      throws NullPointerException
+  {
+    final int result = attributeType.compareTo(other.attributeType);
+    if (result != 0)
+    {
+      return result;
+    }
+    else
+    {
+      // Attribute type is the same, so compare options.
+      return pimpl.compareTo(other.pimpl);
+    }
+  }
+
+
+
+  /**
+   * Indicates whether or not this attribute description contains the provided
+   * option.
+   *
+   * @param option
+   *          The option for which to make the determination.
+   * @return {@code true} if this attribute description has the provided option,
+   *         or {@code false} if not.
+   * @throws NullPointerException
+   *           If {@code option} was {@code null}.
+   */
+  public boolean containsOption(final String option)
+      throws NullPointerException
+  {
+    final String normalizedOption = toLowerCase(option);
+    return pimpl.containsOption(normalizedOption);
+  }
+
+
+
+  /**
+   * Indicates whether the provided object is an attribute description which is
+   * equal to this attribute description. It will be considered equal if the
+   * attribute type and normalized sorted list of options are identical.
+   *
+   * @param o
+   *          The object for which to make the determination.
+   * @return {@code true} if the provided object is an attribute description
+   *         that is equal to this attribute description, or {@code false} if
+   *         not.
+   */
+  @Override
+  public boolean equals(final Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+
+    if (!(o instanceof AttributeDescription))
+    {
+      return false;
+    }
+
+    final AttributeDescription other = (AttributeDescription) o;
+    if (!attributeType.equals(other.attributeType))
+    {
+      return false;
+    }
+
+    // Attribute type is the same, compare options.
+    return pimpl.equals(other.pimpl);
+  }
+
+
+
+  /**
+   * Returns the attribute type associated with this attribute description.
+   *
+   * @return The attribute type associated with this attribute description.
+   */
+  public AttributeType getAttributeType()
+  {
+    return attributeType;
+  }
+
+
+
+  /**
+   * Returns an {@code Iterable} containing the options contained in this
+   * attribute description. Attempts to remove options using an iterator's
+   * {@code remove()} method are not permitted and will result in an {@code
+   * UnsupportedOperationException} being thrown.
+   *
+   * @return An {@code Iterable} containing the options.
+   */
+  public Iterable<String> getOptions()
+  {
+    return pimpl;
+  }
+
+
+
+  /**
+   * Returns the hash code for this attribute description. It will be calculated
+   * as the sum of the hash codes of the attribute type and normalized sorted
+   * list of options.
+   *
+   * @return The hash code for this attribute description.
+   */
+  @Override
+  public int hashCode()
+  {
+    // FIXME: should we cache this?
+    return attributeType.hashCode() * 31 + pimpl.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether or not this attribute description has any options.
+   *
+   * @return {@code true} if this attribute description has any options, or
+   *         {@code false} if not.
+   */
+  public boolean hasOptions()
+  {
+    return pimpl.hasOptions();
+  }
+
+
+
+  /**
+   * Indicates whether or not this attribute description is the {@code
+   * objectClass} attribute description with no options.
+   *
+   * @return {@code true} if this attribute description is the {@code
+   *         objectClass} attribute description with no options, or {@code
+   *         false} if not.
+   */
+  public boolean isObjectClass()
+  {
+    return attributeType.isObjectClass() && !hasOptions();
+  }
+
+
+
+  /**
+   * Indicates whether or not this attribute description is a sub-type of the
+   * provided attribute description as defined in RFC 4512 section 2.5.
+   * Specifically, this method will return {@code true} if and only if the
+   * following conditions are both {@code true}:
+   * <ul>
+   * <li>This attribute description has an attribute type which is equal to, or
+   * is a sub-type of, the attribute type in the provided attribute description.
+   * <li>This attribute description contains all of the options contained in the
+   * provided attribute description.
+   * </ul>
+   * Note that this method will return {@code true} if this attribute
+   * description is equal to the provided attribute description.
+   *
+   * @param other
+   *          The attribute description for which to make the determination.
+   * @return {@code true} if this attribute description is a sub-type of the
+   *         provided attribute description, or {@code false} if not.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public boolean isSubTypeOf(final AttributeDescription other)
+      throws NullPointerException
+  {
+    if (!attributeType.isSubTypeOf(other.attributeType))
+    {
+      return false;
+    }
+    else
+    {
+      return pimpl.isSubTypeOf(other.pimpl);
+    }
+  }
+
+
+
+  /**
+   * Indicates whether or not this attribute description is a super-type of the
+   * provided attribute description as defined in RFC 4512 section 2.5.
+   * Specifically, this method will return {@code true} if and only if the
+   * following conditions are both {@code true}:
+   * <ul>
+   * <li>This attribute description has an attribute type which is equal to, or
+   * is a super-type of, the attribute type in the provided attribute
+   * description.
+   * <li>This attribute description contains a sub-set of the options contained
+   * in the provided attribute description.
+   * </ul>
+   * Note that this method will return {@code true} if this attribute
+   * description is equal to the provided attribute description.
+   *
+   * @param other
+   *          The attribute description for which to make the determination.
+   * @return {@code true} if this attribute description is a super-type of the
+   *         provided attribute description, or {@code false} if not.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public boolean isSuperTypeOf(final AttributeDescription other)
+      throws NullPointerException
+  {
+    if (!other.attributeType.isSubTypeOf(attributeType))
+    {
+      return false;
+    }
+    else
+    {
+      return pimpl.isSuperTypeOf(other.pimpl);
+    }
+  }
+
+
+
+  /**
+   * Returns the string representation of this attribute description as defined
+   * in RFC4512 section 2.5.
+   *
+   * @return The string representation of this attribute description.
+   */
+  @Override
+  public String toString()
+  {
+    return attributeDescription;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeFactory.java
new file mode 100644
index 0000000..3bd3af5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AttributeFactory.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * Attribute factories are included with a set of {@code DecodeOptions} in order
+ * to allow application to control how {@code Attribute} instances are created
+ * when decoding requests and responses.
+ *
+ * @see Attribute
+ * @see DecodeOptions
+ */
+public interface AttributeFactory
+{
+  /**
+   * Creates an attribute using the provided attribute description and no
+   * values.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @return The new attribute.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  Attribute newAttribute(AttributeDescription attributeDescription)
+      throws NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attributes.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attributes.java
new file mode 100644
index 0000000..aec200c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Attributes.java
@@ -0,0 +1,627 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.opends.sdk.schema.AttributeType;
+
+import com.sun.opends.sdk.util.Iterators;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class contains methods for creating and manipulating attributes.
+ */
+public final class Attributes
+{
+
+  /**
+   * Empty attribute.
+   */
+  private static final class EmptyAttribute extends AbstractAttribute
+  {
+
+    private final AttributeDescription attributeDescription;
+
+
+
+    private EmptyAttribute(final AttributeDescription attributeDescription)
+    {
+      this.attributeDescription = attributeDescription;
+    }
+
+
+
+    @Override
+    public boolean add(final ByteString value)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public void clear() throws UnsupportedOperationException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public boolean contains(final Object value) throws NullPointerException
+    {
+      return false;
+    }
+
+
+
+    @Override
+    public AttributeDescription getAttributeDescription()
+    {
+      return attributeDescription;
+    }
+
+
+
+    @Override
+    public boolean isEmpty()
+    {
+      return true;
+    }
+
+
+
+    @Override
+    public Iterator<ByteString> iterator()
+    {
+      return Iterators.emptyIterator();
+    }
+
+
+
+    @Override
+    public boolean remove(final Object value)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public int size()
+    {
+      return 0;
+    }
+
+  }
+
+
+
+  /**
+   * Renamed attribute.
+   */
+  private static final class RenamedAttribute implements Attribute
+  {
+
+    private final Attribute attribute;
+
+    private final AttributeDescription attributeDescription;
+
+
+
+    private RenamedAttribute(final Attribute attribute,
+        final AttributeDescription attributeDescription)
+    {
+      this.attribute = attribute;
+      this.attributeDescription = attributeDescription;
+    }
+
+
+
+    public boolean add(final ByteString value)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.add(value);
+    }
+
+
+
+    public boolean add(final Object firstValue, final Object... remainingValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.add(firstValue, remainingValues);
+    }
+
+
+
+    public boolean addAll(final Collection<? extends ByteString> values)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.addAll(values);
+    }
+
+
+
+    public boolean addAll(final Collection<? extends ByteString> values,
+        final Collection<? super ByteString> duplicateValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.addAll(values, duplicateValues);
+    }
+
+
+
+    public void clear() throws UnsupportedOperationException
+    {
+      attribute.clear();
+    }
+
+
+
+    public boolean contains(final Object value) throws NullPointerException
+    {
+      return attribute.contains(value);
+    }
+
+
+
+    public boolean containsAll(final Collection<?> values)
+        throws NullPointerException
+    {
+      return attribute.containsAll(values);
+    }
+
+
+
+    @Override
+    public boolean equals(final Object object)
+    {
+      return AbstractAttribute.equals(this, object);
+    }
+
+
+
+    public ByteString firstValue() throws NoSuchElementException
+    {
+      return attribute.firstValue();
+    }
+
+
+
+    public String firstValueAsString() throws NoSuchElementException
+    {
+      return attribute.firstValueAsString();
+    }
+
+
+
+    public AttributeDescription getAttributeDescription()
+    {
+      return attributeDescription;
+    }
+
+
+
+    public String getAttributeDescriptionAsString()
+    {
+      return attributeDescription.toString();
+    }
+
+
+
+    @Override
+    public int hashCode()
+    {
+      return AbstractAttribute.hashCode(this);
+    }
+
+
+
+    public boolean isEmpty()
+    {
+      return attribute.isEmpty();
+    }
+
+
+
+    public Iterator<ByteString> iterator()
+    {
+      return attribute.iterator();
+    }
+
+
+
+    public boolean remove(final Object value)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.remove(value);
+    }
+
+
+
+    public boolean removeAll(final Collection<?> values)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.removeAll(values);
+    }
+
+
+
+    public <T> boolean removeAll(final Collection<T> values,
+        final Collection<? super T> missingValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.removeAll(values, missingValues);
+    }
+
+
+
+    public boolean retainAll(final Collection<?> values)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.retainAll(values);
+    }
+
+
+
+    public <T> boolean retainAll(final Collection<T> values,
+        final Collection<? super T> missingValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return attribute.retainAll(values, missingValues);
+    }
+
+
+
+    public int size()
+    {
+      return attribute.size();
+    }
+
+
+
+    public ByteString[] toArray()
+    {
+      return attribute.toArray();
+    }
+
+
+
+    public <T> T[] toArray(final T[] array) throws ArrayStoreException,
+        NullPointerException
+    {
+      return attribute.toArray(array);
+    }
+
+
+
+    @Override
+    public String toString()
+    {
+      return AbstractAttribute.toString(this);
+    }
+
+  }
+
+
+
+  /**
+   * Unmodifiable attribute.
+   */
+  private static final class UnmodifiableAttribute implements Attribute
+  {
+
+    private final Attribute attribute;
+
+
+
+    private UnmodifiableAttribute(final Attribute attribute)
+    {
+      this.attribute = attribute;
+    }
+
+
+
+    public boolean add(final ByteString value)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public boolean add(final Object firstValue, final Object... remainingValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public boolean addAll(final Collection<? extends ByteString> values)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public boolean addAll(final Collection<? extends ByteString> values,
+        final Collection<? super ByteString> duplicateValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public void clear() throws UnsupportedOperationException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public boolean contains(final Object value) throws NullPointerException
+    {
+      return attribute.contains(value);
+    }
+
+
+
+    public boolean containsAll(final Collection<?> values)
+        throws NullPointerException
+    {
+      return attribute.containsAll(values);
+    }
+
+
+
+    @Override
+    public boolean equals(final Object object)
+    {
+      return (object == this || attribute.equals(object));
+    }
+
+
+
+    public ByteString firstValue() throws NoSuchElementException
+    {
+      return attribute.firstValue();
+    }
+
+
+
+    public String firstValueAsString() throws NoSuchElementException
+    {
+      return attribute.firstValueAsString();
+    }
+
+
+
+    public AttributeDescription getAttributeDescription()
+    {
+      return attribute.getAttributeDescription();
+    }
+
+
+
+    public String getAttributeDescriptionAsString()
+    {
+      return attribute.getAttributeDescriptionAsString();
+    }
+
+
+
+    @Override
+    public int hashCode()
+    {
+      return attribute.hashCode();
+    }
+
+
+
+    public boolean isEmpty()
+    {
+      return attribute.isEmpty();
+    }
+
+
+
+    public Iterator<ByteString> iterator()
+    {
+      return Iterators.unmodifiableIterator(attribute.iterator());
+    }
+
+
+
+    public boolean remove(final Object value)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public boolean removeAll(final Collection<?> values)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public <T> boolean removeAll(final Collection<T> values,
+        final Collection<? super T> missingValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public boolean retainAll(final Collection<?> values)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public <T> boolean retainAll(final Collection<T> values,
+        final Collection<? super T> missingValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    public int size()
+    {
+      return attribute.size();
+    }
+
+
+
+    public ByteString[] toArray()
+    {
+      return attribute.toArray();
+    }
+
+
+
+    public <T> T[] toArray(final T[] array) throws ArrayStoreException,
+        NullPointerException
+    {
+      return attribute.toArray(array);
+    }
+
+
+
+    @Override
+    public String toString()
+    {
+      return attribute.toString();
+    }
+
+  }
+
+
+
+  /**
+   * Returns a read-only empty attribute having the specified attribute
+   * description.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @return The empty attribute.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  public static final Attribute emptyAttribute(
+      final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    return new EmptyAttribute(attributeDescription);
+  }
+
+
+
+  /**
+   * Returns a view of {@code attribute} having a different attribute
+   * description. All operations on the returned attribute "pass-through" to the
+   * underlying attribute.
+   *
+   * @param attribute
+   *          The attribute to be renamed.
+   * @param attributeDescription
+   *          The new attribute description for {@code attribute}, which must be
+   *          compatible with {@code attribute}'s attribute description.
+   * @return A renamed view of {@code attribute}.
+   * @throws IllegalArgumentException
+   *           If {@code attributeDescription} does not have the same attribute
+   *           type as {@code attribute}'s attribute description.
+   * @throws NullPointerException
+   *           If {@code attribute} or {@code attributeDescription} was {@code
+   *           null}.
+   */
+  public static final Attribute renameAttribute(final Attribute attribute,
+      final AttributeDescription attributeDescription)
+      throws IllegalArgumentException, NullPointerException
+  {
+    final AttributeType oldType = attribute.getAttributeDescription()
+        .getAttributeType();
+    final AttributeType newType = attributeDescription.getAttributeType();
+
+    // We could relax a bit by ensuring that they are both compatible
+    // (e.g. one sub-type of another, or same equality matching rule,
+    // etc).
+    Validator.ensureTrue(oldType.equals(newType),
+        "Old and new attribute type are not the same");
+
+    return new RenamedAttribute(attribute, attributeDescription);
+  }
+
+
+
+  /**
+   * Returns a read-only view of {@code attribute}. Query operations on the
+   * returned attribute "read-through" to the underlying attribute, and attempts
+   * to modify the returned attribute either directly or indirectly via an
+   * iterator result in an {@code UnsupportedOperationException}.
+   *
+   * @param attribute
+   *          The attribute for which a read-only view is to be returned.
+   * @return A read-only view of {@code attribute}.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  public static final Attribute unmodifiableAttribute(final Attribute attribute)
+      throws NullPointerException
+  {
+    return new UnmodifiableAttribute(attribute);
+  }
+
+
+
+  // Prevent instantiation.
+  private Attributes()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticatedConnectionFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticatedConnectionFactory.java
new file mode 100644
index 0000000..168d660
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticatedConnectionFactory.java
@@ -0,0 +1,240 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.requests.BindRequest;
+import org.opends.sdk.responses.BindResult;
+
+import com.sun.opends.sdk.util.AsynchronousConnectionDecorator;
+import com.sun.opends.sdk.util.FutureResultTransformer;
+import com.sun.opends.sdk.util.RecursiveFutureResult;
+
+
+
+/**
+ * An authenticated connection factory can be used to create pre-authenticated
+ * connections to a Directory Server.
+ * <p>
+ * The connections returned by an authenticated connection factory support all
+ * operations with the exception of Bind requests. Attempts to perform a Bind
+ * will result in an {@code UnsupportedOperationException}.
+ * <p>
+ * If the Bind request fails for some reason (e.g. invalid credentials), then
+ * the connection attempt will fail and an {@code ErrorResultException} will be
+ * thrown.
+ */
+final class AuthenticatedConnectionFactory extends AbstractConnectionFactory
+{
+
+  /**
+   * An authenticated asynchronous connection supports all operations except
+   * Bind operations.
+   */
+  public static final class AuthenticatedAsynchronousConnection extends
+      AsynchronousConnectionDecorator
+  {
+
+    private AuthenticatedAsynchronousConnection(
+        final AsynchronousConnection connection)
+    {
+      super(connection);
+    }
+
+
+
+    /**
+     * Bind operations are not supported by pre-authenticated connections. This
+     * method will always throw {@code UnsupportedOperationException}.
+     */
+    public FutureResult<BindResult> bind(final BindRequest request,
+        final ResultHandler<? super BindResult> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * Bind operations are not supported by pre-authenticated connections. This
+     * method will always throw {@code UnsupportedOperationException}.
+     */
+    public FutureResult<BindResult> bind(final BindRequest request,
+        final ResultHandler<? super BindResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+      StringBuilder builder = new StringBuilder();
+      builder.append("AuthenticatedConnection(");
+      builder.append(connection);
+      builder.append(')');
+      return builder.toString();
+    }
+
+  }
+
+
+
+  private static final class FutureResultImpl
+  {
+    private final FutureResultTransformer<BindResult, AsynchronousConnection> futureBindResult;
+
+    private final RecursiveFutureResult<AsynchronousConnection, BindResult> futureConnectionResult;
+
+    private final BindRequest bindRequest;
+
+    private AsynchronousConnection connection;
+
+
+
+    private FutureResultImpl(final BindRequest request,
+        final ResultHandler<? super AsynchronousConnection> handler)
+    {
+      this.bindRequest = request;
+      this.futureBindResult = new FutureResultTransformer<BindResult, AsynchronousConnection>(
+          handler)
+      {
+
+        @Override
+        protected ErrorResultException transformErrorResult(
+            final ErrorResultException errorResult)
+        {
+          // Ensure that the connection is closed.
+          try
+          {
+            connection.close();
+            connection = null;
+          }
+          catch (final Exception e)
+          {
+            // Ignore.
+          }
+          return errorResult;
+        }
+
+
+
+        @Override
+        protected AsynchronousConnection transformResult(final BindResult result)
+            throws ErrorResultException
+        {
+          return new AuthenticatedAsynchronousConnection(connection);
+        }
+
+      };
+      this.futureConnectionResult = new RecursiveFutureResult<AsynchronousConnection, BindResult>(
+          futureBindResult)
+      {
+
+        @Override
+        protected FutureResult<? extends BindResult> chainResult(
+            final AsynchronousConnection innerResult,
+            final ResultHandler<? super BindResult> handler)
+            throws ErrorResultException
+        {
+          connection = innerResult;
+          return connection.bind(bindRequest, handler);
+        }
+      };
+      futureBindResult.setFutureResult(futureConnectionResult);
+    }
+
+  }
+
+
+
+  private final BindRequest request;
+
+  private final ConnectionFactory parentFactory;
+
+
+
+  /**
+   * Creates a new authenticated connection factory which will obtain
+   * connections using the provided connection factory and immediately perform
+   * the provided Bind request.
+   *
+   * @param factory
+   *          The connection factory to use for connecting to the Directory
+   *          Server.
+   * @param request
+   *          The Bind request to use for authentication.
+   */
+  AuthenticatedConnectionFactory(final ConnectionFactory factory,
+      final BindRequest request)
+  {
+    this.parentFactory = factory;
+
+    // FIXME: should do a defensive copy.
+    this.request = request;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> handler)
+  {
+    final FutureResultImpl future = new FutureResultImpl(request, handler);
+    future.futureConnectionResult.setFutureResult(parentFactory
+        .getAsynchronousConnection(future.futureConnectionResult));
+    return future.futureBindResult;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AuthenticatedConnectionFactory(");
+    builder.append(String.valueOf(parentFactory));
+    builder.append(')');
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticationException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticationException.java
new file mode 100644
index 0000000..2e36959
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthenticationException.java
@@ -0,0 +1,60 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Bind
+ * Request failed due to an authentication failure. More specifically, this
+ * exception is used for the following error result codes:
+ * <ul>
+ * <li>{@link ResultCode#AUTH_METHOD_NOT_SUPPORTED AUTH_METHOD_NOT_SUPPORTED} -
+ * the Bind request failed because it referenced an invalid SASL mechanism.
+ * <li>{@link ResultCode#CLIENT_SIDE_AUTH_UNKNOWN CLIENT_SIDE_AUTH_UNKNOWN} -
+ * the Bind request failed because the user requested an authentication
+ * mechanism which is unknown or unsupported by the OpenDS SDK.
+ * <li>{@link ResultCode#INAPPROPRIATE_AUTHENTICATION
+ * INAPPROPRIATE_AUTHENTICATION} - the Bind request failed because the requested
+ * type of authentication was not appropriate for the targeted entry.
+ * <li>{@link ResultCode#INVALID_CREDENTIALS INVALID_CREDENTIALS} - the Bind
+ * request failed because the user did not provide a valid set of credentials.
+ * </ul>
+ */
+@SuppressWarnings("serial")
+public class AuthenticationException extends ErrorResultException
+{
+  AuthenticationException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthorizationException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthorizationException.java
new file mode 100644
index 0000000..93c97da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/AuthorizationException.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * failed due to an authorization failure. More specifically, this exception is
+ * used for the following error result codes:
+ * <ul>
+ * <li>{@link ResultCode#AUTHORIZATION_DENIED AUTHORIZATION_DENIED} - the
+ * Request failed because the server has not allowed the client to use the
+ * requested authorization.
+ * <li>{@link ResultCode#CONFIDENTIALITY_REQUIRED CONFIDENTIALITY_REQUIRED} -
+ * the Request failed because it requires confidentiality for the communication
+ * between the client and the server.
+ * <li>{@link ResultCode#INSUFFICIENT_ACCESS_RIGHTS INSUFFICIENT_ACCESS_RIGHTS}
+ * - the Request failed because the client does not have sufficient permission
+ * to perform the requested operation.
+ * <li>{@link ResultCode#STRONG_AUTH_REQUIRED STRONG_AUTH_REQUIRED} - the
+ * Request failed because it requires that the client has completed a strong
+ * form of authentication.
+ * </ul>
+ */
+@SuppressWarnings("serial")
+public class AuthorizationException extends ErrorResultException
+{
+  AuthorizationException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequence.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequence.java
new file mode 100755
index 0000000..88ce65e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequence.java
@@ -0,0 +1,326 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+
+/**
+ * A {@code ByteSequence} is a readable sequence of byte values. This interface
+ * provides uniform, read-only access to many different kinds of byte sequences.
+ */
+public interface ByteSequence extends Comparable<ByteSequence>
+{
+
+  /**
+   * Returns a {@link ByteSequenceReader} which can be used to incrementally
+   * read and decode data from this byte sequence.
+   * <p>
+   * <b>NOTE:</b> any concurrent changes to the underlying byte sequence (if
+   * mutable) may cause subsequent reads to overrun and fail.
+   *
+   * @return The {@link ByteSequenceReader} which can be used to incrementally
+   *         read and decode data from this byte sequence.
+   */
+  ByteSequenceReader asReader();
+
+
+
+  /**
+   * Returns the byte value at the specified index.
+   * <p>
+   * An index ranges from zero to {@code length() - 1}. The first byte value of
+   * the sequence is at index zero, the next at index one, and so on, as for
+   * array indexing.
+   *
+   * @param index
+   *          The index of the byte to be returned.
+   * @return The byte value at the specified index.
+   * @throws IndexOutOfBoundsException
+   *           If the index argument is negative or not less than length().
+   */
+  byte byteAt(int index) throws IndexOutOfBoundsException;
+
+
+
+  /**
+   * Compares this byte sequence with the specified byte array sub-sequence for
+   * order. Returns a negative integer, zero, or a positive integer depending on
+   * whether this byte sequence is less than, equal to, or greater than the
+   * specified byte array sub-sequence.
+   *
+   * @param b
+   *          The byte array to compare.
+   * @param offset
+   *          The offset of the sub-sequence in the byte array to be compared;
+   *          must be non-negative and no larger than {@code b.length} .
+   * @param length
+   *          The length of the sub-sequence in the byte array to be compared;
+   *          must be non-negative and no larger than {@code b.length - offset}.
+   * @return A negative integer, zero, or a positive integer depending on
+   *         whether this byte sequence is less than, equal to, or greater than
+   *         the specified byte array sub-sequence.
+   * @throws IndexOutOfBoundsException
+   *           If {@code offset} is negative or if {@code length} is negative or
+   *           if {@code offset + length} is greater than {@code b.length}.
+   */
+  int compareTo(byte[] b, int offset, int length)
+      throws IndexOutOfBoundsException;
+
+
+
+  /**
+   * Compares this byte sequence with the specified byte sequence for order.
+   * Returns a negative integer, zero, or a positive integer depending on
+   * whether this byte sequence is less than, equal to, or greater than the
+   * specified object.
+   *
+   * @param o
+   *          The byte sequence to be compared.
+   * @return A negative integer, zero, or a positive integer depending on
+   *         whether this byte sequence is less than, equal to, or greater than
+   *         the specified object.
+   */
+  int compareTo(ByteSequence o);
+
+
+
+  /**
+   * Copies the contents of this byte sequence to the provided byte array.
+   * <p>
+   * Copying will stop when either the entire content of this sequence has been
+   * copied or if the end of the provided byte array has been reached.
+   * <p>
+   * An invocation of the form:
+   *
+   * <pre>
+   * src.copyTo(b)
+   * </pre>
+   *
+   * Behaves in exactly the same way as the invocation:
+   *
+   * <pre>
+   * src.copyTo(b, 0);
+   * </pre>
+   *
+   * @param b
+   *          The byte array to which bytes are to be copied.
+   * @return The byte array.
+   */
+  byte[] copyTo(byte[] b);
+
+
+
+  /**
+   * Copies the contents of this byte sequence to the specified location in the
+   * provided byte array.
+   * <p>
+   * Copying will stop when either the entire content of this sequence has been
+   * copied or if the end of the provided byte array has been reached.
+   * <p>
+   * An invocation of the form:
+   *
+   * <pre>
+   * src.copyTo(b, offset)
+   * </pre>
+   *
+   * Behaves in exactly the same way as the invocation:
+   *
+   * <pre>
+   * int len = Math.min(src.length(), b.length - offset);
+   * for (int i = 0; i &lt; len; i++)
+   *   b[offset + i] = src.get(i);
+   * </pre>
+   *
+   * Except that it is potentially much more efficient.
+   *
+   * @param b
+   *          The byte array to which bytes are to be copied.
+   * @param offset
+   *          The offset within the array of the first byte to be written; must
+   *          be non-negative and no larger than b.length.
+   * @return The byte array.
+   * @throws IndexOutOfBoundsException
+   *           If {@code offset} is negative.
+   */
+  byte[] copyTo(byte[] b, int offset) throws IndexOutOfBoundsException;
+
+
+
+  /**
+   * Appends the entire contents of this byte sequence to the provided
+   * {@link ByteStringBuilder}.
+   *
+   * @param builder
+   *          The builder to copy to.
+   * @return The builder.
+   */
+  ByteStringBuilder copyTo(ByteStringBuilder builder);
+
+
+
+  /**
+   * Copies the entire contents of this byte sequence to the provided {@code
+   * OutputStream}.
+   *
+   * @param stream
+   *          The {@code OutputStream} to copy to.
+   * @return The {@code OutputStream}.
+   * @throws IOException
+   *           If an error occurs while writing to the {@code OutputStream}.
+   */
+  OutputStream copyTo(OutputStream stream) throws IOException;
+
+
+
+  /**
+   * Indicates whether the provided byte array sub-sequence is equal to this
+   * byte sequence. In order for it to be considered equal, the provided byte
+   * array sub-sequence must contain the same bytes in the same order.
+   *
+   * @param b
+   *          The byte array for which to make the determination.
+   * @param offset
+   *          The offset of the sub-sequence in the byte array to be compared;
+   *          must be non-negative and no larger than {@code b.length} .
+   * @param length
+   *          The length of the sub-sequence in the byte array to be compared;
+   *          must be non-negative and no larger than {@code b.length - offset}.
+   * @return {@code true} if the content of the provided byte array sub-sequence
+   *         is equal to that of this byte sequence, or {@code false} if not.
+   * @throws IndexOutOfBoundsException
+   *           If {@code offset} is negative or if {@code length} is negative or
+   *           if {@code offset + length} is greater than {@code b.length}.
+   */
+  boolean equals(byte[] b, int offset, int length)
+      throws IndexOutOfBoundsException;
+
+
+
+  /**
+   * Indicates whether the provided object is equal to this byte sequence. In
+   * order for it to be considered equal, the provided object must be a byte
+   * sequence containing the same bytes in the same order.
+   *
+   * @param o
+   *          The object for which to make the determination.
+   * @return {@code true} if the provided object is a byte sequence whose
+   *         content is equal to that of this byte sequence, or {@code false} if
+   *         not.
+   */
+  boolean equals(Object o);
+
+
+
+  /**
+   * Returns a hash code for this byte sequence. It will be the sum of all of
+   * the bytes contained in the byte sequence.
+   *
+   * @return A hash code for this byte sequence.
+   */
+  int hashCode();
+
+
+
+  /**
+   * Returns the length of this byte sequence.
+   *
+   * @return The length of this byte sequence.
+   */
+  int length();
+
+
+
+  /**
+   * Returns a new byte sequence that is a subsequence of this byte sequence.
+   * <p>
+   * The subsequence starts with the byte value at the specified {@code start}
+   * index and ends with the byte value at index {@code end - 1}. The length (in
+   * bytes) of the returned sequence is {@code end - start}, so if {@code start
+   * == end} then an empty sequence is returned.
+   * <p>
+   * <b>NOTE:</b> changes to the underlying byte sequence (if mutable) may
+   * render the returned sub-sequence invalid.
+   *
+   * @param start
+   *          The start index, inclusive.
+   * @param end
+   *          The end index, exclusive.
+   * @return The newly created byte subsequence.
+   * @throws IndexOutOfBoundsException
+   *           If {@code start} or {@code end} are negative, if {@code end} is
+   *           greater than {@code length()}, or if {@code start} is greater
+   *           than {@code end}.
+   */
+  ByteSequence subSequence(int start, int end) throws IndexOutOfBoundsException;
+
+
+
+  /**
+   * Returns a byte array containing the bytes in this sequence in the same
+   * order as this sequence. The length of the byte array will be the length of
+   * this sequence.
+   * <p>
+   * An invocation of the form:
+   *
+   * <pre>
+   * src.toByteArray()
+   * </pre>
+   *
+   * Behaves in exactly the same way as the invocation:
+   *
+   * <pre>
+   * src.copyTo(new byte[src.length()]);
+   * </pre>
+   *
+   * @return A byte array consisting of exactly this sequence of bytes.
+   */
+  byte[] toByteArray();
+
+
+
+  /**
+   * Returns the {@link ByteString} representation of this byte sequence.
+   *
+   * @return The {@link ByteString} representation of this byte sequence.
+   */
+  ByteString toByteString();
+
+
+
+  /**
+   * Returns the UTF-8 decoded string representation of this byte sequence. If
+   * UTF-8 decoding fails, the platform's default encoding will be used.
+   *
+   * @return The string representation of this byte sequence.
+   */
+  String toString();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequenceReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequenceReader.java
new file mode 100755
index 0000000..a6f7865
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteSequenceReader.java
@@ -0,0 +1,505 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+/**
+ * An interface for iteratively reading date from a {@link ByteSequence} .
+ * {@code ByteSequenceReader} must be created using the associated {@code
+ * ByteSequence}'s {@code asReader()} method.
+ */
+public final class ByteSequenceReader
+{
+
+  // The current position in the byte sequence.
+  private int pos = 0;
+
+  // The underlying byte sequence.
+  private final ByteSequence sequence;
+
+
+
+  /**
+   * Creates a new byte sequence reader whose source is the provided byte
+   * sequence.
+   * <p>
+   * <b>NOTE:</b> any concurrent changes to the underlying byte sequence (if
+   * mutable) may cause subsequent reads to overrun and fail.
+   * <p>
+   * This constructor is package private: construction must be performed using
+   * {@link ByteSequence#asReader()}.
+   *
+   * @param sequence
+   *          The byte sequence to be read.
+   */
+  ByteSequenceReader(final ByteSequence sequence)
+  {
+    this.sequence = sequence;
+  }
+
+
+
+  /**
+   * Relative get method. Reads the byte at the current position.
+   *
+   * @return The byte at this reader's current position.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; 1}.
+   */
+  public byte get() throws IndexOutOfBoundsException
+  {
+    final byte b = sequence.byteAt(pos);
+    pos++;
+    return b;
+  }
+
+
+
+  /**
+   * Relative bulk get method. This method transfers bytes from this reader into
+   * the given destination array. An invocation of this method of the form:
+   *
+   * <pre>
+   * src.get(b);
+   * </pre>
+   *
+   * Behaves in exactly the same way as the invocation:
+   *
+   * <pre>
+   * src.get(b, 0, b.length);
+   * </pre>
+   *
+   * @param b
+   *          The byte array into which bytes are to be written.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; b.length}.
+   */
+  public void get(final byte[] b) throws IndexOutOfBoundsException
+  {
+    get(b, 0, b.length);
+  }
+
+
+
+  /**
+   * Relative bulk get method. Copies {@code length} bytes from this reader into
+   * the given array, starting at the current position of this reader and at the
+   * given {@code offset} in the array. The position of this reader is then
+   * incremented by {@code length}. In other words, an invocation of this method
+   * of the form:
+   *
+   * <pre>
+   * src.get(b, offset, length);
+   * </pre>
+   *
+   * Has exactly the same effect as the loop:
+   *
+   * <pre>
+   * for (int i = offset; i &lt; offset + length; i++)
+   *   b[i] = src.get();
+   * </pre>
+   *
+   * Except that it first checks that there are sufficient bytes in this buffer
+   * and it is potentially much more efficient.
+   *
+   * @param b
+   *          The byte array into which bytes are to be written.
+   * @param offset
+   *          The offset within the array of the first byte to be written; must
+   *          be non-negative and no larger than {@code b.length}.
+   * @param length
+   *          The number of bytes to be written to the given array; must be
+   *          non-negative and no larger than {@code b.length} .
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; length}.
+   */
+  public void get(final byte[] b, final int offset, final int length)
+      throws IndexOutOfBoundsException
+  {
+    if (offset < 0 || length < 0 || offset + length > b.length
+        || length > remaining())
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    sequence.subSequence(pos, pos + length).copyTo(b, offset);
+    pos += length;
+  }
+
+
+
+  /**
+   * Relative get method for reading a multi-byte BER length. Reads the next one
+   * to five bytes at this reader's current position, composing them into a
+   * integer value and then increments the position by the number of bytes read.
+   *
+   * @return The integer value representing the length at this reader's current
+   *         position.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request.
+   */
+  public int getBERLength() throws IndexOutOfBoundsException
+  {
+    // Make sure we have at least one byte to read.
+    int newPos = pos + 1;
+    if (newPos > sequence.length())
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    int length = sequence.byteAt(pos) & 0x7F;
+    if (length != sequence.byteAt(pos))
+    {
+      // Its a multi-byte length
+      final int numLengthBytes = length;
+      newPos = pos + 1 + numLengthBytes;
+      // Make sure we have the bytes needed
+      if (numLengthBytes > 4 || newPos > sequence.length())
+      {
+        // Shouldn't have more than 4 bytes
+        throw new IndexOutOfBoundsException();
+      }
+
+      length = 0x00;
+      for (int i = pos + 1; i < newPos; i++)
+      {
+        length = length << 8 | sequence.byteAt(i) & 0xFF;
+      }
+    }
+
+    pos = newPos;
+    return length;
+  }
+
+
+
+  /**
+   * Relative bulk get method. Returns a {@link ByteSequence} whose content is
+   * the next {@code length} bytes from this reader, starting at the current
+   * position of this reader. The position of this reader is then incremented by
+   * {@code length}.
+   * <p>
+   * <b>NOTE:</b> The value returned from this method should NEVER be cached as
+   * it prevents the contents of the underlying byte stream from being garbage
+   * collected.
+   *
+   * @param length
+   *          The length of the byte sequence to be returned.
+   * @return The byte sequence whose content is the next {@code length} bytes
+   *         from this reader.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; length}.
+   */
+  public ByteSequence getByteSequence(final int length)
+      throws IndexOutOfBoundsException
+  {
+    final int newPos = pos + length;
+    final ByteSequence subSequence = sequence.subSequence(pos, newPos);
+    pos = newPos;
+    return subSequence;
+  }
+
+
+
+  /**
+   * Relative bulk get method. Returns a {@link ByteString} whose content is the
+   * next {@code length} bytes from this reader, starting at the current
+   * position of this reader. The position of this reader is then incremented by
+   * {@code length}.
+   * <p>
+   * An invocation of this method of the form:
+   *
+   * <pre>
+   * src.getByteString(length);
+   * </pre>
+   *
+   * Has exactly the same effect as:
+   *
+   * <pre>
+   * src.getByteSequence(length).toByteString();
+   * </pre>
+   *
+   * <b>NOTE:</b> The value returned from this method should NEVER be cached as
+   * it prevents the contents of the underlying byte stream from being garbage
+   * collected.
+   *
+   * @param length
+   *          The length of the byte string to be returned.
+   * @return The byte string whose content is the next {@code length} bytes from
+   *         this reader.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; length}.
+   */
+  public ByteString getByteString(final int length)
+      throws IndexOutOfBoundsException
+  {
+    return getByteSequence(length).toByteString();
+  }
+
+
+
+  /**
+   * Relative get method for reading an integer value. Reads the next four bytes
+   * at this reader's current position, composing them into an integer value
+   * according to big-endian byte order, and then increments the position by
+   * four.
+   *
+   * @return The integer value at this reader's current position.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; 4}.
+   */
+  public int getInt() throws IndexOutOfBoundsException
+  {
+    if (remaining() < 4)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    int v = 0;
+    for (int i = 0; i < 4; i++)
+    {
+      v <<= 8;
+      v |= sequence.byteAt(pos++) & 0xFF;
+    }
+
+    return v;
+  }
+
+
+
+  /**
+   * Relative get method for reading a long value. Reads the next eight bytes at
+   * this reader's current position, composing them into a long value according
+   * to big-endian byte order, and then increments the position by eight.
+   *
+   * @return The long value at this reader's current position.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; 8}.
+   */
+  public long getLong() throws IndexOutOfBoundsException
+  {
+    if (remaining() < 8)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    long v = 0;
+    for (int i = 0; i < 8; i++)
+    {
+      v <<= 8;
+      v |= sequence.byteAt(pos++) & 0xFF;
+    }
+
+    return v;
+  }
+
+
+
+  /**
+   * Relative get method for reading an short value. Reads the next 2 bytes at
+   * this reader's current position, composing them into an short value
+   * according to big-endian byte order, and then increments the position by
+   * two.
+   *
+   * @return The integer value at this reader's current position.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; 2}.
+   */
+  public short getShort() throws IndexOutOfBoundsException
+  {
+    if (remaining() < 2)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    short v = 0;
+    for (int i = 0; i < 2; i++)
+    {
+      v <<= 8;
+      v |= sequence.byteAt(pos++) & 0xFF;
+    }
+
+    return v;
+  }
+
+
+
+  /**
+   * Relative get method for reading a UTF-8 encoded string. Reads the next
+   * number of specified bytes at this reader's current position, decoding them
+   * into a string using UTF-8 and then increments the position by the number of
+   * bytes read. If UTF-8 decoding fails, the platform's default encoding will
+   * be used.
+   *
+   * @param length
+   *          The number of bytes to read and decode.
+   * @return The string value at the reader's current position.
+   * @throws IndexOutOfBoundsException
+   *           If there are fewer bytes remaining in this reader than are
+   *           required to satisfy the request, that is, if {@code remaining()
+   *           &lt; length}.
+   */
+  public String getString(final int length) throws IndexOutOfBoundsException
+  {
+    if (remaining() < length)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    final int newPos = pos + length;
+    final String str = sequence.subSequence(pos, pos + length).toString();
+    pos = newPos;
+    return str;
+  }
+
+
+
+  /**
+   * Returns this reader's position.
+   *
+   * @return The position of this reader.
+   */
+  public int position()
+  {
+    return pos;
+  }
+
+
+
+  /**
+   * Sets this reader's position.
+   *
+   * @param pos
+   *          The new position value; must be non-negative and no larger than
+   *          the length of the underlying byte sequence.
+   * @throws IndexOutOfBoundsException
+   *           If the position is negative or larger than the length of the
+   *           underlying byte sequence.
+   */
+  public void position(final int pos) throws IndexOutOfBoundsException
+  {
+    if (pos > sequence.length() || pos < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    this.pos = pos;
+  }
+
+
+
+  /**
+   * Returns the number of bytes between the current position and the end of the
+   * underlying byte sequence.
+   *
+   * @return The number of bytes between the current position and the end of the
+   *         underlying byte sequence.
+   */
+  public int remaining()
+  {
+    return sequence.length() - pos;
+  }
+
+
+
+  /**
+   * Rewinds this reader's position to zero.
+   * <p>
+   * An invocation of this method of the form:
+   *
+   * <pre>
+   * src.rewind();
+   * </pre>
+   *
+   * Has exactly the same effect as:
+   *
+   * <pre>
+   * src.position(0);
+   * </pre>
+   */
+  public void rewind()
+  {
+    position(0);
+  }
+
+
+
+  /**
+   * Skips the given number of bytes. Negative values are allowed.
+   * <p>
+   * An invocation of this method of the form:
+   *
+   * <pre>
+   * src.skip(length);
+   * </pre>
+   *
+   * Has exactly the same effect as:
+   *
+   * <pre>
+   * src.position(position() + length);
+   * </pre>
+   *
+   * @param length
+   *          The number of bytes to skip.
+   * @throws IndexOutOfBoundsException
+   *           If the new position is less than 0 or greater than the length of
+   *           the underlying byte sequence.
+   */
+  public void skip(final int length) throws IndexOutOfBoundsException
+  {
+    position(pos + length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return sequence.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteString.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteString.java
new file mode 100755
index 0000000..31e50ed
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteString.java
@@ -0,0 +1,717 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.logging.Level;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An immutable sequence of bytes backed by a byte array.
+ */
+public final class ByteString implements ByteSequence
+{
+
+  // Singleton empty byte string.
+  private static final ByteString EMPTY = wrap(new byte[0]);
+
+
+
+  /**
+   * Returns an empty byte string.
+   *
+   * @return An empty byte string.
+   */
+  public static ByteString empty()
+  {
+    return EMPTY;
+  }
+
+
+
+  /**
+   * Returns a byte string containing the big-endian encoded bytes of the
+   * provided integer.
+   *
+   * @param i
+   *          The integer to encode.
+   * @return The byte string containing the big-endian encoded bytes of the
+   *         provided integer.
+   */
+  public static ByteString valueOf(int i)
+  {
+    final byte[] bytes = new byte[4];
+    for (int j = 3; j >= 0; j--)
+    {
+      bytes[j] = (byte) (i & 0xFF);
+      i >>>= 8;
+    }
+    return wrap(bytes);
+  }
+
+
+
+  /**
+   * Returns a byte string containing the big-endian encoded bytes of the
+   * provided long.
+   *
+   * @param l
+   *          The long to encode.
+   * @return The byte string containing the big-endian encoded bytes of the
+   *         provided long.
+   */
+  public static ByteString valueOf(long l)
+  {
+    final byte[] bytes = new byte[8];
+    for (int i = 7; i >= 0; i--)
+    {
+      bytes[i] = (byte) (l & 0xFF);
+      l >>>= 8;
+    }
+    return wrap(bytes);
+  }
+
+
+
+  /**
+   * Returns a byte string containing the provided object. If the object is an
+   * instance of {@code ByteSequence} then it is converted to a byte string
+   * using the {@code toByteString()} method. Otherwise a new byte string is
+   * created containing the UTF-8 encoded bytes of the string representation of
+   * the provided object.
+   *
+   * @param o
+   *          The object to use.
+   * @return The byte string containing the provided object.
+   */
+  public static ByteString valueOf(final Object o)
+  {
+    if (o instanceof ByteSequence)
+    {
+      return ((ByteSequence) o).toByteString();
+    }
+    else
+    {
+      return wrap(StaticUtils.getBytes(o.toString()));
+    }
+  }
+
+
+
+  /**
+   * Returns a byte string containing the UTF-8 encoded bytes of the provided
+   * string.
+   *
+   * @param s
+   *          The string to use.
+   * @return The byte string with the encoded bytes of the provided string.
+   */
+  public static ByteString valueOf(final String s)
+  {
+    return wrap(StaticUtils.getBytes(s));
+  }
+
+
+
+  /**
+   * Returns a byte string containing the UTF-8 encoded bytes of the provided
+   * char array.
+   *
+   * @param chars
+   *          The char array to use.
+   * @return A byte string containing the UTF-8 encoded bytes of the provided
+   *         char array.
+   */
+  public static ByteString valueOf(final char[] chars)
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    ByteBuffer buffer = utf8.encode(CharBuffer.wrap(chars));
+    byte[] bytes = new byte[buffer.remaining()];
+    buffer.get(bytes);
+    return wrap(bytes);
+  }
+
+
+
+  /**
+   * Returns a byte string that wraps the provided byte array.
+   * <p>
+   * <b>NOTE:</b> this method takes ownership of the provided byte array and,
+   * therefore, the byte array MUST NOT be altered directly after this method
+   * returns.
+   *
+   * @param b
+   *          The byte array to wrap.
+   * @return The byte string that wraps the given byte array.
+   */
+  public static ByteString wrap(final byte[] b)
+  {
+    return new ByteString(b, 0, b.length);
+  }
+
+
+
+  /**
+   * Returns a byte string that wraps a subsequence of the provided byte array.
+   * <p>
+   * <b>NOTE:</b> this method takes ownership of the provided byte array and,
+   * therefore, the byte array MUST NOT be altered directly after this method
+   * returns.
+   *
+   * @param b
+   *          The byte array to wrap.
+   * @param offset
+   *          The offset of the byte array to be used; must be non-negative and
+   *          no larger than {@code b.length} .
+   * @param length
+   *          The length of the byte array to be used; must be non-negative and
+   *          no larger than {@code b.length - offset}.
+   * @return The byte string that wraps the given byte array.
+   * @throws IndexOutOfBoundsException
+   *           If {@code offset} is negative or if {@code length} is negative or
+   *           if {@code offset + length} is greater than {@code b.length}.
+   */
+  public static ByteString wrap(final byte[] b, final int offset,
+      final int length) throws IndexOutOfBoundsException
+  {
+    checkArrayBounds(b, offset, length);
+    return new ByteString(b, offset, length);
+  }
+
+
+
+  /**
+   * Checks the array bounds of the provided byte array sub-sequence, throwing
+   * an {@code IndexOutOfBoundsException} if they are illegal.
+   *
+   * @param b
+   *          The byte array.
+   * @param offset
+   *          The offset of the byte array to be checked; must be non-negative
+   *          and no larger than {@code b.length}.
+   * @param length
+   *          The length of the byte array to be checked; must be non-negative
+   *          and no larger than {@code b.length - offset}.
+   * @throws IndexOutOfBoundsException
+   *           If {@code offset} is negative or if {@code length} is negative or
+   *           if {@code offset + length} is greater than {@code b.length}.
+   */
+  static void checkArrayBounds(final byte[] b, final int offset,
+      final int length) throws IndexOutOfBoundsException
+  {
+    if (offset < 0 || offset > b.length || length < 0
+        || offset + length > b.length || offset + length < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+  }
+
+
+
+  /**
+   * Compares two byte array sub-sequences and returns a value that indicates
+   * their relative order.
+   *
+   * @param b1
+   *          The byte array containing the first sub-sequence.
+   * @param offset1
+   *          The offset of the first byte array sub-sequence.
+   * @param length1
+   *          The length of the first byte array sub-sequence.
+   * @param b2
+   *          The byte array containing the second sub-sequence.
+   * @param offset2
+   *          The offset of the second byte array sub-sequence.
+   * @param length2
+   *          The length of the second byte array sub-sequence.
+   * @return A negative integer if first byte array sub-sequence should come
+   *         before the second byte array sub-sequence in ascending order, a
+   *         positive integer if the first byte array sub-sequence should come
+   *         after the byte array sub-sequence in ascending order, or zero if
+   *         there is no difference between the two byte array sub-sequences
+   *         with regard to ordering.
+   */
+  static int compareTo(final byte[] b1, final int offset1, final int length1,
+      final byte[] b2, final int offset2, final int length2)
+  {
+    int count = Math.min(length1, length2);
+    int i = offset1;
+    int j = offset2;
+    while (count-- != 0)
+    {
+      final int firstByte = 0xFF & b1[i++];
+      final int secondByte = 0xFF & b2[j++];
+      if (firstByte != secondByte)
+      {
+        return firstByte - secondByte;
+      }
+    }
+    return length1 - length2;
+  }
+
+
+
+  /**
+   * Indicates whether two byte array sub-sequences are equal. In order for them
+   * to be considered equal, they must contain the same bytes in the same order.
+   *
+   * @param b1
+   *          The byte array containing the first sub-sequence.
+   * @param offset1
+   *          The offset of the first byte array sub-sequence.
+   * @param length1
+   *          The length of the first byte array sub-sequence.
+   * @param b2
+   *          The byte array containing the second sub-sequence.
+   * @param offset2
+   *          The offset of the second byte array sub-sequence.
+   * @param length2
+   *          The length of the second byte array sub-sequence.
+   * @return {@code true} if the two byte array sub-sequences have the same
+   *         content, or {@code false} if not.
+   */
+  static boolean equals(final byte[] b1, final int offset1, final int length1,
+      final byte[] b2, final int offset2, final int length2)
+  {
+    if (length1 != length2)
+    {
+      return false;
+    }
+
+    int i = offset1;
+    int j = offset2;
+    int count = length1;
+    while (count-- != 0)
+    {
+      if (b1[i++] != b2[j++])
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+
+
+  /**
+   * Returns a hash code for the provided byte array sub-sequence.
+   *
+   * @param b
+   *          The byte array.
+   * @param offset
+   *          The offset of the byte array sub-sequence.
+   * @param length
+   *          The length of the byte array sub-sequence.
+   * @return A hash code for the provided byte array sub-sequence.
+   */
+  static int hashCode(final byte[] b, final int offset, final int length)
+  {
+    int hashCode = 1;
+    int i = offset;
+    int count = length;
+    while (count-- != 0)
+    {
+      hashCode = 31 * hashCode + b[i++];
+    }
+    return hashCode;
+  }
+
+
+
+  /**
+   * Returns the UTF-8 decoded string representation of the provided byte array
+   * sub-sequence. If UTF-8 decoding fails, the platform's default encoding will
+   * be used.
+   *
+   * @param b
+   *          The byte array.
+   * @param offset
+   *          The offset of the byte array sub-sequence.
+   * @param length
+   *          The length of the byte array sub-sequence.
+   * @return The string representation of the byte array sub-sequence.
+   */
+  static String toString(final byte[] b, final int offset, final int length)
+  {
+    String stringValue;
+    try
+    {
+      stringValue = new String(b, offset, length, "UTF-8");
+    }
+    catch (final Exception e)
+    {
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
+      {
+        StaticUtils.DEBUG_LOG.warning("Unable to decode ByteString "
+            + "bytes as UTF-8 string: " + e.toString());
+      }
+
+      stringValue = new String(b, offset, length);
+    }
+
+    return stringValue;
+  }
+
+
+
+  // These are package private so that compression and crypto
+  // functionality may directly access the fields.
+
+  // The buffer where data is stored.
+  final byte[] buffer;
+
+  // The number of bytes to expose from the buffer.
+  final int length;
+
+  // The start index of the range of bytes to expose through this byte
+  // string.
+  final int offset;
+
+
+
+  /**
+   * Creates a new byte string that wraps a subsequence of the provided byte
+   * array.
+   * <p>
+   * <b>NOTE:</b> this method takes ownership of the provided byte array and,
+   * therefore, the byte array MUST NOT be altered directly after this method
+   * returns.
+   *
+   * @param b
+   *          The byte array to wrap.
+   * @param offset
+   *          The offset of the byte array to be used; must be non-negative and
+   *          no larger than {@code b.length} .
+   * @param length
+   *          The length of the byte array to be used; must be non-negative and
+   *          no larger than {@code b.length - offset}.
+   */
+  private ByteString(final byte[] b, final int offset, final int length)
+  {
+    this.buffer = b;
+    this.offset = offset;
+    this.length = length;
+  }
+
+
+
+  /**
+   * Returns a {@link ByteSequenceReader} which can be used to incrementally
+   * read and decode data from this byte string.
+   *
+   * @return The {@link ByteSequenceReader} which can be used to incrementally
+   *         read and decode data from this byte string.
+   */
+  public ByteSequenceReader asReader()
+  {
+    return new ByteSequenceReader(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte byteAt(final int index) throws IndexOutOfBoundsException
+  {
+    if (index >= length || index < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+    return buffer[offset + index];
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final byte[] b, final int offset, final int length)
+      throws IndexOutOfBoundsException
+  {
+    checkArrayBounds(b, offset, length);
+    return compareTo(this.buffer, this.offset, this.length, b, offset, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final ByteSequence o)
+  {
+    if (this == o)
+    {
+      return 0;
+    }
+    return -o.compareTo(buffer, offset, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(final byte[] b)
+  {
+    copyTo(b, 0);
+    return b;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(final byte[] b, final int offset)
+      throws IndexOutOfBoundsException
+  {
+    if (offset < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+    System.arraycopy(buffer, this.offset, b, offset, Math.min(length, b.length
+        - offset));
+    return b;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteStringBuilder copyTo(final ByteStringBuilder builder)
+  {
+    builder.append(buffer, offset, length);
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public OutputStream copyTo(final OutputStream stream) throws IOException
+  {
+    stream.write(buffer, offset, length);
+    return stream;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean equals(final byte[] b, final int offset, final int length)
+      throws IndexOutOfBoundsException
+  {
+    checkArrayBounds(b, offset, length);
+    return equals(this.buffer, this.offset, this.length, b, offset, length);
+  }
+
+
+
+  /**
+   * Indicates whether the provided object is equal to this byte string. In
+   * order for it to be considered equal, the provided object must be a byte
+   * sequence containing the same bytes in the same order.
+   *
+   * @param o
+   *          The object for which to make the determination.
+   * @return {@code true} if the provided object is a byte sequence whose
+   *         content is equal to that of this byte string, or {@code false} if
+   *         not.
+   */
+  @Override
+  public boolean equals(final Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+    else if (o instanceof ByteSequence)
+    {
+      final ByteSequence other = (ByteSequence) o;
+      return other.equals(buffer, offset, length);
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Returns a hash code for this byte string. It will be the sum of all of the
+   * bytes contained in the byte string.
+   *
+   * @return A hash code for this byte string.
+   */
+  @Override
+  public int hashCode()
+  {
+    return hashCode(buffer, offset, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int length()
+  {
+    return length;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString subSequence(final int start, final int end)
+      throws IndexOutOfBoundsException
+  {
+    if (start < 0 || start > end || end > length)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+    return new ByteString(buffer, offset + start, end - start);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] toByteArray()
+  {
+    return copyTo(new byte[length]);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString toByteString()
+  {
+    return this;
+  }
+
+
+
+  /**
+   * Returns the UTF-8 decoded char array representation of this byte sequence.
+   *
+   * @return The UTF-8 decoded char array representation of this byte sequence.
+   */
+  public char[] toCharArray()
+  {
+    Charset utf8 = Charset.forName("UTF-8");
+    CharBuffer charBuffer = utf8
+        .decode(ByteBuffer.wrap(buffer, offset, length));
+    char[] chars = new char[charBuffer.remaining()];
+    charBuffer.get(chars);
+    return chars;
+  }
+
+
+
+  /**
+   * Returns the integer value represented by the first four bytes of this byte
+   * string in big-endian order.
+   *
+   * @return The integer value represented by the first four bytes of this byte
+   *         string in big-endian order.
+   * @throws IndexOutOfBoundsException
+   *           If this byte string has less than four bytes.
+   */
+  public int toInt() throws IndexOutOfBoundsException
+  {
+    if (length < 4)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    int v = 0;
+    for (int i = 0; i < 4; i++)
+    {
+      v <<= 8;
+      v |= buffer[offset + i] & 0xFF;
+    }
+    return v;
+  }
+
+
+
+  /**
+   * Returns the long value represented by the first eight bytes of this byte
+   * string in big-endian order.
+   *
+   * @return The long value represented by the first eight bytes of this byte
+   *         string in big-endian order.
+   * @throws IndexOutOfBoundsException
+   *           If this byte string has less than eight bytes.
+   */
+  public long toLong() throws IndexOutOfBoundsException
+  {
+    if (length < 8)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    long v = 0;
+    for (int i = 0; i < 8; i++)
+    {
+      v <<= 8;
+      v |= buffer[offset + i] & 0xFF;
+    }
+    return v;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return toString(buffer, offset, length);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteStringBuilder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteStringBuilder.java
new file mode 100755
index 0000000..a66597a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ByteStringBuilder.java
@@ -0,0 +1,1118 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.logging.Level;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * A mutable sequence of bytes backed by a byte array.
+ */
+public final class ByteStringBuilder implements ByteSequence
+{
+
+  /**
+   * A sub-sequence of the parent byte string builder. The sub-sequence will be
+   * robust against all updates to the byte string builder except for
+   * invocations of the method {@code clear()}.
+   */
+  private final class SubSequence implements ByteSequence
+  {
+
+    // The length of the sub-sequence.
+    private final int subLength;
+
+    // The offset of the sub-sequence.
+    private final int subOffset;
+
+
+
+    /**
+     * Creates a new sub-sequence.
+     *
+     * @param offset
+     *          The offset of the sub-sequence.
+     * @param length
+     *          The length of the sub-sequence.
+     */
+    private SubSequence(final int offset, final int length)
+    {
+      this.subOffset = offset;
+      this.subLength = length;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteSequenceReader asReader()
+    {
+      return new ByteSequenceReader(this);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte byteAt(final int index) throws IndexOutOfBoundsException
+    {
+      if (index >= subLength || index < 0)
+      {
+        throw new IndexOutOfBoundsException();
+      }
+
+      // Protect against reallocation: use builder's buffer.
+      return buffer[subOffset + index];
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int compareTo(final byte[] b, final int offset, final int length)
+        throws IndexOutOfBoundsException
+    {
+      ByteString.checkArrayBounds(b, offset, length);
+
+      // Protect against reallocation: use builder's buffer.
+      return ByteString.compareTo(buffer, subOffset, subLength, b, offset,
+          length);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int compareTo(final ByteSequence o)
+    {
+      if (this == o)
+      {
+        return 0;
+      }
+
+      // Protect against reallocation: use builder's buffer.
+      return -o.compareTo(buffer, subOffset, subLength);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] copyTo(final byte[] b)
+    {
+      copyTo(b, 0);
+      return b;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] copyTo(final byte[] b, final int offset)
+        throws IndexOutOfBoundsException
+    {
+      if (offset < 0)
+      {
+        throw new IndexOutOfBoundsException();
+      }
+
+      // Protect against reallocation: use builder's buffer.
+      System.arraycopy(buffer, subOffset, b, offset, Math.min(subLength,
+          b.length - offset));
+      return b;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteStringBuilder copyTo(final ByteStringBuilder builder)
+    {
+      // Protect against reallocation: use builder's buffer.
+      return builder.append(buffer, subOffset, subLength);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public OutputStream copyTo(final OutputStream stream) throws IOException
+    {
+      // Protect against reallocation: use builder's buffer.
+      stream.write(buffer, subOffset, subLength);
+      return stream;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(final byte[] b, final int offset, final int length)
+        throws IndexOutOfBoundsException
+    {
+      ByteString.checkArrayBounds(b, offset, length);
+
+      // Protect against reallocation: use builder's buffer.
+      return ByteString.equals(buffer, subOffset, subLength, b, offset, length);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(final Object o)
+    {
+      if (this == o)
+      {
+        return true;
+      }
+      else if (o instanceof ByteSequence)
+      {
+        final ByteSequence other = (ByteSequence) o;
+
+        // Protect against reallocation: use builder's buffer.
+        return other.equals(buffer, subOffset, subLength);
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+      // Protect against reallocation: use builder's buffer.
+      return ByteString.hashCode(buffer, subOffset, subLength);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int length()
+    {
+      return subLength;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteSequence subSequence(final int start, final int end)
+        throws IndexOutOfBoundsException
+    {
+      if (start < 0 || start > end || end > subLength)
+      {
+        throw new IndexOutOfBoundsException();
+      }
+
+      return new SubSequence(subOffset + start, end - start);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] toByteArray()
+    {
+      return copyTo(new byte[subLength]);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteString toByteString()
+    {
+      // Protect against reallocation: use builder's buffer.
+      final byte[] b = new byte[subLength];
+      System.arraycopy(buffer, subOffset, b, 0, subLength);
+      return ByteString.wrap(b);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+      // Protect against reallocation: use builder's buffer.
+      return ByteString.toString(buffer, subOffset, subLength);
+    }
+  }
+
+
+
+  // These are package private so that compression and crypto
+  // functionality may directly access the fields.
+
+  // The buffer where data is stored.
+  byte[] buffer;
+
+  // The number of bytes to expose from the buffer.
+  int length;
+
+
+
+  /**
+   * Creates a new byte string builder with an initial capacity of 32 bytes.
+   */
+  public ByteStringBuilder()
+  {
+    // Initially create a 32 byte buffer.
+    this(32);
+  }
+
+
+
+  /**
+   * Creates a new byte string builder with the specified initial capacity.
+   *
+   * @param capacity
+   *          The initial capacity.
+   * @throws IllegalArgumentException
+   *           If the {@code capacity} is negative.
+   */
+  public ByteStringBuilder(final int capacity) throws IllegalArgumentException
+  {
+    if (capacity < 0)
+    {
+      throw new IllegalArgumentException();
+    }
+
+    this.buffer = new byte[capacity];
+    this.length = 0;
+  }
+
+
+
+  /**
+   * Appends the provided byte to this byte string builder.
+   *
+   * @param b
+   *          The byte to be appended to this byte string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(final byte b)
+  {
+    ensureAdditionalCapacity(1);
+    buffer[length++] = b;
+    return this;
+  }
+
+
+
+  /**
+   * Appends the provided byte array to this byte string builder.
+   * <p>
+   * An invocation of the form:
+   *
+   * <pre>
+   * src.append(b)
+   * </pre>
+   *
+   * Behaves in exactly the same way as the invocation:
+   *
+   * <pre>
+   * src.append(b, 0, b.length);
+   * </pre>
+   *
+   * @param b
+   *          The byte array to be appended to this byte string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(final byte[] b)
+  {
+    return append(b, 0, b.length);
+  }
+
+
+
+  /**
+   * Appends the provided byte array to this byte string builder.
+   *
+   * @param b
+   *          The byte array to be appended to this byte string builder.
+   * @param offset
+   *          The offset of the byte array to be used; must be non-negative and
+   *          no larger than {@code b.length} .
+   * @param length
+   *          The length of the byte array to be used; must be non-negative and
+   *          no larger than {@code b.length - offset}.
+   * @return This byte string builder.
+   * @throws IndexOutOfBoundsException
+   *           If {@code offset} is negative or if {@code length} is negative or
+   *           if {@code offset + length} is greater than {@code b.length}.
+   */
+  public ByteStringBuilder append(final byte[] b, final int offset,
+      final int length) throws IndexOutOfBoundsException
+  {
+    ByteString.checkArrayBounds(b, offset, length);
+
+    if (length != 0)
+    {
+      ensureAdditionalCapacity(length);
+      System.arraycopy(b, offset, buffer, this.length, length);
+      this.length += length;
+    }
+
+    return this;
+  }
+
+
+
+  /**
+   * Appends the provided {@code ByteBuffer} to this byte string builder.
+   *
+   * @param buffer
+   *          The byte buffer to be appended to this byte string builder.
+   * @param length
+   *          The number of bytes to be appended from {@code buffer}.
+   * @return This byte string builder.
+   * @throws IndexOutOfBoundsException
+   *           If {@code length} is less than zero or greater than {@code
+   *           buffer.remaining()}.
+   */
+  public ByteStringBuilder append(final ByteBuffer buffer, final int length)
+      throws IndexOutOfBoundsException
+  {
+    if (length < 0 || length > buffer.remaining())
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    if (length != 0)
+    {
+      ensureAdditionalCapacity(length);
+      buffer.get(this.buffer, this.length, length);
+      this.length += length;
+    }
+
+    return this;
+  }
+
+
+
+  /**
+   * Appends the provided {@link ByteSequence} to this byte string builder.
+   *
+   * @param bytes
+   *          The byte sequence to be appended to this byte string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(final ByteSequence bytes)
+  {
+    return bytes.copyTo(this);
+  }
+
+
+
+  /**
+   * Appends the provided {@link ByteSequenceReader} to this byte string
+   * builder.
+   *
+   * @param reader
+   *          The byte sequence reader to be appended to this byte string
+   *          builder.
+   * @param length
+   *          The number of bytes to be appended from {@code reader}.
+   * @return This byte string builder.
+   * @throws IndexOutOfBoundsException
+   *           If {@code length} is less than zero or greater than {@code
+   *           reader.remaining()}.
+   */
+  public ByteStringBuilder append(final ByteSequenceReader reader,
+      final int length) throws IndexOutOfBoundsException
+  {
+    if (length < 0 || length > reader.remaining())
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    if (length != 0)
+    {
+      ensureAdditionalCapacity(length);
+      reader.get(buffer, this.length, length);
+      this.length += length;
+    }
+
+    return this;
+  }
+
+
+
+  /**
+   * Appends the provided {@code InputStream} to this byte string builder.
+   *
+   * @param stream
+   *          The input stream to be appended to this byte string builder.
+   * @param length
+   *          The maximum number of bytes to be appended from {@code buffer}.
+   * @return The number of bytes read from the input stream, or {@code -1} if
+   *         the end of the input stream has been reached.
+   * @throws IndexOutOfBoundsException
+   *           If {@code length} is less than zero.
+   * @throws IOException
+   *           If an I/O error occurs.
+   */
+  public int append(final InputStream stream, final int length)
+      throws IndexOutOfBoundsException, IOException
+  {
+    if (length < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    ensureAdditionalCapacity(length);
+    final int bytesRead = stream.read(buffer, this.length, length);
+    if (bytesRead > 0)
+    {
+      this.length += bytesRead;
+    }
+
+    return bytesRead;
+  }
+
+
+
+  /**
+   * Appends the big-endian encoded bytes of the provided integer to this byte
+   * string builder.
+   *
+   * @param i
+   *          The integer whose big-endian encoding is to be appended to this
+   *          byte string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(int i)
+  {
+    ensureAdditionalCapacity(4);
+    for (int j = length + 3; j >= length; j--)
+    {
+      buffer[j] = (byte) (i & 0xFF);
+      i >>>= 8;
+    }
+    length += 4;
+    return this;
+  }
+
+
+
+  /**
+   * Appends the big-endian encoded bytes of the provided long to this byte
+   * string builder.
+   *
+   * @param l
+   *          The long whose big-endian encoding is to be appended to this byte
+   *          string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(long l)
+  {
+    ensureAdditionalCapacity(8);
+    for (int i = length + 7; i >= length; i--)
+    {
+      buffer[i] = (byte) (l & 0xFF);
+      l >>>= 8;
+    }
+    length += 8;
+    return this;
+  }
+
+
+
+  /**
+   * Appends the provided object to this byte string builder. If the object is
+   * an instance of {@code ByteSequence} then its contents will be appended
+   * directly to this byte string builder using the {@code append(ByteSequence)}
+   * method. Otherwise the string representation of the object will be appended
+   * using the {@code append(String)} method.
+   *
+   * @param o
+   *          The object to be appended to this byte string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(final Object o)
+  {
+    if (o == null)
+    {
+      return this;
+    }
+    else if (o instanceof ByteSequence)
+    {
+      return append((ByteSequence) o);
+    }
+    else
+    {
+      return append(o.toString());
+    }
+  }
+
+
+
+  /**
+   * Appends the big-endian encoded bytes of the provided short to this byte
+   * string builder.
+   *
+   * @param i
+   *          The short whose big-endian encoding is to be appended to this byte
+   *          string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(short i)
+  {
+    ensureAdditionalCapacity(2);
+    for (int j = length + 1; j >= length; j--)
+    {
+      buffer[j] = (byte) (i & 0xFF);
+      i >>>= 8;
+    }
+    length += 2;
+    return this;
+  }
+
+
+
+  /**
+   * Appends the UTF-8 encoded bytes of the provided string to this byte string
+   * builder.
+   *
+   * @param s
+   *          The string whose UTF-8 encoding is to be appended to this byte
+   *          string builder.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder append(final String s)
+  {
+    if (s == null)
+    {
+      return this;
+    }
+
+    // Assume that each char is 1 byte
+    final int len = s.length();
+    ensureAdditionalCapacity(len);
+
+    for (int i = 0; i < len; i++)
+    {
+      final char c = s.charAt(i);
+      final byte b = (byte) (c & 0x0000007F);
+
+      if (c == b)
+      {
+        buffer[this.length + i] = b;
+      }
+      else
+      {
+        // There is a multi-byte char. Defer to JDK
+        try
+        {
+          return append(s.getBytes("UTF-8"));
+        }
+        catch (final Exception e)
+        {
+          if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
+          {
+            StaticUtils.DEBUG_LOG.warning("Unable to encode String "
+                + "to UTF-8 bytes: " + e.toString());
+          }
+
+          return append(s.getBytes());
+        }
+      }
+    }
+
+    // The 1 byte char assumption was correct
+    this.length += len;
+    return this;
+  }
+
+
+
+  /**
+   * Appends the ASN.1 BER length encoding representation of the provided
+   * integer to this byte string builder.
+   *
+   * @param length
+   *          The value to encode using the BER length encoding rules.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder appendBERLength(final int length)
+  {
+    if ((length & 0x0000007F) == length)
+    {
+      ensureAdditionalCapacity(1);
+
+      buffer[this.length++] = (byte) (length & 0xFF);
+    }
+    else if ((length & 0x000000FF) == length)
+    {
+      ensureAdditionalCapacity(2);
+
+      buffer[this.length++] = (byte) 0x81;
+      buffer[this.length++] = (byte) (length & 0xFF);
+    }
+    else if ((length & 0x0000FFFF) == length)
+    {
+      ensureAdditionalCapacity(3);
+
+      buffer[this.length++] = (byte) 0x82;
+      buffer[this.length++] = (byte) (length >> 8 & 0xFF);
+      buffer[this.length++] = (byte) (length & 0xFF);
+    }
+    else if ((length & 0x00FFFFFF) == length)
+    {
+      ensureAdditionalCapacity(4);
+
+      buffer[this.length++] = (byte) 0x83;
+      buffer[this.length++] = (byte) (length >> 16 & 0xFF);
+      buffer[this.length++] = (byte) (length >> 8 & 0xFF);
+      buffer[this.length++] = (byte) (length & 0xFF);
+    }
+    else
+    {
+      ensureAdditionalCapacity(5);
+
+      buffer[this.length++] = (byte) 0x84;
+      buffer[this.length++] = (byte) (length >> 24 & 0xFF);
+      buffer[this.length++] = (byte) (length >> 16 & 0xFF);
+      buffer[this.length++] = (byte) (length >> 8 & 0xFF);
+      buffer[this.length++] = (byte) (length & 0xFF);
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Returns a {@link ByteSequenceReader} which can be used to incrementally
+   * read and decode data from this byte string builder.
+   * <p>
+   * <b>NOTE:</b> all concurrent updates to this byte string builder are
+   * supported with the exception of {@link #clear()}. Any invocations of
+   * {@link #clear()} must be accompanied by a subsequent call to {@code
+   * ByteSequenceReader.rewind()}.
+   *
+   * @return The {@link ByteSequenceReader} which can be used to incrementally
+   *         read and decode data from this byte string builder.
+   * @see #clear()
+   */
+  public ByteSequenceReader asReader()
+  {
+    return new ByteSequenceReader(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte byteAt(final int index) throws IndexOutOfBoundsException
+  {
+    if (index >= length || index < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+    return buffer[index];
+  }
+
+
+
+  /**
+   * Sets the length of this byte string builder to zero.
+   * <p>
+   * <b>NOTE:</b> if this method is called, then {@code
+   * ByteSequenceReader.rewind()} must also be called on any associated byte
+   * sequence readers in order for them to remain valid.
+   *
+   * @return This byte string builder.
+   * @see #asReader()
+   */
+  public ByteStringBuilder clear()
+  {
+    length = 0;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final byte[] b, final int offset, final int length)
+      throws IndexOutOfBoundsException
+  {
+    ByteString.checkArrayBounds(b, offset, length);
+    return ByteString.compareTo(this.buffer, 0, this.length, b, offset, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final ByteSequence o)
+  {
+    if (this == o)
+    {
+      return 0;
+    }
+    return -o.compareTo(buffer, 0, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(final byte[] b)
+  {
+    copyTo(b, 0);
+    return b;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] copyTo(final byte[] b, final int offset)
+      throws IndexOutOfBoundsException
+  {
+    if (offset < 0)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+    System.arraycopy(buffer, 0, b, offset, Math.min(length, b.length - offset));
+    return b;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteStringBuilder copyTo(final ByteStringBuilder builder)
+  {
+    builder.append(buffer, 0, length);
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public OutputStream copyTo(final OutputStream stream) throws IOException
+  {
+    stream.write(buffer, 0, length);
+    return stream;
+  }
+
+
+
+  /**
+   * Ensures that the specified number of additional bytes will fit in this byte
+   * string builder and resizes it if necessary.
+   *
+   * @param size
+   *          The number of additional bytes.
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder ensureAdditionalCapacity(final int size)
+  {
+    final int newCount = this.length + size;
+    if (newCount > buffer.length)
+    {
+      final byte[] newbuffer = new byte[Math.max(buffer.length << 1, newCount)];
+      System.arraycopy(buffer, 0, newbuffer, 0, buffer.length);
+      buffer = newbuffer;
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean equals(final byte[] b, final int offset, final int length)
+      throws IndexOutOfBoundsException
+  {
+    ByteString.checkArrayBounds(b, offset, length);
+    return ByteString.equals(this.buffer, 0, this.length, b, offset, length);
+  }
+
+
+
+  /**
+   * Indicates whether the provided object is equal to this byte string builder.
+   * In order for it to be considered equal, the provided object must be a byte
+   * sequence containing the same bytes in the same order.
+   *
+   * @param o
+   *          The object for which to make the determination.
+   * @return {@code true} if the provided object is a byte sequence whose
+   *         content is equal to that of this byte string builder, or {@code
+   *         false} if not.
+   */
+  @Override
+  public boolean equals(final Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+    else if (o instanceof ByteSequence)
+    {
+      final ByteSequence other = (ByteSequence) o;
+      return other.equals(buffer, 0, length);
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Returns the byte array that backs this byte string builder. Modifications
+   * to this byte string builder's content may cause the returned array's
+   * content to be modified, and vice versa.
+   * <p>
+   * Note that the length of the returned array is only guaranteed to be the
+   * same as the length of this byte string builder immediately after a call to
+   * {@link #trimToSize()}.
+   * <p>
+   * In addition, subsequent modifications to this byte string builder may cause
+   * the backing byte array to be reallocated thus decoupling the returned byte
+   * array from this byte string builder.
+   *
+   * @return The byte array that backs this byte string builder.
+   */
+  public byte[] getBackingArray()
+  {
+    return buffer;
+  }
+
+
+
+  /**
+   * Returns a hash code for this byte string builder. It will be the sum of all
+   * of the bytes contained in the byte string builder.
+   * <p>
+   * <b>NOTE:</b> subsequent changes to this byte string builder will invalidate
+   * the returned hash code.
+   *
+   * @return A hash code for this byte string builder.
+   */
+  @Override
+  public int hashCode()
+  {
+    return ByteString.hashCode(buffer, 0, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int length()
+  {
+    return length;
+  }
+
+
+
+  /**
+   * Sets the length of this byte string builder.
+   * <p>
+   * If the <code>newLength</code> argument is less than the current length, the
+   * length is changed to the specified length.
+   * <p>
+   * If the <code>newLength</code> argument is greater than or equal to the
+   * current length, then the capacity is increased and sufficient null bytes
+   * are appended so that length becomes the <code>newLength</code> argument.
+   * <p>
+   * The <code>newLength</code> argument must be greater than or equal to
+   * <code>0</code>.
+   *
+   * @param newLength
+   *          The new length.
+   * @return This byte string builder.
+   * @throws IndexOutOfBoundsException
+   *           If the <code>newLength</code> argument is negative.
+   */
+  public ByteStringBuilder setLength(final int newLength)
+      throws IndexOutOfBoundsException
+  {
+    if (newLength < 0)
+    {
+      throw new IndexOutOfBoundsException("Negative newLength: " + newLength);
+    }
+
+    if (newLength > length)
+    {
+      ensureAdditionalCapacity(newLength - length);
+
+      // Pad with zeros.
+      for (int i = length; i < newLength; i++)
+      {
+        buffer[i] = 0;
+      }
+    }
+    length = newLength;
+
+    return this;
+  }
+
+
+
+  /**
+   * Returns a new byte sequence that is a subsequence of this byte sequence.
+   * <p>
+   * The subsequence starts with the byte value at the specified {@code start}
+   * index and ends with the byte value at index {@code end - 1}. The length (in
+   * bytes) of the returned sequence is {@code end - start}, so if {@code start
+   * == end} then an empty sequence is returned.
+   * <p>
+   * <b>NOTE:</b> the returned sub-sequence will be robust against all updates
+   * to the byte string builder except for invocations of the method
+   * {@link #clear()}. If a permanent immutable byte sequence is required then
+   * callers should invoke {@code toByteString()} on the returned byte sequence.
+   *
+   * @param start
+   *          The start index, inclusive.
+   * @param end
+   *          The end index, exclusive.
+   * @return The newly created byte subsequence.
+   * @throws IndexOutOfBoundsException
+   *           If {@code start} or {@code end} are negative, if {@code end} is
+   *           greater than {@code length()}, or if {@code start} is greater
+   *           than {@code end}.
+   */
+  public ByteSequence subSequence(final int start, final int end)
+      throws IndexOutOfBoundsException
+  {
+    if (start < 0 || start > end || end > length)
+    {
+      throw new IndexOutOfBoundsException();
+    }
+
+    return new SubSequence(start, end - start);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte[] toByteArray()
+  {
+    return copyTo(new byte[length]);
+  }
+
+
+
+  /**
+   * Returns the {@link ByteString} representation of this byte string builder.
+   * Subsequent changes to this byte string builder will not modify the returned
+   * {@link ByteString}.
+   *
+   * @return The {@link ByteString} representation of this byte sequence.
+   */
+  public ByteString toByteString()
+  {
+    final byte[] b = new byte[length];
+    System.arraycopy(buffer, 0, b, 0, length);
+    return ByteString.wrap(b);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return ByteString.toString(buffer, 0, length);
+  }
+
+
+
+  /**
+   * Attempts to reduce storage used for this byte string builder. If the buffer
+   * is larger than necessary to hold its current sequence of bytes, then it may
+   * be resized to become more space efficient.
+   *
+   * @return This byte string builder.
+   */
+  public ByteStringBuilder trimToSize()
+  {
+    if (buffer.length > length)
+    {
+      final byte[] newBuffer = new byte[length];
+      System.arraycopy(buffer, 0, newBuffer, 0, length);
+      buffer = newBuffer;
+    }
+    return this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/CancelledResultException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/CancelledResultException.java
new file mode 100644
index 0000000..8abe3d5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/CancelledResultException.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * was cancelled. More specifically, this exception is used for the following
+ * error result codes:
+ * <ul>
+ * <li>{@link ResultCode#CANCELLED CANCELLED} - the requested operation was
+ * cancelled.
+ * <li>{@link ResultCode#CLIENT_SIDE_USER_CANCELLED CLIENT_SIDE_USER_CANCELLED}
+ * - the requested operation was cancelled by the user.
+ * </ul>
+ */
+@SuppressWarnings("serial")
+public class CancelledResultException extends ErrorResultException
+{
+  CancelledResultException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConditionResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConditionResult.java
new file mode 100644
index 0000000..1a67178
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConditionResult.java
@@ -0,0 +1,298 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * The result of a tri-state logical expression. Condition results are used to
+ * represent the result of a conditional evaluation that can yield three
+ * possible values: {@code FALSE} (i.e. "no"), {@code TRUE} (i.e. "yes"), or
+ * {@code UNDEFINED} (i.e. "maybe"). A result of {@code UNDEFINED} indicates
+ * that further investigation may be required.
+ */
+public enum ConditionResult
+{
+  /**
+   * Indicates that the condition evaluated to {@code false}.
+   */
+  FALSE("false"),
+
+  /**
+   * Indicates that the condition could not be evaluated and its result is
+   * undefined.
+   */
+  UNDEFINED("undefined"),
+
+  /**
+   * Indicates that the condition evaluated to {@code true}.
+   */
+  TRUE("true");
+
+  // Boolean -> ConditionResult map.
+  private static final boolean[] BOOLEAN_MAP = { false, false, true };
+
+  // AND truth table.
+  private static final ConditionResult[][] LOGICAL_AND = {
+      { FALSE, FALSE, FALSE }, { FALSE, UNDEFINED, UNDEFINED },
+      { FALSE, UNDEFINED, TRUE }, };
+
+  // NOT truth table.
+  private static final ConditionResult[] LOGICAL_NOT = { TRUE, UNDEFINED, FALSE };
+
+  // OR truth table.
+  private static final ConditionResult[][] LOGICAL_OR = {
+      { FALSE, UNDEFINED, TRUE }, { UNDEFINED, UNDEFINED, TRUE },
+      { TRUE, TRUE, TRUE }, };
+
+
+
+  /**
+   * Returns the logical AND of zero condition results, which is always {@code
+   * TRUE}.
+   *
+   * @return The logical OR of zero condition results, which is always {@code
+   *         TRUE}.
+   */
+  public static ConditionResult and()
+  {
+    return TRUE;
+  }
+
+
+
+  /**
+   * Returns the logical AND of the provided condition result, which is always
+   * {@code r}.
+   *
+   * @param r
+   *          The condition result.
+   * @return The logical AND of the provided condition result, which is always
+   *         {@code r}.
+   */
+  public static ConditionResult and(final ConditionResult r)
+  {
+    return r;
+  }
+
+
+
+  /**
+   * Returns the logical AND of the provided condition results, which is {@code
+   * TRUE} if all of the provided condition results are {@code TRUE}, {@code
+   * FALSE} if at least one of them is {@code FALSE}, and {@code UNDEFINED}
+   * otherwise. Note that {@code TRUE} is returned if the provided list of
+   * results is empty.
+   *
+   * @param results
+   *          The condition results to be compared.
+   * @return The logical AND of the provided condition results.
+   */
+  public static ConditionResult and(final ConditionResult... results)
+  {
+    ConditionResult finalResult = TRUE;
+    for (final ConditionResult result : results)
+    {
+      finalResult = and(finalResult, result);
+      if (finalResult == FALSE)
+      {
+        break;
+      }
+    }
+    return finalResult;
+  }
+
+
+
+  /**
+   * Returns the logical AND of the provided condition results, which is {@code
+   * TRUE} if both of the provided condition results are {@code TRUE}, {@code
+   * FALSE} if at least one of them is {@code FALSE} , and {@code UNDEFINED}
+   * otherwise.
+   *
+   * @param r1
+   *          The first condition result to be compared.
+   * @param r2
+   *          The second condition result to be compared.
+   * @return The logical AND of the provided condition results.
+   */
+  public static ConditionResult and(final ConditionResult r1,
+      final ConditionResult r2)
+  {
+    return LOGICAL_AND[r1.ordinal()][r2.ordinal()];
+  }
+
+
+
+  /**
+   * Returns the logical NOT of the provided condition result, which is {@code
+   * TRUE} if the provided condition result is {@code FALSE}, {@code TRUE} if it
+   * is {@code FALSE}, and {@code UNDEFINED} otherwise.
+   *
+   * @param r
+   *          The condition result to invert.
+   * @return The logical NOT of the provided condition result.
+   */
+  public static ConditionResult not(final ConditionResult r)
+  {
+    return LOGICAL_NOT[r.ordinal()];
+  }
+
+
+
+  /**
+   * Returns the logical OR of zero condition results, which is always {@code
+   * FALSE}.
+   *
+   * @return The logical OR of zero condition results, which is always {@code
+   *         FALSE}.
+   */
+  public static ConditionResult or()
+  {
+    return FALSE;
+  }
+
+
+
+  /**
+   * Returns the logical OR of the provided condition result, which is always
+   * {@code r}.
+   *
+   * @param r
+   *          The condition result.
+   * @return The logical OR of the provided condition result, which is always
+   *         {@code r}.
+   */
+  public static ConditionResult or(final ConditionResult r)
+  {
+    return r;
+  }
+
+
+
+  /**
+   * Returns the logical OR of the provided condition results, which is {@code
+   * FALSE} if all of the provided condition results are {@code FALSE}, {@code
+   * TRUE} if at least one of them is {@code TRUE}, and {@code UNDEFINED}
+   * otherwise. Note that {@code FALSE} is returned if the provided list of
+   * results is empty.
+   *
+   * @param results
+   *          The condition results to be compared.
+   * @return The logical OR of the provided condition results.
+   */
+  public static ConditionResult or(final ConditionResult... results)
+  {
+    ConditionResult finalResult = FALSE;
+    for (final ConditionResult result : results)
+    {
+      finalResult = and(finalResult, result);
+      if (finalResult == TRUE)
+      {
+        break;
+      }
+    }
+    return finalResult;
+  }
+
+
+
+  /**
+   * Returns the logical OR of the provided condition results, which is {@code
+   * FALSE} if both of the provided condition results are {@code FALSE}, {@code
+   * TRUE} if at least one of them is {@code TRUE} , and {@code UNDEFINED}
+   * otherwise.
+   *
+   * @param r1
+   *          The first condition result to be compared.
+   * @param r2
+   *          The second condition result to be compared.
+   * @return The logical OR of the provided condition results.
+   */
+  public static ConditionResult or(final ConditionResult r1,
+      final ConditionResult r2)
+  {
+    return LOGICAL_OR[r1.ordinal()][r2.ordinal()];
+  }
+
+
+
+  /**
+   * Returns the condition result which is equivalent to the provided boolean
+   * value.
+   *
+   * @param b
+   *          The boolean value.
+   * @return {@code TRUE} if {@code b} was {@code true}, otherwise {@code FALSE}
+   *         .
+   */
+  public static ConditionResult valueOf(final boolean b)
+  {
+    return b ? TRUE : FALSE;
+  }
+
+
+
+  // The human-readable name for this result.
+  private final String resultName;
+
+
+
+  // Prevent instantiation.
+  private ConditionResult(final String resultName)
+  {
+    this.resultName = resultName;
+  }
+
+
+
+  /**
+   * Converts this condition result to a boolean value. {@code FALSE} and
+   * {@code UNDEFINED} are both converted to {@code false}, and {@code TRUE} is
+   * converted to {@code true}.
+   *
+   * @return The boolean equivalent of this condition result.
+   */
+  public boolean toBoolean()
+  {
+    return BOOLEAN_MAP[ordinal()];
+  }
+
+
+
+  /**
+   * Returns the string representation of this condition result.
+   *
+   * @return The string representation of his condition result.
+   */
+  @Override
+  public String toString()
+  {
+    return resultName;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connection.java
new file mode 100644
index 0000000..542be35
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connection.java
@@ -0,0 +1,1260 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.Closeable;
+import java.util.Collection;
+import java.util.concurrent.BlockingQueue;
+
+import org.opends.sdk.ldif.ConnectionEntryReader;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * A synchronous connection with a Directory Server over which read and update
+ * operations may be performed. See RFC 4511 for the LDAPv3 protocol
+ * specification and more information about the types of operations defined in
+ * LDAP.
+ * <p>
+ * <h3>Operation processing</h3>
+ * <p>
+ * All operations are performed synchronously and return an appropriate
+ * {@link Result} representing the final status of the operation. Operation
+ * failures, for whatever reason, are signalled using an
+ * {@link ErrorResultException}.
+ * <p>
+ * <h3>Closing connections</h3>
+ * <p>
+ * Applications must ensure that a connection is closed by calling
+ * {@link #close()} even if a fatal error occurs on the connection. Once a
+ * connection has been closed by the client application, any attempts to
+ * continue to use the connection will result in an
+ * {@link IllegalStateException} being thrown. Note that, if a fatal error is
+ * encountered on the connection, then the application can continue to use the
+ * connection. In this case all requests subsequent to the failure will fail
+ * with an appropriate {@link ErrorResultException} when their result is
+ * retrieved.
+ * <p>
+ * <h3>Event notification</h3>
+ * <p>
+ * Applications can choose to be notified when a connection is closed by the
+ * application, receives an unsolicited notification, or experiences a fatal
+ * error by registering a {@link ConnectionEventListener} with the connection
+ * using the {@link #addConnectionEventListener} method.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight
+ *      Directory Access Protocol (LDAP): The Protocol </a>
+ */
+public interface Connection extends Closeable
+{
+
+  /**
+   * Adds an entry to the Directory Server using the provided add request.
+   *
+   * @param request
+   *          The add request.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support add operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  Result add(AddRequest request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Adds the provided entry to the Directory Server.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * AddRequest request = new AddRequest(entry);
+   * connection.add(request);
+   * </pre>
+   *
+   * @param entry
+   *          The entry to be added.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support add operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  Result add(Entry entry) throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Adds an entry to the Directory Server using the provided lines of LDIF.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * AddRequest request = new AddRequest(ldifLines);
+   * connection.add(request);
+   * </pre>
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing the an LDIF add change record or an LDIF
+   *          entry record.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support add operations.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  Result add(String... ldifLines) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      LocalizedIllegalArgumentException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Registers the provided connection event listener so that it will be
+   * notified when this connection is closed by the application, receives an
+   * unsolicited notification, or experiences a fatal error.
+   *
+   * @param listener
+   *          The listener which wants to be notified when events occur on this
+   *          connection.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code listener} was {@code null}.
+   */
+  void addConnectionEventListener(ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Authenticates to the Directory Server using the provided bind request.
+   *
+   * @param request
+   *          The bind request.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support bind operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  BindResult bind(BindRequest request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Authenticates to the Directory Server using simple authentication and the
+   * provided user name and password.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * BindRequest request = new SimpleBindRequest(name, password);
+   * connection.bind(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the Directory object that the client
+   *          wishes to bind as, which may be empty.
+   * @param password
+   *          The password of the Directory object that the client wishes to
+   *          bind as, which may be empty.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support bind operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code name} or {@code password} was {@code null}.
+   */
+  BindResult bind(String name, char[] password) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Releases any resources associated with this connection. For physical
+   * connections to a Directory Server this will mean that an unbind request is
+   * sent and the underlying socket is closed.
+   * <p>
+   * Other connection implementations may behave differently, and may choose not
+   * to send an unbind request if its use is inappropriate (for example a pooled
+   * connection will be released and returned to its connection pool without
+   * ever issuing an unbind request).
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * UnbindRequest request = new UnbindRequest();
+   * connection.close(request);
+   * </pre>
+   *
+   * Calling {@code close} on a connection that is already closed has no effect.
+   */
+  void close();
+
+
+
+  /**
+   * Releases any resources associated with this connection. For physical
+   * connections to a Directory Server this will mean that the provided unbind
+   * request is sent and the underlying socket is closed.
+   * <p>
+   * Other connection implementations may behave differently, and may choose to
+   * ignore the provided unbind request if its use is inappropriate (for example
+   * a pooled connection will be released and returned to its connection pool
+   * without ever issuing an unbind request).
+   * <p>
+   * Calling {@code close} on a connection that is already closed has no effect.
+   *
+   * @param request
+   *          The unbind request to use in the case where a physical connection
+   *          is closed.
+   * @param reason
+   *          A reason describing why the connection was closed.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  void close(UnbindRequest request, String reason) throws NullPointerException;
+
+
+
+  /**
+   * Compares an entry in the Directory Server using the provided compare
+   * request.
+   *
+   * @param request
+   *          The compare request.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support compare operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  CompareResult compare(CompareRequest request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Compares the named entry in the Directory Server against the provided
+   * attribute value assertion.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * CompareRequest request = new CompareRequest(name, attributeDescription,
+   *     assertionValue);
+   * connection.compare(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be compared.
+   * @param attributeDescription
+   *          The name of the attribute to be compared.
+   * @param assertionValue
+   *          The assertion value to be compared.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} or {@code AttributeDescription} could not be
+   *           decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support compare operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code name}, {@code attributeDescription}, or {@code
+   *           assertionValue} was {@code null}.
+   */
+  CompareResult compare(String name, String attributeDescription,
+      String assertionValue) throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Deletes an entry from the Directory Server using the provided delete
+   * request.
+   *
+   * @param request
+   *          The delete request.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support delete operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  Result delete(DeleteRequest request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Deletes the named entry from the Directory Server.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * DeleteRequest request = new DeleteRequest(name);
+   * connection.delete(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be deleted.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support delete operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  Result delete(String name) throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Requests that the Directory Server performs the provided extended request.
+   *
+   * @param <R>
+   *          The type of result returned by the extended request.
+   * @param request
+   *          The extended request.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support extended operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  <R extends ExtendedResult> R extendedRequest(ExtendedRequest<R> request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Requests that the Directory Server performs the provided extended request,
+   * optionally listening for any intermediate responses.
+   *
+   * @param <R>
+   *          The type of result returned by the extended request.
+   * @param request
+   *          The extended request.
+   * @param handler
+   *          An intermediate response handler which can be used to process any
+   *          intermediate responses as they are received, may be {@code null}.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support extended operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  <R extends ExtendedResult> R extendedRequest(ExtendedRequest<R> request,
+      IntermediateResponseHandler handler) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Requests that the Directory Server performs the provided extended request.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * GenericExtendedRequest request = new GenericExtendedRequest(requestName,
+   *     requestValue);
+   * connection.extendedRequest(request);
+   * </pre>
+   *
+   * @param requestName
+   *          The dotted-decimal representation of the unique OID corresponding
+   *          to the extended request.
+   * @param requestValue
+   *          The content of the extended request in a form defined by the
+   *          extended operation, or {@code null} if there is no content.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support extended operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code requestName} was {@code null}.
+   */
+  GenericExtendedResult extendedRequest(String requestName,
+      ByteString requestValue) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Returns an asynchronous connection sharing the same underlying network
+   * connection as this synchronous connection.
+   *
+   * @return An asynchronous connection sharing the same underlying network
+   *         connection as this synchronous connection.
+   */
+  AsynchronousConnection getAsynchronousConnection();
+
+
+
+  /**
+   * Indicates whether or not this connection has been explicitly closed by
+   * calling {@code close}. This method will not return {@code true} if a fatal
+   * error has occurred on the connection unless {@code close} has been called.
+   *
+   * @return {@code true} if this connection has been explicitly closed by
+   *         calling {@code close}, or {@code false} otherwise.
+   */
+  boolean isClosed();
+
+
+
+  /**
+   * Returns {@code true} if this connection has not been closed and no fatal
+   * errors have been detected. This method is guaranteed to return {@code
+   * false} only when it is called after the method {@code close} has been
+   * called.
+   *
+   * @return {@code true} if this connection is valid, {@code false} otherwise.
+   */
+  boolean isValid();
+
+
+
+  /**
+   * Modifies an entry in the Directory Server using the provided modify
+   * request.
+   *
+   * @param request
+   *          The modify request.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  Result modify(ModifyRequest request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Modifies an entry in the Directory Server using the provided lines of LDIF.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * ModifyRequest request = new ModifyRequest(name, ldifChanges);
+   * connection.modify(request);
+   * </pre>
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing the a single LDIF modify change record.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify operations.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  Result modify(String... ldifLines) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      LocalizedIllegalArgumentException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Renames an entry in the Directory Server using the provided modify DN
+   * request.
+   *
+   * @param request
+   *          The modify DN request.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify DN operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  Result modifyDN(ModifyDNRequest request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Renames the named entry in the Directory Server using the provided new RDN.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * ModifyDNRequest request = new ModifyDNRequest(name, newRDN);
+   * connection.modifyDN(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be renamed.
+   * @param newRDN
+   *          The new RDN of the entry.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} or {@code newRDN} could not be decoded using the
+   *           default schema.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support modify DN operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code name} or {@code newRDN} was {@code null}.
+   */
+  Result modifyDN(String name, String newRDN) throws ErrorResultException,
+      LocalizedIllegalArgumentException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Reads the named entry from the Directory Server.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * SearchRequest request = new SearchRequest(name, SearchScope.BASE_OBJECT,
+   *     &quot;(objectClass=*)&quot;, attributeDescriptions);
+   * connection.searchSingleEntry(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be read.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with the entry, which
+   *          may be {@code null} or empty indicating that all user attributes
+   *          should be returned.
+   * @return The single search result entry returned from the search.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code name} was {@code null}.
+   */
+  SearchResultEntry readEntry(DN name, String... attributeDescriptions)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Reads the named entry from the Directory Server.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * SearchRequest request = new SearchRequest(name, SearchScope.BASE_OBJECT,
+   *     &quot;(objectClass=*)&quot;, attributeDescriptions);
+   * connection.searchSingleEntry(request);
+   * </pre>
+   *
+   * @param name
+   *          The distinguished name of the entry to be read.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with the entry.
+   * @return The single search result entry returned from the search.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code baseObject} could not be decoded using the default
+   *           schema.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code name} was {@code null}.
+   */
+  SearchResultEntry readEntry(String name, String... attributeDescriptions)
+      throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the request
+   * will fail with an {@link EntryNotFoundException}. More specifically, this
+   * method will never return {@code null}.
+   *
+   * @return The Directory Server's Root DSE.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   */
+  RootDSE readRootDSE() throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named subschema
+   * sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * Implementations may choose to perform optimizations such as caching.
+   *
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @return The schema from the Directory Server.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   */
+  Schema readSchema(DN name) throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named subschema
+   * sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * Implementations may choose to perform optimizations such as caching.
+   *
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @return The schema from the Directory Server.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   */
+  Schema readSchema(String name) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the named
+   * entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by the
+   * Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, this method will never
+   * return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code subschemaSubentry}
+   * attribute of the entry in order to locate the schema. However,
+   * implementations may choose to perform other optimizations, such as caching.
+   *
+   * @param name
+   *          The distinguished name of the entry whose schema is to be located.
+   * @return The schema from the Directory Server which applies to the named
+   *         entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   */
+  Schema readSchemaForEntry(DN name) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the named
+   * entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by the
+   * Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, this method will never
+   * return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code subschemaSubentry}
+   * attribute of the entry in order to locate the schema. However,
+   * implementations may choose to perform other optimizations, such as caching.
+   *
+   * @param name
+   *          The distinguished name of the entry whose schema is to be located.
+   * @return The schema from the Directory Server which applies to the named
+   *         entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   */
+  Schema readSchemaForEntry(String name) throws ErrorResultException,
+      InterruptedException, LocalizedIllegalArgumentException,
+      UnsupportedOperationException, IllegalStateException;
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the Root DSE.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * A typical implementation will first read the {@code subschemaSubentry}
+   * attribute of the Root DSE in order to locate the schema. However,
+   * implementations may choose to perform other optimizations, such as caching.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * connection.readSchemaForEntry(DN.rootDN());
+   * </pre>
+   *
+   * @return The schema from the Directory Server which applies to the named
+   *         entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   */
+  Schema readSchemaForRootDSE() throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException;
+
+
+
+  /**
+   * Removes the provided connection event listener from this connection so that
+   * it will no longer be notified when this connection is closed by the
+   * application, receives an unsolicited notification, or experiences a fatal
+   * error.
+   *
+   * @param listener
+   *          The listener which no longer wants to be notified when events
+   *          occur on this connection.
+   * @throws NullPointerException
+   *           If the {@code listener} was {@code null}.
+   */
+  void removeConnectionEventListener(ConnectionEventListener listener)
+      throws NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server using the provided search request. Any
+   * matching entries returned by the search will be added to {@code entries},
+   * even if the final search result indicates that the search failed. Search
+   * result references will be discarded.
+   * <p>
+   * <b>Warning:</b> Usage of this method is discouraged if the search request
+   * is expected to yield a large number of search results since the entire set
+   * of results will be stored in memory, potentially causing an {@code
+   * OutOfMemoryError}.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * connection.search(request, entries, null);
+   * </pre>
+   *
+   * @param request
+   *          The search request.
+   * @param entries
+   *          The collection to which matching entries should be added.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} or {@code entries} was {@code null}.
+   */
+  Result search(SearchRequest request,
+      Collection<? super SearchResultEntry> entries)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server using the provided search request. Any
+   * matching entries returned by the search will be added to {@code entries},
+   * even if the final search result indicates that the search failed.
+   * Similarly, search result references returned by the search will be added to
+   * {@code references}.
+   * <p>
+   * <b>Warning:</b> Usage of this method is discouraged if the search request
+   * is expected to yield a large number of search results since the entire set
+   * of results will be stored in memory, potentially causing an {@code
+   * OutOfMemoryError}.
+   *
+   * @param request
+   *          The search request.
+   * @param entries
+   *          The collection to which matching entries should be added.
+   * @param references
+   *          The collection to which search result references should be added,
+   *          or {@code null} if references are to be discarded.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} or {@code entries} was {@code null}.
+   */
+  Result search(SearchRequest request,
+      Collection<? super SearchResultEntry> entries,
+      Collection<? super SearchResultReference> references)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server using the provided search request. Any
+   * matching entries returned by the search as well as any search result
+   * references will be passed to the provided search result handler.
+   *
+   * @param request
+   *          The search request.
+   * @param handler
+   *          A search result handler which can be used to process the search
+   *          result entries and references as they are received, may be {@code
+   *          null}.
+   * @return The result of the operation.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  Result search(SearchRequest request, SearchResultHandler handler)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server using the provided search parameters. Any
+   * matching entries returned by the search will be exposed through the
+   * {@code EntryReader} interface.
+   * <p>
+   * <b>Warning:</b> When using a queue with an optional capacity bound,
+   * the connection will stop reading responses and wait if necessary for
+   * space to become available.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * SearchRequest request = new SearchRequest(baseDN, scope, filter,
+   *     attributeDescriptions);
+   * connection.search(request, new LinkedBlockingQueue&lt;Response&gt;());
+   * </pre>
+   *
+   * @param baseObject
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed.
+   * @param scope
+   *          The scope of the search.
+   * @param filter
+   *          The filter that defines the conditions that must be fulfilled in
+   *          order for an entry to be returned.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with each entry.
+   * @return An entry reader exposing the returned entries.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code baseObject}, {@code scope}, or {@code filter} were
+   *           {@code null}.
+   */
+  ConnectionEntryReader search(String baseObject, SearchScope scope,
+      String filter, String... attributeDescriptions)
+      throws UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+
+
+  /**
+   * Searches the Directory Server using the provided search parameters. Any
+   * matching entries returned by the search will be exposed through the
+   * {@code EntryReader} interface.
+   * <p>
+   * <b>Warning:</b> When using a queue with an optional capacity bound,
+   * the connection will stop reading responses and wait if necessary for
+   * space to become available.
+   *
+   * @param request
+   *          The search request.
+   * @param entries
+   *          The queue to which matching entries should be added.
+   * @return The result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If {@code request} or {@code entries} was {@code null}.
+   */
+  ConnectionEntryReader search(SearchRequest request,
+                               BlockingQueue<Response> entries)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+  /**
+   * Searches the Directory Server for a single entry using the provided search
+   * request.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}. If multiple
+   * matching entries are returned by the Directory Server then the request will
+   * fail with an {@link MultipleEntriesFoundException}.
+   *
+   * @param request
+   *          The search request.
+   * @return The single search result entry returned from the search.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code request} was {@code null}.
+   */
+  SearchResultEntry searchSingleEntry(SearchRequest request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException;
+
+
+
+  /**
+   * Searches the Directory Server for a single entry using the provided search
+   * parameters.
+   * <p>
+   * If the requested entry is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}. If multiple
+   * matching entries are returned by the Directory Server then the request will
+   * fail with an {@link MultipleEntriesFoundException}.
+   * <p>
+   * This method is equivalent to the following code:
+   *
+   * <pre>
+   * SearchRequest request = new SearchRequest(baseObject, scope, filter,
+   *     attributeDescriptions);
+   * connection.searchSingleEntry(request);
+   * </pre>
+   *
+   * @param baseObject
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed.
+   * @param scope
+   *          The scope of the search.
+   * @param filter
+   *          The filter that defines the conditions that must be fulfilled in
+   *          order for an entry to be returned.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with each entry.
+   * @return The single search result entry returned from the search.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code baseObject} could not be decoded using the default
+   *           schema or if {@code filter} is not a valid LDAP string
+   *           representation of a filter.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code baseObject}, {@code scope}, or {@code filter} were
+   *           {@code null}.
+   */
+  SearchResultEntry searchSingleEntry(String baseObject, SearchScope scope,
+      String filter, String... attributeDescriptions)
+      throws ErrorResultException, InterruptedException,
+      LocalizedIllegalArgumentException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionEventListener.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionEventListener.java
new file mode 100644
index 0000000..f94355b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionEventListener.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.EventListener;
+
+import org.opends.sdk.responses.ExtendedResult;
+
+
+
+/**
+ * An object that registers to be notified when a connection is closed by the
+ * application, receives an unsolicited notification, or experiences a fatal
+ * error.
+ */
+public interface ConnectionEventListener extends EventListener
+{
+  /**
+   * Notifies this connection event listener that the application has called
+   * {@code close} on the connection. The connection event listener will be
+   * notified immediately after the application calls the {@code close} method
+   * on the associated connection.
+   */
+  void handleConnectionClosed();
+
+
+
+  /**
+   * Notifies this connection event listener that a fatal error has occurred and
+   * the connection can no longer be used - the server has crashed, for example.
+   * The connection implementation makes this notification just before it throws
+   * the provided {@link ErrorResultException} to the application.
+   * <p>
+   * <b>Note:</b> disconnect notifications are treated as fatal connection
+   * errors and are handled by this method. In this case
+   * {@code isDisconnectNotification} will be {@code true} and {@code error}
+   * will contain the result code and any diagnostic information contained in
+   * the notification message.
+   *
+   * @param isDisconnectNotification
+   *          {@code true} if the error was triggered by a disconnect
+   *          notification sent by the server, otherwise {@code false}.
+   * @param error
+   *          The exception that is about to be thrown to the application.
+   */
+  void handleConnectionError(boolean isDisconnectNotification,
+      ErrorResultException error);
+
+
+
+  /**
+   * Notifies this connection event listener that the connection has just
+   * received the provided unsolicited notification from the server.
+   * <p>
+   * <b>Note:</b> disconnect notifications are treated as fatal connection
+   * errors and are handled by the {@link #handleConnectionError} method.
+   *
+   * @param notification
+   *          The unsolicited notification.
+   */
+  void handleUnsolicitedNotification(ExtendedResult notification);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionException.java
new file mode 100644
index 0000000..839f2fc
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionException.java
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * was unsuccessful because of a connection failure.
+ */
+@SuppressWarnings("serial")
+public class ConnectionException extends ErrorResultException
+{
+  ConnectionException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionFactory.java
new file mode 100644
index 0000000..45417cb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionFactory.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * A connection factory provides an interface for obtaining a connection to a
+ * Directory Server. Connection factories can be used to wrap other connection
+ * factories in order to provide enhanced capabilities in a manner which is
+ * transparent to the application. For example:
+ * <ul>
+ * <li>Connection pooling
+ * <li>Load balancing
+ * <li>Keep alive
+ * <li>Transactional connections
+ * <li>Connections to LDIF files
+ * <li>Data transformations
+ * <li>Logging connections
+ * <li>Read-only connections
+ * <li>Pre-authenticated connections
+ * <li>Recording connections, with primitive roll-back functionality
+ * </ul>
+ * An application typically obtains a connection from a connection factory,
+ * performs one or more operations, and then closes the connection. Applications
+ * should aim to close connections as soon as possible in order to avoid
+ * resource contention.
+ */
+public interface ConnectionFactory
+{
+  /**
+   * Initiates an asynchronous connection request to the Directory Server
+   * associated with this connection factory. The returned {@code FutureResult}
+   * can be used to retrieve the completed asynchronous connection.
+   * Alternatively, if a {@code ResultHandler} is provided, the handler will be
+   * notified when the connection is available and ready for use.
+   *
+   * @param handler
+   *          The completion handler, or {@code null} if no handler is to be
+   *          used.
+   * @return A future which can be used to retrieve the asynchronous connection.
+   */
+  FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      ResultHandler<? super AsynchronousConnection> handler);
+
+
+
+  /**
+   * Returns a connection to the Directory Server associated with this
+   * connection factory. The connection returned by this method can be used
+   * immediately.
+   *
+   * @return A connection to the Directory Server associated with this
+   *         connection factory.
+   * @throws ErrorResultException
+   *           If the connection request failed for some reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   */
+  Connection getConnection() throws ErrorResultException, InterruptedException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionPool.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionPool.java
new file mode 100644
index 0000000..e9497da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionPool.java
@@ -0,0 +1,881 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.AsynchronousFutureResult;
+import com.sun.opends.sdk.util.CompletedFutureResult;
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A simple connection pool implementation.
+ */
+final class ConnectionPool extends AbstractConnectionFactory
+{
+
+  /**
+   * This result handler is invoked when an attempt to add a new connection to
+   * the pool completes.
+   */
+  private final class ConnectionResultHandler implements
+      ResultHandler<AsynchronousConnection>
+  {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      // Connection attempt failed, so decrease the pool size.
+      currentPoolSize.release();
+
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+      {
+        StaticUtils.DEBUG_LOG.fine(String.format(
+            "Connection attempt failed: " + error.getMessage()
+                + " currentPoolSize=%d, poolSize=%d",
+            poolSize - currentPoolSize.availablePermits(), poolSize));
+      }
+
+      QueueElement holder;
+      synchronized (queue)
+      {
+        if (queue.isEmpty() || !queue.getFirst().isWaitingFuture())
+        {
+          // No waiting futures.
+          return;
+        }
+        else
+        {
+          holder = queue.removeFirst();
+        }
+      }
+
+      // There was waiting future, so close it.
+      holder.getWaitingFuture().handleErrorResult(error);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleResult(final AsynchronousConnection connection)
+    {
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+      {
+        StaticUtils.DEBUG_LOG.fine(String.format(
+            "Connection attempt succeeded: "
+                + " currentPoolSize=%d, poolSize=%d",
+                poolSize - currentPoolSize.availablePermits(), poolSize));
+      }
+
+      publishConnection(connection);
+    }
+  }
+
+
+
+  /**
+   * A pooled connection is passed to the client. It wraps an underlying
+   * "pooled" connection obtained from the underlying factory and lasts until
+   * the client application closes this connection. More specifically, pooled
+   * connections are not actually stored in the internal queue.
+   */
+  private final class PooledConnection implements AsynchronousConnection
+  {
+    // Connection event listeners registed against this pooled connection should
+    // have the same life time as the pooled connection.
+    private final List<ConnectionEventListener> listeners =
+      new CopyOnWriteArrayList<ConnectionEventListener>();
+
+    private final AsynchronousConnection connection;
+
+    private final AtomicBoolean isClosed = new AtomicBoolean(false);
+
+
+
+    PooledConnection(final AsynchronousConnection connection)
+    {
+      this.connection = connection;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Void> abandon(final AbandonRequest request)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.abandon(request);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> add(final AddRequest request,
+        final ResultHandler<? super Result> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.add(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> add(final AddRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection
+          .add(request, resultHandler, intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addConnectionEventListener(
+        final ConnectionEventListener listener) throws IllegalStateException,
+        NullPointerException
+    {
+      Validator.ensureNotNull(listener);
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      listeners.add(listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<BindResult> bind(final BindRequest request,
+        final ResultHandler<? super BindResult> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.bind(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<BindResult> bind(final BindRequest request,
+        final ResultHandler<? super BindResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.bind(request, resultHandler,
+          intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close()
+    {
+      if (!isClosed.compareAndSet(false, true))
+      {
+        // Already closed.
+        return;
+      }
+
+      // Don't put invalid connections back in the pool.
+      if (connection.isValid())
+      {
+        publishConnection(connection);
+      }
+      else
+      {
+        // The connection may have been disconnected by the remote server, but
+        // the server may still be available. In order to avoid leaving pending
+        // futures hanging indefinitely, we should try to reconnect immediately.
+
+        // Close the dead connection.
+        connection.close();
+
+        // Try to get a new connection to replace it.
+        factory.getAsynchronousConnection(connectionResultHandler);
+
+        if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          StaticUtils.DEBUG_LOG.warning(String.format(
+              "Connection no longer valid. "
+                  + "currentPoolSize=%d, poolSize=%d",
+                  poolSize - currentPoolSize.availablePermits(), poolSize));
+        }
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close(final UnbindRequest request, final String reason)
+        throws NullPointerException
+    {
+      close();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<CompareResult> compare(final CompareRequest request,
+        final ResultHandler<? super CompareResult> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.compare(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<CompareResult> compare(final CompareRequest request,
+        final ResultHandler<? super CompareResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.compare(request, resultHandler,
+          intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> delete(final DeleteRequest request,
+        final ResultHandler<? super Result> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.delete(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> delete(final DeleteRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.delete(request, resultHandler,
+          intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <R extends ExtendedResult> FutureResult<R> extendedRequest(
+        final ExtendedRequest<R> request, final ResultHandler<? super R> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.extendedRequest(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <R extends ExtendedResult> FutureResult<R> extendedRequest(
+        final ExtendedRequest<R> request,
+        final ResultHandler<? super R> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.extendedRequest(request, resultHandler,
+          intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Connection getSynchronousConnection()
+    {
+      return new SynchronousConnection(this);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isClosed()
+    {
+      return isClosed.get();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValid()
+    {
+      return connection.isValid() && !isClosed();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> modify(final ModifyRequest request,
+        final ResultHandler<? super Result> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.modify(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> modify(final ModifyRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.modify(request, resultHandler,
+          intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
+        final ResultHandler<? super Result> handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.modifyDN(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> modifyDN(final ModifyDNRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.modifyDN(request, resultHandler,
+          intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<SearchResultEntry> readEntry(final DN name,
+        final Collection<String> attributeDescriptions,
+        final ResultHandler<? super SearchResultEntry> resultHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readEntry(name, attributeDescriptions, resultHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<RootDSE> readRootDSE(
+        final ResultHandler<? super RootDSE> handler)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readRootDSE(handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Schema> readSchema(final DN name,
+        final ResultHandler<? super Schema> handler)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readSchema(name, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Schema> readSchemaForEntry(final DN name,
+        final ResultHandler<? super Schema> handler)
+        throws UnsupportedOperationException, IllegalStateException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.readSchemaForEntry(name, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void removeConnectionEventListener(
+        final ConnectionEventListener listener) throws NullPointerException
+    {
+      Validator.ensureNotNull(listener);
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      listeners.remove(listener);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> search(final SearchRequest request,
+        final SearchResultHandler handler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.search(request, handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<Result> search(final SearchRequest request,
+        final SearchResultHandler resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.search(request, resultHandler,
+          intermediateResponseHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FutureResult<SearchResultEntry> searchSingleEntry(
+        final SearchRequest request,
+        final ResultHandler<? super SearchResultEntry> resultHandler)
+        throws UnsupportedOperationException, IllegalStateException,
+        NullPointerException
+    {
+      if (isClosed())
+      {
+        throw new IllegalStateException();
+      }
+      return connection.searchSingleEntry(request, resultHandler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+      final StringBuilder builder = new StringBuilder();
+      builder.append("PooledConnection(");
+      builder.append(connection);
+      builder.append(')');
+      return builder.toString();
+    }
+  }
+
+
+
+  /**
+   * A queue element is either a pending connection request future awaiting an
+   * {@code AsynchronousConnection} or it is an unused
+   * {@code AsynchronousConnection} awaiting a connection request.
+   */
+  private static final class QueueElement
+  {
+    private final Object value;
+
+
+
+    QueueElement(final AsynchronousConnection connection)
+    {
+      this.value = connection;
+    }
+
+
+
+    QueueElement(final ResultHandler<? super AsynchronousConnection> handler)
+    {
+      this.value = new AsynchronousFutureResult<AsynchronousConnection>(handler);
+    }
+
+
+
+    AsynchronousConnection getWaitingConnection()
+    {
+      if (value instanceof AsynchronousConnection)
+      {
+        return (AsynchronousConnection) value;
+      }
+      else
+      {
+        throw new IllegalStateException();
+      }
+    }
+
+
+
+    @SuppressWarnings("unchecked")
+    AsynchronousFutureResult<AsynchronousConnection> getWaitingFuture()
+    {
+      if (value instanceof AsynchronousFutureResult)
+      {
+        return (AsynchronousFutureResult<AsynchronousConnection>) value;
+      }
+      else
+      {
+        throw new IllegalStateException();
+      }
+    }
+
+
+
+    boolean isWaitingFuture()
+    {
+      return value instanceof AsynchronousFutureResult;
+    }
+
+
+
+    public String toString()
+    {
+      return String.valueOf(value);
+    }
+  }
+
+
+
+  // Guarded by queue.
+  private final LinkedList<QueueElement> queue = new LinkedList<QueueElement>();
+
+  private final ConnectionFactory factory;
+
+  private final int poolSize;
+
+  private final Semaphore currentPoolSize;
+
+  private final ResultHandler<AsynchronousConnection> connectionResultHandler =
+    new ConnectionResultHandler();
+
+
+
+  /**
+   * Creates a new connection pool which will maintain {@code poolSize}
+   * connections created using the provided connection factory.
+   *
+   * @param factory
+   *          The connection factory to use for creating new connections.
+   * @param poolSize
+   *          The maximum size of the connection pool.
+   */
+  ConnectionPool(final ConnectionFactory factory, final int poolSize)
+  {
+    this.factory = factory;
+    this.poolSize = poolSize;
+    this.currentPoolSize = new Semaphore(poolSize);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> handler)
+  {
+    QueueElement holder;
+    synchronized (queue)
+    {
+      if (queue.isEmpty() || queue.getFirst().isWaitingFuture())
+      {
+        holder = new QueueElement(handler);
+        queue.add(holder);
+      }
+      else
+      {
+        holder = queue.removeFirst();
+      }
+    }
+
+    if (!holder.isWaitingFuture())
+    {
+      // There was a completed connection attempt.
+      final AsynchronousConnection connection = holder.getWaitingConnection();
+      final PooledConnection pooledConnection = new PooledConnection(connection);
+      if (handler != null)
+      {
+        handler.handleResult(pooledConnection);
+      }
+      return new CompletedFutureResult<AsynchronousConnection>(pooledConnection);
+    }
+    else
+    {
+      // Grow the pool if needed.
+      final FutureResult<AsynchronousConnection> future = holder
+          .getWaitingFuture();
+      if (!future.isDone() && currentPoolSize.tryAcquire())
+      {
+        factory.getAsynchronousConnection(connectionResultHandler);
+      }
+      return future;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ConnectionPool(");
+    builder.append(String.valueOf(factory));
+    builder.append(',');
+    builder.append(poolSize);
+    builder.append(')');
+    return builder.toString();
+  }
+
+
+
+  private void publishConnection(final AsynchronousConnection connection)
+  {
+    QueueElement holder;
+    synchronized (queue)
+    {
+      if (queue.isEmpty() || !queue.getFirst().isWaitingFuture())
+      {
+        holder = new QueueElement(connection);
+        queue.add(holder);
+        return;
+      }
+      else
+      {
+        holder = queue.removeFirst();
+      }
+    }
+
+    // There was waiting future, so close it.
+    final PooledConnection pooledConnection = new PooledConnection(connection);
+    holder.getWaitingFuture().handleResult(pooledConnection);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionSecurityLayer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionSecurityLayer.java
new file mode 100644
index 0000000..2066c06
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConnectionSecurityLayer.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * An interface for providing additional connection security to a connection.
+ */
+public interface ConnectionSecurityLayer
+{
+
+  /**
+   * Disposes of any system resources or security-sensitive information that
+   * this connection security layer might be using. Invoking this method
+   * invalidates this instance.
+   */
+  void dispose();
+
+
+
+  /**
+   * Unwraps a byte array received from the peer.
+   *
+   * @param incoming
+   *          A non-{@code null} byte array containing the encoded bytes from
+   *          the peer.
+   * @param offset
+   *          The starting position in {@code incoming} of the bytes to be
+   *          unwrapped.
+   * @param len
+   *          The number of bytes from {@code incoming} to be unwrapped.
+   * @return A non-{@code null} byte array containing the unwrapped bytes.
+   * @throws org.opends.sdk.ErrorResultException
+   *           If {@code incoming} cannot be successfully unwrapped.
+   */
+  byte[] unwrap(byte[] incoming, int offset, int len)
+      throws ErrorResultException;
+
+
+
+  /**
+   * Wraps a byte array to be sent to the peer.
+   *
+   * @param outgoing
+   *          A non-{@code null} byte array containing the unencoded bytes to be
+   *          sent to the peer.
+   * @param offset
+   *          The starting position in {@code outgoing} of the bytes to be
+   *          wrapped.
+   * @param len
+   *          The number of bytes from {@code outgoing} to be wrapped.
+   * @return A non-{@code null} byte array containing the wrapped bytes.
+   * @throws ErrorResultException
+   *           If {@code outgoing} cannot be successfully wrapped.
+   */
+  byte[] wrap(byte[] outgoing, int offset, int len) throws ErrorResultException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connections.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connections.java
new file mode 100644
index 0000000..7965ebb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Connections.java
@@ -0,0 +1,342 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.opends.sdk.requests.BindRequest;
+import org.opends.sdk.requests.SearchRequest;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class contains methods for creating and manipulating connection
+ * factories and connections.
+ */
+public final class Connections
+{
+  /**
+   * Creates a new authenticated connection factory which will obtain
+   * connections using the provided connection factory and immediately perform
+   * the provided Bind request.
+   * <p>
+   * The connections returned by an authenticated connection factory support all
+   * operations with the exception of Bind requests. Attempts to perform a Bind
+   * will result in an {@code UnsupportedOperationException}.
+   * <p>
+   * If the Bind request fails for some reason (e.g. invalid credentials), then
+   * the connection attempt will fail and an {@code ErrorResultException} will
+   * be thrown.
+   *
+   * @param factory
+   *          The connection factory to use for connecting to the Directory
+   *          Server.
+   * @param request
+   *          The Bind request to use for authentication.
+   * @return The new connection pool.
+   * @throws NullPointerException
+   *           If {@code factory} or {@code request} was {@code null}.
+   */
+  public static ConnectionFactory newAuthenticatedConnectionFactory(
+      final ConnectionFactory factory, final BindRequest request)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(factory, request);
+
+    return new AuthenticatedConnectionFactory(factory, request);
+  }
+
+
+
+  /**
+   * Creates a new connection pool which will maintain {@code poolSize}
+   * connections created using the provided connection factory.
+   *
+   * @param factory
+   *          The connection factory to use for creating new connections.
+   * @param poolSize
+   *          The maximum size of the connection pool.
+   * @return The new connection pool.
+   * @throws IllegalArgumentException
+   *           If {@code poolSize} is negative.
+   * @throws NullPointerException
+   *           If {@code factory} was {@code null}.
+   */
+  public static ConnectionFactory newConnectionPool(
+      final ConnectionFactory factory, final int poolSize)
+      throws IllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(factory);
+    Validator.ensureTrue(poolSize >= 0, "negative pool size");
+    return new ConnectionPool(factory, poolSize);
+  }
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections in order to detect that they are still alive every 10 seconds
+   * using the default scheduler.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   * @return The new heart-beat connection factory.
+   * @throws NullPointerException
+   *           If {@code factory} was {@code null}.
+   */
+  public static ConnectionFactory newHeartBeatConnectionFactory(
+      final ConnectionFactory factory) throws NullPointerException
+  {
+    return new HeartBeatConnectionFactory(factory);
+  }
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections in order to detect that they are still alive using the
+   * specified frequency and the default scheduler.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   * @param interval
+   *          The interval between keepalive pings.
+   * @param unit
+   *          The time unit for the interval between keepalive pings.
+   * @return The new heart-beat connection factory.
+   * @throws IllegalArgumentException
+   *           If {@code interval} was negative.
+   * @throws NullPointerException
+   *           If {@code factory} or {@code unit} was {@code null}.
+   */
+  public static ConnectionFactory newHeartBeatConnectionFactory(
+      final ConnectionFactory factory, final long interval, final TimeUnit unit)
+      throws IllegalArgumentException, NullPointerException
+  {
+    return new HeartBeatConnectionFactory(factory, interval, unit);
+  }
+
+
+
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections using the specified search request in order to detect that they
+   * are still alive.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   * @param interval
+   *          The interval between keepalive pings.
+   * @param unit
+   *          The time unit for the interval between keepalive pings.
+   * @param heartBeat
+   *          The search request to use for keepalive pings.
+   * @return The new heart-beat connection factory.
+   * @throws IllegalArgumentException
+   *           If {@code interval} was negative.
+   * @throws NullPointerException
+   *           If {@code factory}, {@code unit}, or {@code heartBeat} was {@code null}.
+   */
+  public static ConnectionFactory newHeartBeatConnectionFactory(
+      final ConnectionFactory factory, final long interval, final TimeUnit unit,
+      final SearchRequest heartBeat) throws IllegalArgumentException,
+      NullPointerException
+  {
+    return new HeartBeatConnectionFactory(factory, interval, unit, heartBeat);
+  }
+
+
+
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections using the specified search request in order to detect that they
+   * are still alive.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   * @param interval
+   *          The interval between keepalive pings.
+   * @param unit
+   *          The time unit for the interval between keepalive pings.
+   * @param heartBeat
+   *          The search request to use for keepalive pings.
+   * @param scheduler
+   *          The scheduler which should for periodically sending keepalive
+   *          pings.
+   * @return The new heart-beat connection factory.
+   * @throws IllegalArgumentException
+   *           If {@code interval} was negative.
+   * @throws NullPointerException
+   *           If {@code factory}, {@code unit}, or {@code heartBeat} was
+   *           {@code null}.
+   */
+  public static ConnectionFactory newHeartBeatConnectionFactory(
+      final ConnectionFactory factory, final long interval,
+      final TimeUnit unit, final SearchRequest heartBeat,
+      final ScheduledExecutorService scheduler)
+      throws IllegalArgumentException, NullPointerException
+  {
+    return new HeartBeatConnectionFactory(factory, interval, unit, heartBeat,
+        scheduler);
+  }
+
+
+
+  /**
+   * Creates a new connection factory which binds internal client connections to
+   * {@link ServerConnection}s created using the provided
+   * {@link ServerConnectionFactory}.
+   * <p>
+   * When processing requests, {@code ServerConnection} implementations are
+   * passed an integer as the first parameter. This integer represents a pseudo
+   * {@code requestID} which is incremented for each successive internal request
+   * on a per client connection basis. The request ID may be useful for logging
+   * purposes.
+   * <p>
+   * An internal connection factory does not require {@code ServerConnection}
+   * implementations to return a result when processing requests. However, it is
+   * recommended that implementations do always return results even for
+   * abandoned requests. This is because application client threads may block
+   * indefinitely waiting for results.
+   *
+   * @param <C>
+   *          The type of client context.
+   * @param factory
+   *          The server connection factory to use for creating connections.
+   * @param clientContext
+   *          The client context.
+   * @return The new internal connection factory.
+   * @throws NullPointerException
+   *           If {@code factory} was {@code null}.
+   */
+  public static <C> ConnectionFactory newInternalConnectionFactory(
+      final ServerConnectionFactory<C, Integer> factory, final C clientContext)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(factory);
+    return new InternalConnectionFactory<C>(factory, clientContext);
+  }
+
+
+
+  /**
+   * Creates a new load balancer which will obtain connections using the
+   * provided load balancing algorithm.
+   *
+   * @param algorithm
+   *          The load balancing algorithm which will be used to obtain the next
+   * @return The new load balancer.
+   * @throws NullPointerException
+   *           If {@code algorithm} was {@code null}.
+   */
+  public static ConnectionFactory newLoadBalancer(
+      final LoadBalancingAlgorithm algorithm) throws NullPointerException
+  {
+    return new LoadBalancer(algorithm);
+  }
+
+
+
+  /**
+   * Creates a new connection factory which forwards connection requests to the
+   * provided factory, but whose {@code toString} method will always return
+   * {@code name}.
+   * <p>
+   * This method may be useful for debugging purposes in order to more easily
+   * identity connection factories.
+   *
+   * @param factory
+   *          The connection factory to be named.
+   * @param name
+   *          The name of the connection factory.
+   * @return The named connection factory.
+   * @throws NullPointerException
+   *           If {@code factory} or {@code name} was {@code null}.
+   */
+  public static ConnectionFactory newNamedConnectionFactory(
+      final ConnectionFactory factory, final String name)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(factory, name);
+
+    return new ConnectionFactory()
+    {
+
+      @Override
+      public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+          final ResultHandler<? super AsynchronousConnection> handler)
+      {
+        return factory.getAsynchronousConnection(handler);
+      }
+
+
+
+      @Override
+      public Connection getConnection() throws ErrorResultException,
+          InterruptedException
+      {
+        return factory.getConnection();
+      }
+
+
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public String toString()
+      {
+        return name;
+      }
+
+    };
+  }
+
+
+
+  // Prevent instantiation.
+  private Connections()
+  {
+    // Do nothing.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConstraintViolationException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConstraintViolationException.java
new file mode 100644
index 0000000..5d8c9c0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ConstraintViolationException.java
@@ -0,0 +1,80 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the update
+ * Request failed because it would have left the Directory in an inconsistent
+ * state. More specifically, this exception is used for the following error
+ * result codes:
+ * <ul>
+ * <li>{@link ResultCode#ATTRIBUTE_OR_VALUE_EXISTS ATTRIBUTE_OR_VALUE_EXISTS} -
+ * the Request failed because it would have resulted in a conflict with an
+ * existing attribute or attribute value in the target entry.
+ * <li>{@link ResultCode#CONSTRAINT_VIOLATION CONSTRAINT_VIOLATION} - the
+ * Request failed because it would have violated some constraint defined in the
+ * server.
+ * <li>{@link ResultCode#ENTRY_ALREADY_EXISTS ENTRY_ALREADY_EXISTS} - the
+ * Request failed because it would have resulted in an entry that conflicts with
+ * an entry that already exists.
+ * <li>{@link ResultCode#INVALID_ATTRIBUTE_SYNTAX INVALID_ATTRIBUTE_SYNTAX} -
+ * the Request failed because it violated the syntax for a specified attribute.
+ * <li>{@link ResultCode#INVALID_DN_SYNTAX INVALID_DN_SYNTAX} - the Request
+ * failed because it would have resulted in an entry with an invalid or
+ * malformed DN.
+ * <li>{@link ResultCode#NAMING_VIOLATION NAMING_VIOLATION} - the Request failed
+ * becauseit would have violated the server's naming configuration.
+ * <li>{@link ResultCode#NOT_ALLOWED_ON_NONLEAF NOT_ALLOWED_ON_NONLEAF} - the
+ * Request failed because it is not allowed for non-leaf entries.
+ * <li>{@link ResultCode#NOT_ALLOWED_ON_RDN NOT_ALLOWED_ON_RDN} - the Request
+ * failed because it is not allowed on an RDN attribute.
+ * <li>{@link ResultCode#OBJECTCLASS_MODS_PROHIBITED
+ * OBJECTCLASS_MODS_PROHIBITED} - the Request failed because it would have
+ * modified the objectclasses associated with an entry in an illegal manner.
+ * <li>{@link ResultCode#OBJECTCLASS_VIOLATION OBJECTCLASS_VIOLATION} - the
+ * Request failed because it would have resulted in an entry that violated the
+ * server schema.
+ * <li>{@link ResultCode#UNDEFINED_ATTRIBUTE_TYPE UNDEFINED_ATTRIBUTE_TYPE} -
+ * the Request failed because it referenced an attribute that is not defined in
+ * the server schema.
+ * </ul>
+ */
+@SuppressWarnings("serial")
+public class ConstraintViolationException extends ErrorResultException
+{
+  ConstraintViolationException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DN.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DN.java
new file mode 100644
index 0000000..9631c20
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DN.java
@@ -0,0 +1,813 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_DN_TYPE_NOT_FOUND;
+
+import java.util.*;
+
+import org.opends.sdk.schema.Schema;
+import org.opends.sdk.schema.UnknownSchemaElementException;
+
+import com.sun.opends.sdk.util.SubstringReader;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A distinguished name (DN) as defined in RFC 4512 section 2.3 is the
+ * concatenation of its relative distinguished name (RDN) and its immediate
+ * superior's DN. A DN unambiguously refers to an entry in the Directory.
+ * <p>
+ * The following are examples of string representations of DNs:
+ *
+ * <pre>
+ * UID=nobody@example.com,DC=example,DC=com CN=John
+ * Smith,OU=Sales,O=ACME Limited,L=Moab,ST=Utah,C=US
+ * </pre>
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4512#section-2.3">RFC 4512 -
+ *      Lightweight Directory Access Protocol (LDAP): Directory Information
+ *      Models </a>
+ */
+public final class DN implements Iterable<RDN>, Comparable<DN>
+{
+  private static final DN ROOT_DN = new DN(null, null, "");
+
+  // This is the size of the per-thread per-schema DN cache. We should
+  // be conservative here in case there are many threads. We will only
+  // cache parent DNs, so there's no need for it to be big.
+  private static final int DN_CACHE_SIZE = 32;
+
+  private static final ThreadLocal<WeakHashMap<Schema, Map<String, DN>>> CACHE =
+    new ThreadLocal<WeakHashMap<Schema, Map<String, DN>>>()
+  {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected WeakHashMap<Schema, Map<String, DN>> initialValue()
+    {
+      return new WeakHashMap<Schema, Map<String, DN>>();
+    }
+
+  };
+
+
+
+  /**
+   * Returns the Root DN. The Root DN does not contain and RDN components and is
+   * superior to all other DNs.
+   *
+   * @return The Root DN.
+   */
+  public static DN rootDN()
+  {
+    return ROOT_DN;
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of a DN using the default
+   * schema.
+   *
+   * @param dn
+   *          The LDAP string representation of a DN.
+   * @return The parsed DN.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} is not a valid LDAP string representation of a DN.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public static DN valueOf(final String dn)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return valueOf(dn, Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of a DN using the provided
+   * schema.
+   *
+   * @param dn
+   *          The LDAP string representation of a DN.
+   * @param schema
+   *          The schema to use when parsing the DN.
+   * @return The parsed DN.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} is not a valid LDAP string representation of a DN.
+   * @throws NullPointerException
+   *           If {@code dn} or {@code schema} was {@code null}.
+   */
+  public static DN valueOf(final String dn, final Schema schema)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(dn, schema);
+    if (dn.length() == 0)
+    {
+      return ROOT_DN;
+    }
+
+    // First check if DN is already cached.
+    final Map<String, DN> cache = getCache(schema);
+    final DN cachedDN = cache.get(dn);
+    if (cachedDN != null)
+    {
+      return cachedDN;
+    }
+
+    // Not in cache so decode.
+    final SubstringReader reader = new SubstringReader(dn);
+    return decode(dn, reader, schema, cache);
+  }
+
+
+
+  /**
+   * Compares the provided DN values to determine their relative order in a
+   * sorted list.
+   *
+   * @param dn1
+   *          The first DN to be compared. It must not be {@code null}.
+   * @param dn2
+   *          The second DN to be compared. It must not be {@code null}.
+   * @return A negative integer if the first DN should come before the second DN
+   *         in a sorted list, a positive integer if the first DN should come
+   *         after the second DN in a sorted list, or zero if the two DN values
+   *         can be considered equal.
+   */
+  private static int compareTo(final DN dn1, final DN dn2)
+  {
+    // Quickly check if we are comparing against root dse.
+    if (dn1.isRootDN())
+    {
+      if (dn2.isRootDN())
+      {
+        // both are equal.
+        return 0;
+      }
+      else
+      {
+        // dn1 comes before dn2.
+        return -1;
+      }
+    }
+
+    if (dn2.isRootDN())
+    {
+      // dn1 comes after dn2.
+      return 1;
+    }
+
+    int dn1Size = dn1.size - 1;
+    int dn2Size = dn2.size - 1;
+    while (dn1Size >= 0 && dn2Size >= 0)
+    {
+      final DN dn1Parent = dn1.parent(dn1Size--);
+      final DN dn2Parent = dn2.parent(dn2Size--);
+      if (dn1Parent.isRootDN())
+      {
+        if (dn2Parent.isRootDN())
+        {
+          break;
+        }
+        return -1;
+      }
+
+      if (dn2Parent.isRootDN())
+      {
+        return 1;
+      }
+
+      final int result = dn1Parent.rdn.compareTo(dn2Parent.rdn);
+      if (result > 0)
+      {
+        return 1;
+      }
+      else if (result < 0)
+      {
+        return -1;
+      }
+    }
+
+    // What do we have here?
+    if (dn1Size > dn2Size)
+    {
+      return 1;
+    }
+    else if (dn1Size < dn2Size)
+    {
+      return -1;
+    }
+
+    return 0;
+  }
+
+
+
+  // Decodes a DN using the provided reader and schema.
+  private static DN decode(final String dnString, final SubstringReader reader,
+      final Schema schema, final Map<String, DN> cache)
+      throws LocalizedIllegalArgumentException
+  {
+    reader.skipWhitespaces();
+    if (reader.remaining() == 0)
+    {
+      return ROOT_DN;
+    }
+
+    RDN rdn;
+    try
+    {
+      rdn = RDN.decode(null, reader, schema);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      final LocalizableMessage message = ERR_DN_TYPE_NOT_FOUND.get(reader
+          .getString(), e.getMessageObject());
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    DN parent;
+    if (reader.remaining() > 0 && reader.read() == ',')
+    {
+      reader.mark();
+      final String parentString = reader.read(reader.remaining());
+
+      parent = cache.get(parentString);
+      if (parent == null)
+      {
+        reader.reset();
+        parent = decode(parentString, reader, schema, cache);
+
+        // Only cache parent DNs since leaf DNs are likely to make the
+        // cache to volatile.
+        cache.put(parentString, parent);
+      }
+    }
+    else
+    {
+      parent = ROOT_DN;
+    }
+
+    return new DN(rdn, parent, dnString);
+  }
+
+
+
+  @SuppressWarnings("serial")
+  private static Map<String, DN> getCache(final Schema schema)
+  {
+    final WeakHashMap<Schema, Map<String, DN>> threadLocalMap = CACHE.get();
+    Map<String, DN> schemaLocalMap = threadLocalMap.get(schema);
+
+    if (schemaLocalMap == null)
+    {
+      schemaLocalMap = new LinkedHashMap<String, DN>(DN_CACHE_SIZE, 0.75f, true)
+      {
+        @Override
+        protected boolean removeEldestEntry(final Map.Entry<String, DN> e)
+        {
+          return size() > DN_CACHE_SIZE;
+        }
+      };
+      threadLocalMap.put(schema, schemaLocalMap);
+    }
+    return schemaLocalMap;
+  }
+
+
+
+  private final RDN rdn;
+
+  private final DN parent;
+
+  private final int size;
+
+  // We need to store the original string value if provided in order to
+  // preserve the original whitespace.
+  private String stringValue;
+
+
+
+  // Private constructor.
+  private DN(final RDN rdn, final DN parent, final String stringValue)
+  {
+    this.rdn = rdn;
+    this.parent = parent;
+    this.stringValue = stringValue;
+    this.size = parent != null ? parent.size + 1 : 0;
+  }
+
+
+
+  /**
+   * Returns a DN which is subordinate to this DN and having the additional RDN
+   * components contained in the provided DN.
+   *
+   * @param dn
+   *          The DN containing the RDN components to be added to this DN.
+   * @return The subordinate DN.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public DN child(final DN dn) throws NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+
+    if (dn.isRootDN())
+    {
+      return this;
+    }
+    else if (isRootDN())
+    {
+      return dn;
+    }
+    else
+    {
+      final RDN[] rdns = new RDN[dn.size()];
+      int i = rdns.length;
+      for (DN next = dn; next.rdn != null; next = next.parent)
+      {
+        rdns[--i] = next.rdn;
+      }
+      DN newDN = this;
+      for (i = 0; i < rdns.length; i++)
+      {
+        newDN = new DN(rdns[i], newDN, null);
+      }
+      return newDN;
+    }
+  }
+
+
+
+  /**
+   * Returns a DN which is an immediate child of this DN and having the
+   * specified RDN.
+   *
+   * @param rdn
+   *          The RDN for the child DN.
+   * @return The child DN.
+   * @throws NullPointerException
+   *           If {@code rdn} was {@code null}.
+   */
+  public DN child(final RDN rdn) throws NullPointerException
+  {
+    Validator.ensureNotNull(rdn);
+    return new DN(rdn, this, null);
+  }
+
+
+
+  /**
+   * Returns a DN which is subordinate to this DN and having the additional RDN
+   * components contained in the provided DN decoded using the default schema.
+   *
+   * @param dn
+   *          The DN containing the RDN components to be added to this DN.
+   * @return The subordinate DN.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} is not a valid LDAP string representation of a DN.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public DN child(final String dn) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    return child(valueOf(dn));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final DN dn)
+  {
+    return compareTo(this, dn);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    else if (obj instanceof DN)
+    {
+      DN other = (DN)obj;
+      if(size == other.size())
+      {
+        if(size == 0)
+        {
+          return true;
+        }
+
+        if(rdn.equals(other.rdn))
+        {
+          return parent.equals(other.parent);
+        }
+      }
+    }
+
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    if (size == 0)
+    {
+      return 0;
+    }
+    else
+    {
+      return 31 * parent.hashCode() + rdn.hashCode();
+    }
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is an immediate child of the provided DN.
+   *
+   * @param dn
+   *          The potential parent DN.
+   * @return {@code true} if this DN is the immediate child of the provided DN,
+   *         otherwise {@code false}.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isChildOf(final DN dn) throws NullPointerException
+  {
+    // If this is the Root DN then parent will be null but this is ok.
+    return dn.equals(parent);
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is an immediate child of the provided DN
+   * decoded using the default schema.
+   *
+   * @param dn
+   *          The potential parent DN.
+   * @return {@code true} if this DN is the immediate child of the provided DN,
+   *         otherwise {@code false}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} is not a valid LDAP string representation of a DN.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isChildOf(final String dn)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    // If this is the Root DN then parent will be null but this is ok.
+    return isChildOf(valueOf(dn));
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is the immediate parent of the provided DN.
+   *
+   * @param dn
+   *          The potential child DN.
+   * @return {@code true} if this DN is the immediate parent of the provided DN,
+   *         otherwise {@code false}.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isParentOf(final DN dn) throws NullPointerException
+  {
+    // If dn is the Root DN then parent will be null but this is ok.
+    return equals(dn.parent);
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is the immediate parent of the provided DN.
+   *
+   * @param dn
+   *          The potential child DN.
+   * @return {@code true} if this DN is the immediate parent of the provided DN,
+   *         otherwise {@code false}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} is not a valid LDAP string representation of a DN.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isParentOf(final String dn)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    // If dn is the Root DN then parent will be null but this is ok.
+    return isParentOf(valueOf(dn));
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is the Root DN.
+   *
+   * @return {@code true} if this DN is the Root DN, otherwise {@code false}.
+   */
+  public boolean isRootDN()
+  {
+    return size == 0;
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is subordinate to or equal to the provided
+   * DN.
+   *
+   * @param dn
+   *          The potential child DN.
+   * @return {@code true} if this DN is subordinate to or equal to the provided
+   *         DN, otherwise {@code false}.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isSubordinateOrEqualTo(final DN dn)
+      throws NullPointerException
+  {
+    if (size < dn.size)
+    {
+      return false;
+    }
+    else if (size == dn.size)
+    {
+      return equals(dn);
+    }
+    else
+    {
+      // dn is a potential superior of this.
+      return parent(size - dn.size).equals(dn);
+    }
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is subordinate to or equal to the provided
+   * DN.
+   *
+   * @param dn
+   *          The potential child DN.
+   * @return {@code true} if this DN is subordinate to or equal to the provided
+   *         DN, otherwise {@code false}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} is not a valid LDAP string representation of a DN.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isSubordinateOrEqualTo(final String dn)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return isSubordinateOrEqualTo(valueOf(dn));
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is superior to or equal to the provided DN.
+   *
+   * @param dn
+   *          The potential child DN.
+   * @return {@code true} if this DN is superior to or equal to the provided DN,
+   *         otherwise {@code false}.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isSuperiorOrEqualTo(final DN dn) throws NullPointerException
+  {
+    if (size > dn.size)
+    {
+      return false;
+    }
+    else if (size == dn.size)
+    {
+      return equals(dn);
+    }
+    else
+    {
+      // dn is a potential subordinate of this.
+      return dn.parent(dn.size - size).equals(this);
+    }
+  }
+
+
+
+  /**
+   * Returns {@code true} if this DN is superior to or equal to the provided DN.
+   *
+   * @param dn
+   *          The potential child DN.
+   * @return {@code true} if this DN is superior to or equal to the provided DN,
+   *         otherwise {@code false}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} is not a valid LDAP string representation of a DN.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  public boolean isSuperiorOrEqualTo(final String dn)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return isSuperiorOrEqualTo(valueOf(dn));
+  }
+
+
+
+  /**
+   * Returns an iterator of the RDNs contained in this DN. The RDNs will be
+   * returned in the order starting with this DN's RDN, followed by the RDN of
+   * the parent DN, and so on.
+   * <p>
+   * Attempts to remove RDNs using an iterator's {@code remove()} method are not
+   * permitted and will result in an {@code UnsupportedOperationException} being
+   * thrown.
+   *
+   * @return An iterator of the RDNs contained in this DN.
+   */
+  public Iterator<RDN> iterator()
+  {
+    return new Iterator<RDN>()
+    {
+      private DN dn = DN.this;
+
+
+
+      public boolean hasNext()
+      {
+        return dn.rdn != null;
+      }
+
+
+
+      public RDN next()
+      {
+        if (dn.rdn == null)
+        {
+          throw new NoSuchElementException();
+        }
+
+        final RDN rdn = dn.rdn;
+        dn = dn.parent;
+        return rdn;
+      }
+
+
+
+      public void remove()
+      {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+
+
+
+  /**
+   * Returns the DN which is the immediate parent of this DN, or {@code null} if
+   * this DN is the Root DN.
+   * <p>
+   * This method is equivalent to:
+   *
+   * <pre>
+   * parent(1);
+   * </pre>
+   *
+   * @return The DN which is the immediate parent of this DN, or {@code null} if
+   *         this DN is the Root DN.
+   */
+  public DN parent()
+  {
+    return parent;
+  }
+
+
+
+  /**
+   * Returns the DN which is equal to this DN with the specified number of RDNs
+   * removed. Note that if {@code index} is zero then this DN will be returned
+   * (identity).
+   *
+   * @param index
+   *          The number of RDNs to be removed.
+   * @return The DN which is equal to this DN with the specified number of RDNs
+   *         removed, or {@code null} if the parent of the Root DN is reached.
+   * @throws IllegalArgumentException
+   *           If {@code index} is less than zero.
+   */
+  public DN parent(final int index) throws IllegalArgumentException
+  {
+    // We allow size + 1 so that we can return null as the parent of the
+    // Root DN.
+    Validator.ensureTrue(index >= 0, "index less than zero");
+
+    DN parentDN = this;
+    for (int i = 0; parentDN != null && i < index; i++)
+    {
+      parentDN = parentDN.parent;
+    }
+    return parentDN;
+  }
+
+
+
+  /**
+   * Returns the RDN of this DN, or {@code null} if this DN is the Root DN.
+   *
+   * @return The RDN of this DN, or {@code null} if this DN is the Root DN.
+   */
+  public RDN rdn()
+  {
+    return rdn;
+  }
+
+
+
+  /**
+   * Returns the number of RDN components in this DN.
+   *
+   * @return The number of RDN components in this DN.
+   */
+  public int size()
+  {
+    return size;
+  }
+
+
+
+  /**
+   * Returns the RFC 4514 string representation of this DN.
+   *
+   * @return The RFC 4514 string representation of this DN.
+   * @see <a href="http://tools.ietf.org/html/rfc4514">RFC 4514 - Lightweight
+   *      Directory Access Protocol (LDAP): String Representation of
+   *      Distinguished Names </a>
+   */
+  @Override
+  public String toString()
+  {
+    // We don't care about potential race conditions here.
+    if (stringValue == null)
+    {
+      final StringBuilder builder = new StringBuilder();
+      rdn.toString(builder);
+      if (!parent.isRootDN())
+      {
+        builder.append(',');
+        builder.append(parent.toString());
+      }
+      stringValue = builder.toString();
+    }
+    return stringValue;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeException.java
new file mode 100644
index 0000000..c80bcae
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeException.java
@@ -0,0 +1,150 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.IOException;
+
+
+
+/**
+ * Thrown when data from an input source cannot be decoded, perhaps due to the
+ * data being malformed in some way. By default decoding exceptions are fatal,
+ * indicating that the associated input source is no longer usable.
+ */
+@SuppressWarnings("serial")
+public final class DecodeException extends IOException implements
+    LocalizableException
+{
+  /**
+   * Creates a new non-fatal decode exception with the provided message.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   * @return The new non-fatal decode exception.
+   */
+  public static DecodeException error(final LocalizableMessage message)
+  {
+    return new DecodeException(message, false, null);
+  }
+
+
+
+  /**
+   * Creates a new non-fatal decode exception with the provided message and root
+   * cause.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   * @param cause
+   *          The underlying cause of this exception.
+   * @return The new non-fatal decode exception.
+   */
+  public static DecodeException error(final LocalizableMessage message,
+      final Throwable cause)
+  {
+    return new DecodeException(message, false, cause);
+  }
+
+
+
+  /**
+   * Creates a new fatal decode exception with the provided message. The
+   * associated input source can no longer be used.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   * @return The new fatal decode exception.
+   */
+  public static DecodeException fatalError(final LocalizableMessage message)
+  {
+    return new DecodeException(message, true, null);
+  }
+
+
+
+  /**
+   * Creates a new fatal decode exception with the provided message and root
+   * cause. The associated input source can no longer be used.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   * @param cause
+   *          The underlying cause of this exception.
+   * @return The new fatal decode exception.
+   */
+  public static DecodeException fatalError(final LocalizableMessage message,
+      final Throwable cause)
+  {
+    return new DecodeException(message, true, cause);
+  }
+
+
+
+  private final LocalizableMessage message;
+
+  private final boolean isFatal;
+
+
+
+  // Construction is provided via factory methods.
+  private DecodeException(final LocalizableMessage message,
+      final boolean isFatal, final Throwable cause)
+  {
+    super(message.toString(), cause);
+    this.message = message;
+    this.isFatal = isFatal;
+  }
+
+
+
+  /**
+   * Returns the message that explains the problem that occurred.
+   *
+   * @return LocalizableMessage of the problem
+   */
+  public LocalizableMessage getMessageObject()
+  {
+    return message;
+  }
+
+
+
+  /**
+   * Indicates whether or not the error was fatal and the associated input
+   * source can no longer be used.
+   *
+   * @return {@code true} if the error was fatal and the associated input source
+   *         can no longer be used, otherwise {@code false} .
+   */
+  public boolean isFatal()
+  {
+    return isFatal;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeOptions.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeOptions.java
new file mode 100644
index 0000000..886191e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DecodeOptions.java
@@ -0,0 +1,241 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Decode options allow applications to control how requests and responses are
+ * decoded. In particular:
+ * <ul>
+ * <li>The strategy for selecting which {@code Schema} should be used for
+ * decoding distinguished names, attribute descriptions, and other objects which
+ * require a schema in order to be decoded.
+ * <li>The {@code Attribute} implementation which should be used when decoding
+ * attributes.
+ * <li>The {@code Entry} implementation which should be used when decoding
+ * entries or entry like objects.
+ * </ul>
+ */
+public final class DecodeOptions
+{
+  private static final class FixedSchemaResolver implements SchemaResolver
+  {
+    private final Schema schema;
+
+
+
+    private FixedSchemaResolver(final Schema schema)
+    {
+      this.schema = schema;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Schema resolveSchema(final String dn)
+    {
+      return schema;
+    }
+
+  }
+
+
+
+  private SchemaResolver schemaResolver;
+
+  private EntryFactory entryFactory;
+
+  private AttributeFactory attributeFactory;
+
+
+
+  /**
+   * Creates a new set of decode options which will always use the default
+   * schema returned by {@link Schema#getDefaultSchema()},
+   * {@link LinkedAttribute}, and {@link LinkedHashMapEntry}.
+   */
+  public DecodeOptions()
+  {
+    this.attributeFactory = LinkedAttribute.FACTORY;
+    this.entryFactory = LinkedHashMapEntry.FACTORY;
+    this.schemaResolver = new FixedSchemaResolver(Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Creates a new set of decode options having the same initial set of options
+   * as the provided set of decode options.
+   *
+   * @param options
+   *          The set of decode options to be copied.
+   */
+  public DecodeOptions(final DecodeOptions options)
+  {
+    this.attributeFactory = options.attributeFactory;
+    this.entryFactory = options.entryFactory;
+    this.schemaResolver = options.schemaResolver;
+  }
+
+
+
+  /**
+   * Returns the {@code AttributeFactory} which will be used for creating new
+   * {@code Attribute} instances when decoding attributes.
+   *
+   * @return The {@code AttributeFactory} which will be used for creating new
+   *         {@code Attribute} instances when decoding attributes.
+   */
+  public final AttributeFactory getAttributeFactory()
+  {
+    return attributeFactory;
+  }
+
+
+
+  /**
+   * Returns the {@code EntryFactory} which will be used for creating new
+   * {@code Entry} instances when decoding entries.
+   *
+   * @return The {@code EntryFactory} which will be used for creating new
+   *         {@code Entry} instances when decoding entries.
+   */
+  public final EntryFactory getEntryFactory()
+  {
+    return entryFactory;
+  }
+
+
+
+  /**
+   * Returns the strategy for selecting which {@code Schema} should be used for
+   * decoding distinguished names, attribute descriptions, and other objects
+   * which require a {@code Schema} in order to be decoded.
+   *
+   * @return The schema resolver which will be used for decoding.
+   */
+  public final SchemaResolver getSchemaResolver()
+  {
+    return schemaResolver;
+  }
+
+
+
+  /**
+   * Sets the {@code AttributeFactory} which will be used for creating new
+   * {@code Attribute} instances when decoding attributes.
+   *
+   * @param factory
+   *          The {@code AttributeFactory} which will be used for creating new
+   *          {@code Attribute} instances when decoding attributes.
+   * @return A reference to this set of decode options.
+   * @throws NullPointerException
+   *           If {@code factory} was {@code null}.
+   */
+  public final DecodeOptions setAttributeFactory(final AttributeFactory factory)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(factory);
+    this.attributeFactory = factory;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the {@code EntryFactory} which will be used for creating new {@code
+   * Entry} instances when decoding entries.
+   *
+   * @param factory
+   *          The {@code EntryFactory} which will be used for creating new
+   *          {@code Entry} instances when decoding entries.
+   * @return A reference to this set of decode options.
+   * @throws NullPointerException
+   *           If {@code factory} was {@code null}.
+   */
+  public final DecodeOptions setEntryFactory(final EntryFactory factory)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(factory);
+    this.entryFactory = factory;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the {@code Schema} which will be used for decoding distinguished
+   * names, attribute descriptions, and other objects which require a schema in
+   * order to be decoded. This setting overrides the currently active schema
+   * resolver set using {@link #setSchemaResolver}.
+   *
+   * @param schema
+   *          The {@code Schema} which will be used for decoding.
+   * @return A reference to this set of decode options.
+   * @throws NullPointerException
+   *           If {@code schema} was {@code null}.
+   */
+  public final DecodeOptions setSchema(final Schema schema)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(schema);
+    this.schemaResolver = new FixedSchemaResolver(schema);
+    return this;
+  }
+
+
+
+  /**
+   * Sets the strategy for selecting which {@code Schema} should be used for
+   * decoding distinguished names, attribute descriptions, and other objects
+   * which require a {@code Schema} in order to be decoded. This setting
+   * overrides the currently active schema set using {@link #setSchema}.
+   *
+   * @param resolver
+   *          The {@code SchemaResolver} which will be used for decoding.
+   * @return A reference to this set of decode options.
+   * @throws NullPointerException
+   *           If {@code resolver} was {@code null}.
+   */
+  public final DecodeOptions setSchemaResolver(final SchemaResolver resolver)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(resolver);
+    this.schemaResolver = resolver;
+    return this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DereferenceAliasesPolicy.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DereferenceAliasesPolicy.java
new file mode 100644
index 0000000..3bd0309
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/DereferenceAliasesPolicy.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * A Search operation alias dereferencing policy as defined in RFC 4511 section
+ * 4.5.1.3 is used to indicate whether or not alias entries (as defined in RFC
+ * 4512) are to be dereferenced during stages of a Search operation. The act of
+ * dereferencing an alias includes recursively dereferencing aliases that refer
+ * to aliases.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.5.1.3">RFC 4511 -
+ *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
+ *      Directory Access Protocol (LDAP): Directory Information Models </a>
+ */
+public final class DereferenceAliasesPolicy
+{
+  private static final DereferenceAliasesPolicy[] ELEMENTS = new DereferenceAliasesPolicy[4];
+
+  private static final List<DereferenceAliasesPolicy> IMMUTABLE_ELEMENTS = Collections
+      .unmodifiableList(Arrays.asList(ELEMENTS));
+
+  /**
+   * Do not dereference aliases in searching or in locating the base object of a
+   * Search operation.
+   */
+  public static final DereferenceAliasesPolicy NEVER = register(0, "never");
+
+  /**
+   * While searching subordinates of the base object, dereference any alias
+   * within the scope of the Search operation. Dereferenced objects become the
+   * vertices of further search scopes where the Search operation is also
+   * applied. If the search scope is {@code WHOLE_SUBTREE}, the Search continues
+   * in the subtree(s) of any dereferenced object. If the search scope is
+   * {@code SINGLE_LEVEL}, the search is applied to any dereferenced objects and
+   * is not applied to their subordinates.
+   */
+  public static final DereferenceAliasesPolicy IN_SEARCHING = register(1,
+      "search");
+
+  /**
+   * Dereference aliases in locating the base object of a Search operation, but
+   * not when searching subordinates of the base object.
+   */
+  public static final DereferenceAliasesPolicy FINDING_BASE = register(2,
+      "find");
+
+  /**
+   * Dereference aliases both in searching and in locating the base object of a
+   * Search operation.
+   */
+  public static final DereferenceAliasesPolicy ALWAYS = register(3, "always");
+
+
+
+  /**
+   * Returns the alias dereferencing policy having the specified integer value
+   * as defined in RFC 4511 section 4.5.1.
+   *
+   * @param intValue
+   *          The integer value of the alias dereferencing policy.
+   * @return The dereference aliases policy, or {@code null} if there was no
+   *         alias dereferencing policy associated with {@code intValue}.
+   */
+  public static DereferenceAliasesPolicy valueOf(final int intValue)
+  {
+    if (intValue < 0 || intValue >= ELEMENTS.length)
+    {
+      return null;
+    }
+    return ELEMENTS[intValue];
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the set of available alias
+   * dereferencing policies indexed on their integer value as defined in RFC
+   * 4511 section 4.5.1.
+   *
+   * @return An unmodifiable list containing the set of available alias
+   *         dereferencing policies.
+   */
+  public static List<DereferenceAliasesPolicy> values()
+  {
+    return IMMUTABLE_ELEMENTS;
+  }
+
+
+
+  /**
+   * Creates and registers a new alias dereferencing policy with the
+   * application.
+   *
+   * @param intValue
+   *          The integer value of the alias dereferencing policy as defined in
+   *          RFC 4511 section 4.5.1.
+   * @param name
+   *          The name of the alias dereferencing policy.
+   * @return The new alias dereferencing policy.
+   */
+  private static DereferenceAliasesPolicy register(final int intValue,
+      final String name)
+  {
+    final DereferenceAliasesPolicy t = new DereferenceAliasesPolicy(intValue,
+        name);
+    ELEMENTS[intValue] = t;
+    return t;
+  }
+
+
+
+  private final int intValue;
+
+  private final String name;
+
+
+
+  // Prevent direct instantiation.
+  private DereferenceAliasesPolicy(final int intValue, final String name)
+  {
+    this.intValue = intValue;
+    this.name = name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    else if (obj instanceof DereferenceAliasesPolicy)
+    {
+      return this.intValue == ((DereferenceAliasesPolicy) obj).intValue;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Returns the integer value of this alias dereferencing policy as defined in
+   * RFC 4511 section 4.5.1.
+   *
+   * @return The integer value of this alias dereferencing policy.
+   */
+  public int intValue()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Returns the string representation of this alias dereferencing policy.
+   *
+   * @return The string representation of this alias dereferencing policy.
+   */
+  @Override
+  public String toString()
+  {
+    return name;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entries.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entries.java
new file mode 100644
index 0000000..821aea3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entries.java
@@ -0,0 +1,515 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.opends.sdk.requests.ModifyRequest;
+import org.opends.sdk.requests.Requests;
+
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Iterables;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class contains methods for creating and manipulating entries.
+ *
+ * @see Entry
+ */
+public final class Entries
+{
+
+  private static final class UnmodifiableEntry implements Entry
+  {
+    private final Entry entry;
+
+
+
+    private UnmodifiableEntry(final Entry entry)
+    {
+      this.entry = entry;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean addAttribute(final Attribute attribute)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean addAttribute(final Attribute attribute,
+        final Collection<ByteString> duplicateValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Entry addAttribute(final String attributeDescription,
+        final Object... values) throws LocalizedIllegalArgumentException,
+        UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public Entry clearAttributes() throws UnsupportedOperationException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public boolean containsAttribute(final Attribute attribute,
+        final Collection<ByteString> missingValues) throws NullPointerException
+    {
+      return entry.containsAttribute(attribute, missingValues);
+    }
+
+
+
+    @Override
+    public boolean containsAttribute(final String attributeDescription,
+        final Object... values) throws LocalizedIllegalArgumentException,
+        NullPointerException
+    {
+      return entry.containsAttribute(attributeDescription, values);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(final Object object)
+    {
+      return (object == this || entry.equals(object));
+    }
+
+
+
+    @Override
+    public Iterable<Attribute> getAllAttributes()
+    {
+      return Iterables.unmodifiableIterable(Iterables.transformedIterable(
+          entry.getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+    }
+
+
+
+    @Override
+    public Iterable<Attribute> getAllAttributes(
+        final AttributeDescription attributeDescription)
+    {
+      return Iterables.unmodifiableIterable(Iterables.transformedIterable(
+          entry.getAllAttributes(attributeDescription),
+          UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterable<Attribute> getAllAttributes(
+        final String attributeDescription)
+        throws LocalizedIllegalArgumentException, NullPointerException
+    {
+      return Iterables.unmodifiableIterable(Iterables.transformedIterable(
+          entry.getAllAttributes(attributeDescription),
+          UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+    }
+
+
+
+    @Override
+    public Attribute getAttribute(
+        final AttributeDescription attributeDescription)
+    {
+      final Attribute attribute = entry.getAttribute(attributeDescription);
+      if (attribute != null)
+      {
+        return Attributes.unmodifiableAttribute(attribute);
+      }
+      else
+      {
+        return null;
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Attribute getAttribute(final String attributeDescription)
+        throws LocalizedIllegalArgumentException, NullPointerException
+    {
+      final Attribute attribute = entry.getAttribute(attributeDescription);
+      if (attribute != null)
+      {
+        return Attributes.unmodifiableAttribute(attribute);
+      }
+      else
+      {
+        return null;
+      }
+    }
+
+
+
+    @Override
+    public int getAttributeCount()
+    {
+      return entry.getAttributeCount();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public DN getName()
+    {
+      return entry.getName();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+      return entry.hashCode();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean removeAttribute(final Attribute attribute,
+        final Collection<ByteString> missingValues)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public boolean removeAttribute(
+        final AttributeDescription attributeDescription)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Entry removeAttribute(final String attributeDescription,
+        final Object... values) throws LocalizedIllegalArgumentException,
+        UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean replaceAttribute(final Attribute attribute)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Entry replaceAttribute(final String attributeDescription,
+        final Object... values) throws LocalizedIllegalArgumentException,
+        UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public Entry setName(final DN dn) throws UnsupportedOperationException,
+        NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Entry setName(final String dn)
+        throws LocalizedIllegalArgumentException,
+        UnsupportedOperationException, NullPointerException
+    {
+      throw new UnsupportedOperationException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+      return entry.toString();
+    }
+
+  }
+
+
+
+  private static final Function<Attribute, Attribute, Void> UNMODIFIABLE_ATTRIBUTE_FUNCTION =
+    new Function<Attribute, Attribute, Void>()
+  {
+
+    @Override
+    public Attribute apply(final Attribute value, final Void p)
+    {
+      return Attributes.unmodifiableAttribute(value);
+    }
+
+  };
+
+
+
+  /**
+   * Creates a new modify request containing a list of modifications which can
+   * be used to transform {@code fromEntry} into entry {@code toEntry}.
+   * <p>
+   * The modify request is reversible: it will contain only modifications of
+   * type {@link ModificationType#ADD ADD} and {@link ModificationType#DELETE
+   * DELETE}.
+   * <p>
+   * Finally, the modify request will use the distinguished name taken from
+   * {@code fromEntry}. Moreover, this method will not check to see if both
+   * {@code fromEntry} and {@code toEntry} have the same distinguished name.
+   * <p>
+   * This method is equivalent to:
+   *
+   * <pre>
+   * ModifyRequest request = Requests.newModifyRequest(fromEntry, toEntry);
+   * </pre>
+   *
+   * @param fromEntry
+   *          The source entry.
+   * @param toEntry
+   *          The destination entry.
+   * @return A modify request containing a list of modifications which can be
+   *         used to transform {@code fromEntry} into entry {@code toEntry}.
+   * @throws NullPointerException
+   *           If {@code fromEntry} or {@code toEntry} were {@code null}.
+   * @see Requests#newModifyRequest(Entry, Entry)
+   */
+  public static final ModifyRequest diffEntries(final Entry fromEntry,
+      final Entry toEntry) throws NullPointerException
+  {
+    Validator.ensureNotNull(fromEntry, toEntry);
+
+    final ModifyRequest request = Requests
+        .newModifyRequest(fromEntry.getName());
+
+    TreeMapEntry tfrom;
+    if (fromEntry instanceof TreeMapEntry)
+    {
+      tfrom = (TreeMapEntry) fromEntry;
+    }
+    else
+    {
+      tfrom = new TreeMapEntry(fromEntry);
+    }
+
+    TreeMapEntry tto;
+    if (toEntry instanceof TreeMapEntry)
+    {
+      tto = (TreeMapEntry) toEntry;
+    }
+    else
+    {
+      tto = new TreeMapEntry(toEntry);
+    }
+
+    final Iterator<Attribute> ifrom = tfrom.getAllAttributes().iterator();
+    final Iterator<Attribute> ito = tto.getAllAttributes().iterator();
+
+    Attribute afrom = ifrom.hasNext() ? ifrom.next() : null;
+    Attribute ato = ito.hasNext() ? ito.next() : null;
+
+    while (afrom != null && ato != null)
+    {
+      final AttributeDescription adfrom = afrom.getAttributeDescription();
+      final AttributeDescription adto = ato.getAttributeDescription();
+
+      final int cmp = adfrom.compareTo(adto);
+      if (cmp == 0)
+      {
+        // Attribute is in both entries. Compute the set of values to be added
+        // and removed. We won't replace the attribute because this is not
+        // reversible.
+        final Attribute addedValues = new LinkedAttribute(ato);
+        addedValues.removeAll(afrom);
+        if (!addedValues.isEmpty())
+        {
+          request.addModification(new Modification(ModificationType.ADD,
+              addedValues));
+        }
+
+        final Attribute deletedValues = new LinkedAttribute(afrom);
+        deletedValues.removeAll(ato);
+        if (!deletedValues.isEmpty())
+        {
+          request.addModification(new Modification(ModificationType.DELETE,
+              deletedValues));
+        }
+
+        afrom = ifrom.hasNext() ? ifrom.next() : null;
+        ato = ito.hasNext() ? ito.next() : null;
+      }
+      else if (cmp < 0)
+      {
+        // afrom in source, but not destination.
+        request
+            .addModification(new Modification(ModificationType.DELETE, afrom));
+        afrom = ifrom.hasNext() ? ifrom.next() : null;
+      }
+      else
+      {
+        // ato in destination, but not in source.
+        request.addModification(new Modification(ModificationType.ADD, ato));
+        ato = ito.hasNext() ? ito.next() : null;
+      }
+    }
+
+    // Additional attributes in source entry: these must be deleted.
+    if (afrom != null)
+    {
+      request.addModification(new Modification(ModificationType.DELETE, afrom));
+    }
+
+    while (ifrom.hasNext())
+    {
+      final Attribute a = ifrom.next();
+      request.addModification(new Modification(ModificationType.DELETE, a));
+    }
+
+    // Additional attributes in destination entry: these must be added.
+    if (ato != null)
+    {
+      request.addModification(new Modification(ModificationType.ADD, ato));
+    }
+
+    while (ito.hasNext())
+    {
+      final Attribute a = ito.next();
+      request.addModification(new Modification(ModificationType.ADD, a));
+    }
+
+    return request;
+  }
+
+
+
+  /**
+   * Returns a read-only view of {@code entry} and its attributes. Query
+   * operations on the returned entry and its attributes "read-through" to the
+   * underlying entry or attribute, and attempts to modify the returned entry
+   * and its attributes either directly or indirectly via an iterator result in
+   * an {@code UnsupportedOperationException}.
+   *
+   * @param entry
+   *          The entry for which a read-only view is to be returned.
+   * @return A read-only view of {@code entry}.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public static final Entry unmodifiableEntry(final Entry entry)
+      throws NullPointerException
+  {
+    return new UnmodifiableEntry(entry);
+  }
+
+
+
+  // Prevent instantiation.
+  private Entries()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entry.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entry.java
new file mode 100644
index 0000000..9a573e9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Entry.java
@@ -0,0 +1,550 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+
+
+
+/**
+ * An entry, comprising of a distinguished name and zero or more attributes.
+ * <p>
+ * Some methods require a schema in order to decode their parameters (e.g.
+ * {@link #addAttribute(String, Object...)} and {@link #setName(String)}). In
+ * these cases the default schema is used unless an alternative schema is
+ * specified in the {@code Entry} constructor. The default schema is not used
+ * for any other purpose. In particular, an {@code Entry} will permit attributes
+ * to be added which have been decoded using multiple schemas.
+ * <p>
+ * Full LDAP modify semantics are provided via the {@link #addAttribute},
+ * {@link #removeAttribute}, and {@link #replaceAttribute} methods.
+ * <p>
+ * Implementations should specify any constraints or special behavior.
+ * Specifically:
+ * <ul>
+ * <li>Which methods are supported.
+ * <li>The order in which attributes are returned using the
+ * {@link #getAllAttributes()} method.
+ * <li>How existing attributes are modified during calls to
+ * {@link #addAttribute}, {@link #removeAttribute}, and
+ * {@link #replaceAttribute} and the conditions, if any, where a reference to
+ * the passed in attribute is maintained.
+ * </ul>
+ *
+ * @see Entries
+ */
+public interface Entry
+{
+
+  /**
+   * Ensures that this entry contains the provided attribute and values
+   * (optional operation). This method has the following semantics:
+   * <ul>
+   * <li>If this entry does not already contain an attribute with the same
+   * attribute description, then this entry will be modified such that it
+   * contains {@code attribute}, even if it is empty.
+   * <li>If this entry already contains an attribute with the same attribute
+   * description, then the attribute values contained in {@code attribute} will
+   * be merged with the existing attribute values.
+   * </ul>
+   * <p>
+   * <b>NOTE:</b> When {@code attribute} is non-empty, this method implements
+   * LDAP Modify add semantics.
+   *
+   * @param attribute
+   *          The attribute values to be added to this entry, merging with any
+   *          existing attribute values.
+   * @return {@code true} if this entry changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes or their values to be
+   *           added.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  boolean addAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Ensures that this entry contains the provided attribute and values
+   * (optional operation). This method has the following semantics:
+   * <ul>
+   * <li>If this entry does not already contain an attribute with the same
+   * attribute description, then this entry will be modified such that it
+   * contains {@code attribute}, even if it is empty.
+   * <li>If this entry already contains an attribute with the same attribute
+   * description, then the attribute values contained in {@code attribute} will
+   * be merged with the existing attribute values.
+   * </ul>
+   * <p>
+   * <b>NOTE:</b> When {@code attribute} is non-empty, this method implements
+   * LDAP Modify add semantics.
+   *
+   * @param attribute
+   *          The attribute values to be added to this entry, merging with any
+   *          existing attribute values.
+   * @param duplicateValues
+   *          A collection into which duplicate values will be added, or {@code
+   *          null} if duplicate values should not be saved.
+   * @return {@code true} if this entry changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes or their values to be
+   *           added.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  boolean addAttribute(Attribute attribute,
+      Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Ensures that this entry contains the provided attribute and values
+   * (optional operation). This method has the following semantics:
+   * <ul>
+   * <li>If this entry does not already contain an attribute with the same
+   * attribute description, then this entry will be modified such that it
+   * contains {@code attribute}, even if it is empty.
+   * <li>If this entry already contains an attribute with the same attribute
+   * description, then the attribute values contained in {@code attribute} will
+   * be merged with the existing attribute values.
+   * </ul>
+   * <p>
+   * The attribute description will be decoded using the schema associated with
+   * this entry (usually the default schema).
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   * <p>
+   * <b>NOTE:</b> When {@code attribute} is non-empty, this method implements
+   * LDAP Modify add semantics.
+   *
+   * @param attributeDescription
+   *          The name of the attribute whose values are to be added.
+   * @param values
+   *          The attribute values to be added to this entry, merging any
+   *          existing attribute values.
+   * @return This entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           schema associated with this entry.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes or their values to be
+   *           added.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  Entry addAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Removes all the attributes from this entry (optional operation).
+   *
+   * @return This entry.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes to be removed.
+   */
+  Entry clearAttributes() throws UnsupportedOperationException;
+
+
+
+  /**
+   * Returns {@code true} if this entry contains all of the attribute values
+   * contained in {@code attribute}. If {@code attribute} is empty then this
+   * method will return {@code true} if the attribute is present in this entry,
+   * regardless of how many values it contains.
+   *
+   * @param attribute
+   *          The attribute values whose presence in this entry is to be tested.
+   * @param missingValues
+   *          A collection into which missing values will be added, or {@code
+   *          null} if missing values should not be saved.
+   * @return {@code true} if this entry contains all of the attribute values
+   *         contained in {@code attribute}.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  boolean containsAttribute(Attribute attribute,
+      Collection<ByteString> missingValues) throws NullPointerException;
+
+
+
+  /**
+   * Returns {@code true} if this entry contains all of the attribute values
+   * contained in {@code values}. If {@code values} is {@code null} or empty
+   * then this method will return {@code true} if the attribute is present in
+   * this entry, regardless of how many values it contains.
+   * <p>
+   * The attribute description will be decoded using the schema associated with
+   * this entry (usually the default schema).
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The name of the attribute whose presence in this entry is to be
+   *          tested.
+   * @param values
+   *          The attribute values whose presence in this entry is to be tested,
+   *          which may be {@code null}.
+   * @return {@code true} if this entry contains all of the attribute values
+   *         contained in {@code values}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           schema associated with this entry.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  boolean containsAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * Returns {@code true} if {@code object} is an entry which is equal to this
+   * entry. Two entries are considered equal if their distinguished names are
+   * equal, they both have the same number of attributes, and every attribute
+   * contained in the first entry is also contained in the second entry.
+   *
+   * @param object
+   *          The object to be tested for equality with this entry.
+   * @return {@code true} if {@code object} is an entry which is equal to this
+   *         entry, or {@code false} if not.
+   */
+  boolean equals(Object object);
+
+
+
+  /**
+   * Returns an {@code Iterable} containing all of the attributes in this entry.
+   * The returned {@code Iterable} may be used to remove attributes if permitted
+   * by this entry.
+   *
+   * @return An {@code Iterable} containing all of the attributes.
+   */
+  Iterable<Attribute> getAllAttributes();
+
+
+
+  /**
+   * Returns an {@code Iterable} containing all the attributes in this entry
+   * having an attribute description which is a sub-type of the provided
+   * attribute description. The returned {@code Iterable} may be used to remove
+   * attributes if permitted by this entry.
+   *
+   * @param attributeDescription
+   *          The name of the attributes to be returned.
+   * @return An {@code Iterable} containing the matching attributes.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  Iterable<Attribute> getAllAttributes(AttributeDescription attributeDescription)
+      throws NullPointerException;
+
+
+
+  /**
+   * Returns an {@code Iterable} containing all the attributes in this entry
+   * having an attribute description which is a sub-type of the provided
+   * attribute description. The returned {@code Iterable} may be used to remove
+   * attributes if permitted by this entry.
+   * <p>
+   * The attribute description will be decoded using the schema associated with
+   * this entry (usually the default schema).
+   *
+   * @param attributeDescription
+   *          The name of the attributes to be returned.
+   * @return An {@code Iterable} containing the matching attributes.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           schema associated with this entry.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  Iterable<Attribute> getAllAttributes(String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * Returns the named attribute contained in this entry, or {@code null} if it
+   * is not included with this entry.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be returned.
+   * @return The named attribute, or {@code null} if it is not included with
+   *         this entry.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  Attribute getAttribute(AttributeDescription attributeDescription)
+      throws NullPointerException;
+
+
+
+  /**
+   * Returns the named attribute contained in this entry, or {@code null} if it
+   * is not included with this entry.
+   * <p>
+   * The attribute description will be decoded using the schema associated with
+   * this entry (usually the default schema).
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be returned.
+   * @return The named attribute, or {@code null} if it is not included with
+   *         this entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           schema associated with this entry.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  Attribute getAttribute(String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * Returns the number of attributes in this entry.
+   *
+   * @return The number of attributes.
+   */
+  int getAttributeCount();
+
+
+
+  /**
+   * Returns the string representation of the distinguished name of this entry.
+   *
+   * @return The string representation of the distinguished name.
+   */
+  DN getName();
+
+
+
+  /**
+   * Returns the hash code for this entry. It will be calculated as the sum of
+   * the hash codes of the distinguished name and all of the attributes.
+   *
+   * @return The hash code for this entry.
+   */
+  int hashCode();
+
+
+
+  /**
+   * Removes all of the attribute values contained in {@code attribute} from
+   * this entry if it is present (optional operation). If {@code attribute} is
+   * empty then the entire attribute will be removed if it is present.
+   * <p>
+   * <b>NOTE:</b> This method implements LDAP Modify delete semantics.
+   *
+   * @param attribute
+   *          The attribute values to be removed from this entry, which may be
+   *          empty if the entire attribute is to be removed.
+   * @param missingValues
+   *          A collection into which missing values will be added, or {@code
+   *          null} if missing values should not be saved.
+   * @return {@code true} if this entry changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes or their values to be
+   *           removed.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  boolean removeAttribute(Attribute attribute,
+      Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Removes the named attribute from this entry if it is present (optional
+   * operation). If this attribute does not contain the attribute, the call
+   * leaves this entry unchanged and returns {@code false}.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be removed.
+   * @return {@code true} if this entry changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes to be removed.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  boolean removeAttribute(AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Removes all of the attribute values contained in {@code values} from the
+   * named attribute in this entry if it is present (optional operation). If
+   * {@code values} is {@code null} or empty then the entire attribute will be
+   * removed if it is present.
+   * <p>
+   * The attribute description will be decoded using the schema associated with
+   * this entry (usually the default schema).
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   * <p>
+   * <b>NOTE:</b> This method implements LDAP Modify delete semantics.
+   *
+   * @param attributeDescription
+   *          The name of the attribute whose values are to be removed.
+   * @param values
+   *          The attribute values to be removed from this entry, which may be
+   *          {@code null} or empty if the entire attribute is to be removed.
+   * @return This entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           schema associated with this entry.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes or their values to be
+   *           removed.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  Entry removeAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Adds all of the attribute values contained in {@code attribute} to this
+   * entry, replacing any existing attribute values (optional operation). If
+   * {@code attribute} is empty then the entire attribute will be removed if it
+   * is present.
+   * <p>
+   * <b>NOTE:</b> This method implements LDAP Modify replace semantics.
+   *
+   * @param attribute
+   *          The attribute values to be added to this entry, replacing any
+   *          existing attribute values, and which may be empty if the entire
+   *          attribute is to be removed.
+   * @return {@code true} if this entry changed as a result of this call.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes or their values to be
+   *           replaced.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  boolean replaceAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Adds all of the attribute values contained in {@code values} to this entry,
+   * replacing any existing attribute values (optional operation). If {@code
+   * values} is {@code null} or empty then the entire attribute will be removed
+   * if it is present.
+   * <p>
+   * The attribute description will be decoded using the schema associated with
+   * this entry (usually the default schema).
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   * <p>
+   * <b>NOTE:</b> This method implements LDAP Modify replace semantics.
+   *
+   * @param attributeDescription
+   *          The name of the attribute whose values are to be replaced.
+   * @param values
+   *          The attribute values to be added to this entry, replacing any
+   *          existing attribute values, and which may be {@code null} or empty
+   *          if the entire attribute is to be removed.
+   * @return This entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           schema associated with this entry.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit attributes or their values to be
+   *           replaced.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  Entry replaceAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of this entry (optional operation).
+   *
+   * @param dn
+   *          The distinguished name.
+   * @return This entry.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit the distinguished name to be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  Entry setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of this entry (optional operation).
+   * <p>
+   * The distinguished name will be decoded using the schema associated with
+   * this entry (usually the default schema).
+   *
+   * @param dn
+   *          The string representation of the distinguished name.
+   * @return This entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} could not be decoded using the schema associated
+   *           with this entry.
+   * @throws UnsupportedOperationException
+   *           If this entry does not permit the distinguished name to be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  Entry setName(String dn) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Returns a string representation of this entry.
+   *
+   * @return The string representation of this entry.
+   */
+  String toString();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryFactory.java
new file mode 100644
index 0000000..2c4b2e6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryFactory.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * Entry factories are included with a set of {@code DecodeOptions} in order to
+ * allow application to control how {@code Entry} instances are created when
+ * decoding requests and responses.
+ *
+ * @see Entry
+ * @see DecodeOptions
+ */
+public interface EntryFactory
+{
+  /**
+   * Creates an empty entry using the provided distinguished name and no
+   * attributes.
+   *
+   * @param name
+   *          The distinguished name of the entry to be created.
+   * @return The new entry.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  Entry newEntry(DN name) throws NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryNotFoundException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryNotFoundException.java
new file mode 100644
index 0000000..31f7de8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/EntryNotFoundException.java
@@ -0,0 +1,60 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * failed because the target entry was not found by the Directory Server. More
+ * specifically, this exception is used for the following error result codes:
+ * <ul>
+ * <li>{@link ResultCode#NO_SUCH_OBJECT NO_SUCH_OBJECT} - the requested
+ * operation failed because it referenced an entry that does not exist.
+ * <li>{@link ResultCode#REFERRAL REFERRAL} - the requested operation failed
+ * because it referenced an entry that is located on another server.
+ * <li>{@link ResultCode#CLIENT_SIDE_NO_RESULTS_RETURNED
+ * CLIENT_SIDE_NO_RESULTS_RETURNED} - the requested single entry search
+ * operation or read operation failed because the Directory Server did not
+ * return any matching entries.
+ * </ul>
+ * <b>NOTE:</b> referrals are handled by the {@link ReferralException}
+ * sub-class.
+ */
+@SuppressWarnings("serial")
+public class EntryNotFoundException extends ErrorResultException
+{
+  EntryNotFoundException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultException.java
new file mode 100644
index 0000000..6d57f82
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultException.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.concurrent.ExecutionException;
+
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * was unsuccessful.
+ */
+@SuppressWarnings("serial")
+public class ErrorResultException extends ExecutionException
+{
+
+  /**
+   * Creates a new error result exception with the provided result code and
+   * diagnostic message.
+   *
+   * @param resultCode
+   *          The result code.
+   * @param diagnosticMessage
+   *          The diagnostic message, which may be empty or {@code null}
+   *          indicating that none was provided.
+   * @return The new error result exception.
+   * @throws IllegalArgumentException
+   *           If the provided result code does not represent a failure.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static ErrorResultException newErrorResult(ResultCode resultCode,
+      String diagnosticMessage) throws IllegalArgumentException,
+      NullPointerException
+  {
+    return newErrorResult(resultCode, diagnosticMessage, null);
+  }
+
+
+
+  /**
+   * Creates a new error result exception with the provided result code,
+   * diagnostic message, and cause.
+   *
+   * @param resultCode
+   *          The result code.
+   * @param diagnosticMessage
+   *          The diagnostic message, which may be empty or {@code null}
+   *          indicating that none was provided.
+   * @param cause
+   *          The throwable cause, which may be null indicating that none was
+   *          provided.
+   * @return The new error result exception.
+   * @throws IllegalArgumentException
+   *           If the provided result code does not represent a failure.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static ErrorResultException newErrorResult(ResultCode resultCode,
+      String diagnosticMessage, Throwable cause)
+      throws IllegalArgumentException, NullPointerException
+  {
+    Result result = Responses.newResult(resultCode)
+        .setDiagnosticMessage(diagnosticMessage).setCause(cause);
+    return wrap(result);
+  }
+
+
+
+  /**
+   * Wraps the provided result in an appropriate error result exception. The
+   * type of error result exception used depends on the underlying result code.
+   *
+   * @param result
+   *          The result whose result code indicates a failure.
+   * @return The error result exception wrapping the provided result.
+   * @throws IllegalArgumentException
+   *           If the provided result does not represent a failure.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static ErrorResultException wrap(final Result result)
+      throws IllegalArgumentException, NullPointerException
+  {
+    if (!result.getResultCode().isExceptional())
+    {
+      throw new IllegalArgumentException(
+          "Attempted to wrap a successful result: " + result);
+    }
+
+    ResultCode rc = result.getResultCode();
+    if (rc == ResultCode.ASSERTION_FAILED)
+    {
+      return new AssertionFailureException(result);
+    }
+    else if (rc == ResultCode.AUTH_METHOD_NOT_SUPPORTED
+        || rc == ResultCode.CLIENT_SIDE_AUTH_UNKNOWN
+        || rc == ResultCode.INAPPROPRIATE_AUTHENTICATION
+        || rc == ResultCode.INVALID_CREDENTIALS)
+    {
+      return new AuthenticationException(result);
+    }
+    else if (rc == ResultCode.AUTHORIZATION_DENIED
+        || rc == ResultCode.CONFIDENTIALITY_REQUIRED
+        || rc == ResultCode.INSUFFICIENT_ACCESS_RIGHTS
+        || rc == ResultCode.STRONG_AUTH_REQUIRED)
+    {
+      return new AuthorizationException(result);
+    }
+    else if (rc == ResultCode.CLIENT_SIDE_USER_CANCELLED
+        || rc == ResultCode.CANCELLED)
+    {
+      return new CancelledResultException(result);
+    }
+    else if (rc == ResultCode.CLIENT_SIDE_SERVER_DOWN
+        || rc == ResultCode.CLIENT_SIDE_CONNECT_ERROR
+        || rc == ResultCode.CLIENT_SIDE_DECODING_ERROR
+        || rc == ResultCode.CLIENT_SIDE_ENCODING_ERROR)
+    {
+      return new ConnectionException(result);
+    }
+    else if (rc == ResultCode.ATTRIBUTE_OR_VALUE_EXISTS
+        || rc == ResultCode.CONSTRAINT_VIOLATION
+        || rc == ResultCode.ENTRY_ALREADY_EXISTS
+        || rc == ResultCode.INVALID_ATTRIBUTE_SYNTAX
+        || rc == ResultCode.INVALID_DN_SYNTAX
+        || rc == ResultCode.NAMING_VIOLATION
+        || rc == ResultCode.NOT_ALLOWED_ON_NONLEAF
+        || rc == ResultCode.NOT_ALLOWED_ON_RDN
+        || rc == ResultCode.OBJECTCLASS_MODS_PROHIBITED
+        || rc == ResultCode.OBJECTCLASS_VIOLATION
+        || rc == ResultCode.UNDEFINED_ATTRIBUTE_TYPE)
+    {
+      return new ConstraintViolationException(result);
+    }
+    else if (rc == ResultCode.REFERRAL)
+    {
+      return new ReferralException(result);
+    }
+    else if (rc == ResultCode.NO_SUCH_OBJECT
+        || rc == ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED)
+    {
+      return new EntryNotFoundException(result);
+    }
+    else if (rc == ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED)
+    {
+      return new MultipleEntriesFoundException(result);
+    }
+    else if (rc == ResultCode.CLIENT_SIDE_TIMEOUT
+        || rc == ResultCode.TIME_LIMIT_EXCEEDED)
+    {
+      return new TimeoutResultException(result);
+    }
+
+    return new ErrorResultException(result);
+  }
+
+
+
+  private final Result result;
+
+
+
+  /**
+   * Creates a new error result exception using the provided result.
+   *
+   * @param result
+   *          The error result.
+   */
+  ErrorResultException(final Result result)
+  {
+    super(result.getResultCode() + ": " + result.getDiagnosticMessage());
+    this.result = result;
+  }
+
+
+
+  /**
+   * Returns the error result which caused this exception to be thrown. The type
+   * of result returned corresponds to the expected result type of the original
+   * request.
+   *
+   * @return The error result which caused this exception to be thrown.
+   */
+  public Result getResult()
+  {
+    return result;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultIOException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultIOException.java
new file mode 100644
index 0000000..7366bbd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ErrorResultIOException.java
@@ -0,0 +1,76 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.IOException;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An {@code ErrorResultIOException} adapts an {@code ErrorResultException} to
+ * an {@code IOException}.
+ */
+@SuppressWarnings("serial")
+public final class ErrorResultIOException extends IOException
+{
+  private final ErrorResultException cause;
+
+
+
+  /**
+   * Creates a new error result IO exception with the provided cause.
+   *
+   * @param cause
+   *          The cause which may be later retrieved by the {@link #getCause}
+   *          method.
+   * @throws NullPointerException
+   *           If {@code cause} was {@code null}.
+   */
+  public ErrorResultIOException(final ErrorResultException cause)
+      throws NullPointerException
+  {
+    super(Validator.ensureNotNull(cause));
+
+    this.cause = cause;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ErrorResultException getCause()
+  {
+    return cause;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FailoverLoadBalancingAlgorithm.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FailoverLoadBalancingAlgorithm.java
new file mode 100644
index 0000000..11f21d4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FailoverLoadBalancingAlgorithm.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+
+
+/**
+ * A fail-over load balancing algorithm provides fault tolerance across multiple
+ * underlying connection factories.
+ * <p>
+ * This algorithm is typically used for load-balancing <i>between</i> data
+ * centers, where there is preference to always always forward connection
+ * requests to the <i>closest available</i> data center. This algorithm
+ * contrasts with the {@link RoundRobinLoadBalancingAlgorithm} which is used for
+ * load-balancing <i>within</i> a data center.
+ * <p>
+ * This algorithm selects connection factories based on the order in which they
+ * were provided during construction. More specifically, an attempt to obtain a
+ * connection factory will always return the <i>first operational</i> connection
+ * factory in the list. Applications should, therefore, organize the connection
+ * factories such that the <i>preferred</i> (usually the closest) connection
+ * factories appear before those which are less preferred.
+ * <p>
+ * If a problem occurs that temporarily prevents connections from being obtained
+ * for one of the connection factories, then this algorithm automatically
+ * "fails over" to the next operational connection factory in the list. If none
+ * of the connection factories are operational then a
+ * {@code ConnectionException} is returned to the client.
+ * <p>
+ * The implementation periodically attempts to connect to failed connection
+ * factories in order to determine if they have become available again.
+ *
+ * @see RoundRobinLoadBalancingAlgorithm
+ * @see Connections#newLoadBalancer(LoadBalancingAlgorithm)
+ */
+public final class FailoverLoadBalancingAlgorithm extends
+    AbstractLoadBalancingAlgorithm
+{
+
+  /**
+   * Creates a new fail-over load balancing algorithm which will monitor offline
+   * connection factories every 1 second using the default scheduler.
+   *
+   * @param factories
+   *          The ordered collection of connection factories.
+   */
+  public FailoverLoadBalancingAlgorithm(
+      final Collection<ConnectionFactory> factories)
+  {
+    super(factories);
+  }
+
+
+
+  /**
+   * Creates a new fail-over load balancing algorithm which will monitor offline
+   * connection factories using the specified frequency using the default
+   * scheduler.
+   *
+   * @param factories
+   *          The connection factories.
+   * @param interval
+   *          The interval between attempts to poll offline factories.
+   * @param unit
+   *          The time unit for the interval between attempts to poll offline
+   *          factories.
+   */
+  public FailoverLoadBalancingAlgorithm(
+      final Collection<ConnectionFactory> factories, final long interval,
+      final TimeUnit unit)
+  {
+    super(factories, interval, unit);
+  }
+
+
+
+  /**
+   * Creates a new fail-over load balancing algorithm which will monitor offline
+   * connection factories using the specified frequency and scheduler.
+   *
+   * @param factories
+   *          The connection factories.
+   * @param interval
+   *          The interval between attempts to poll offline factories.
+   * @param unit
+   *          The time unit for the interval between attempts to poll offline
+   *          factories.
+   * @param scheduler
+   *          The scheduler which should for periodically monitoring dead
+   *          connection factories to see if they are usable again.
+   */
+  public FailoverLoadBalancingAlgorithm(
+      final Collection<ConnectionFactory> factories, final long interval,
+      final TimeUnit unit, final ScheduledExecutorService scheduler)
+  {
+    super(factories, interval, unit, scheduler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  String getAlgorithmName()
+  {
+    return "Failover";
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  int getInitialConnectionFactoryIndex()
+  {
+    // Always start with the first connection factory.
+    return 0;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Filter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Filter.java
new file mode 100644
index 0000000..f52bbba
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Filter.java
@@ -0,0 +1,2123 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.byteToHex;
+import static com.sun.opends.sdk.util.StaticUtils.getBytes;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+
+import java.util.*;
+
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A search filter as defined in RFC 4511. In addition this class also provides
+ * support for the absolute true and absolute false filters as defined in RFC
+ * 4526.
+ * <p>
+ * This class provides many factory methods for creating common types of filter.
+ * Applications interact with a filter using {@link FilterVisitor} which is
+ * applied to a filter using the {@link #accept(FilterVisitor, Object)} method.
+ * <p>
+ * The RFC 4515 string representation of a filter can be generated using the
+ * {@link #toString} methods and parsed using the {@link #valueOf(String)}
+ * factory method.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight
+ *      Directory Access Protocol (LDAP): The Protocol </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4515">RFC 4515 - String
+ *      Representation of Search Filters </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4526">RFC 4526 - Absolute True
+ *      and False Filters </a>
+ */
+public final class Filter
+{
+  private static final class AndImpl extends Impl
+  {
+    private final List<Filter> subFilters;
+
+
+
+    public AndImpl(final List<Filter> subFilters)
+    {
+      this.subFilters = subFilters;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitAndFilter(p, subFilters);
+    }
+
+  }
+
+
+
+  private static final class ApproxMatchImpl extends Impl
+  {
+
+    private final ByteString assertionValue;
+
+    private final String attributeDescription;
+
+
+
+    public ApproxMatchImpl(final String attributeDescription,
+        final ByteString assertionValue)
+    {
+      this.attributeDescription = attributeDescription;
+      this.assertionValue = assertionValue;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitApproxMatchFilter(p, attributeDescription, assertionValue);
+    }
+
+  }
+
+
+
+  private static final class EqualityMatchImpl extends Impl
+  {
+
+    private final ByteString assertionValue;
+
+    private final String attributeDescription;
+
+
+
+    public EqualityMatchImpl(final String attributeDescription,
+        final ByteString assertionValue)
+    {
+      this.attributeDescription = attributeDescription;
+      this.assertionValue = assertionValue;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v
+          .visitEqualityMatchFilter(p, attributeDescription, assertionValue);
+    }
+
+  }
+
+
+
+  private static final class ExtensibleMatchImpl extends Impl
+  {
+    private final String attributeDescription;
+
+    private final boolean dnAttributes;
+
+    private final String matchingRule;
+
+    private final ByteString matchValue;
+
+
+
+    public ExtensibleMatchImpl(final String matchingRule,
+        final String attributeDescription, final ByteString matchValue,
+        final boolean dnAttributes)
+    {
+      this.matchingRule = matchingRule;
+      this.attributeDescription = attributeDescription;
+      this.matchValue = matchValue;
+      this.dnAttributes = dnAttributes;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitExtensibleMatchFilter(p, matchingRule,
+          attributeDescription, matchValue, dnAttributes);
+    }
+
+  }
+
+
+
+  private static final class GreaterOrEqualImpl extends Impl
+  {
+
+    private final ByteString assertionValue;
+
+    private final String attributeDescription;
+
+
+
+    public GreaterOrEqualImpl(final String attributeDescription,
+        final ByteString assertionValue)
+    {
+      this.attributeDescription = attributeDescription;
+      this.assertionValue = assertionValue;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitGreaterOrEqualFilter(p, attributeDescription,
+          assertionValue);
+    }
+
+  }
+
+
+
+  private static abstract class Impl
+  {
+    protected Impl()
+    {
+      // Nothing to do.
+    }
+
+
+
+    public abstract <R, P> R accept(FilterVisitor<R, P> v, P p);
+  }
+
+
+
+  private static final class LessOrEqualImpl extends Impl
+  {
+
+    private final ByteString assertionValue;
+
+    private final String attributeDescription;
+
+
+
+    public LessOrEqualImpl(final String attributeDescription,
+        final ByteString assertionValue)
+    {
+      this.attributeDescription = attributeDescription;
+      this.assertionValue = assertionValue;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitLessOrEqualFilter(p, attributeDescription, assertionValue);
+    }
+
+  }
+
+
+
+  private static final class NotImpl extends Impl
+  {
+    private final Filter subFilter;
+
+
+
+    public NotImpl(final Filter subFilter)
+    {
+      this.subFilter = subFilter;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitNotFilter(p, subFilter);
+    }
+
+  }
+
+
+
+  private static final class OrImpl extends Impl
+  {
+    private final List<Filter> subFilters;
+
+
+
+    public OrImpl(final List<Filter> subFilters)
+    {
+      this.subFilters = subFilters;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitOrFilter(p, subFilters);
+    }
+
+  }
+
+
+
+  private static final class PresentImpl extends Impl
+  {
+
+    private final String attributeDescription;
+
+
+
+    public PresentImpl(final String attributeDescription)
+    {
+      this.attributeDescription = attributeDescription;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitPresentFilter(p, attributeDescription);
+    }
+
+  }
+
+
+
+  private static final class SubstringsImpl extends Impl
+  {
+
+    private final List<ByteString> anyStrings;
+
+    private final String attributeDescription;
+
+    private final ByteString finalString;
+
+    private final ByteString initialString;
+
+
+
+    public SubstringsImpl(final String attributeDescription,
+        final ByteString initialString, final List<ByteString> anyStrings,
+        final ByteString finalString)
+    {
+      this.attributeDescription = attributeDescription;
+      this.initialString = initialString;
+      this.anyStrings = anyStrings;
+      this.finalString = finalString;
+
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitSubstringsFilter(p, attributeDescription, initialString,
+          anyStrings, finalString);
+    }
+
+  }
+
+
+
+  private static final class UnrecognizedImpl extends Impl
+  {
+
+    private final ByteString filterBytes;
+
+    private final byte filterTag;
+
+
+
+    public UnrecognizedImpl(final byte filterTag, final ByteString filterBytes)
+    {
+      this.filterTag = filterTag;
+      this.filterBytes = filterBytes;
+    }
+
+
+
+    @Override
+    public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+    {
+      return v.visitUnrecognizedFilter(p, filterTag, filterBytes);
+    }
+
+  }
+
+
+
+  // RFC 4526 - FALSE filter.
+  private static final Filter FALSE = new Filter(new OrImpl(Collections
+      .<Filter> emptyList()));
+
+  // Heavily used (objectClass=*) filter.
+  private static final Filter OBJECT_CLASS_PRESENT = new Filter(
+      new PresentImpl("objectClass"));
+
+  private static final FilterVisitor<StringBuilder, StringBuilder>
+    TO_STRING_VISITOR = new FilterVisitor<StringBuilder, StringBuilder>()
+  {
+
+    public StringBuilder visitAndFilter(final StringBuilder builder,
+        final List<Filter> subFilters)
+    {
+      builder.append("(&");
+      for (final Filter subFilter : subFilters)
+      {
+        subFilter.accept(this, builder);
+      }
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitApproxMatchFilter(final StringBuilder builder,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      builder.append('(');
+      builder.append(attributeDescription);
+      builder.append("~=");
+      valueToFilterString(builder, assertionValue);
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitEqualityMatchFilter(final StringBuilder builder,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      builder.append('(');
+      builder.append(attributeDescription);
+      builder.append("=");
+      valueToFilterString(builder, assertionValue);
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitExtensibleMatchFilter(
+        final StringBuilder builder, final String matchingRule,
+        final String attributeDescription, final ByteString assertionValue,
+        final boolean dnAttributes)
+    {
+      builder.append('(');
+
+      if (attributeDescription != null)
+      {
+        builder.append(attributeDescription);
+      }
+
+      if (dnAttributes)
+      {
+        builder.append(":dn");
+      }
+
+      if (matchingRule != null)
+      {
+        builder.append(':');
+        builder.append(matchingRule);
+      }
+
+      builder.append(":=");
+      valueToFilterString(builder, assertionValue);
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitGreaterOrEqualFilter(final StringBuilder builder,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      builder.append('(');
+      builder.append(attributeDescription);
+      builder.append(">=");
+      valueToFilterString(builder, assertionValue);
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitLessOrEqualFilter(final StringBuilder builder,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      builder.append('(');
+      builder.append(attributeDescription);
+      builder.append("<=");
+      valueToFilterString(builder, assertionValue);
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitNotFilter(final StringBuilder builder,
+        final Filter subFilter)
+    {
+      builder.append("(|");
+      subFilter.accept(this, builder);
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitOrFilter(final StringBuilder builder,
+        final List<Filter> subFilters)
+    {
+      builder.append("(|");
+      for (final Filter subFilter : subFilters)
+      {
+        subFilter.accept(this, builder);
+      }
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitPresentFilter(final StringBuilder builder,
+        final String attributeDescription)
+    {
+      builder.append('(');
+      builder.append(attributeDescription);
+      builder.append("=*)");
+      return builder;
+    }
+
+
+
+    public StringBuilder visitSubstringsFilter(final StringBuilder builder,
+        final String attributeDescription, final ByteString initialSubstring,
+        final List<ByteString> anySubstrings, final ByteString finalSubstring)
+    {
+      builder.append('(');
+      builder.append(attributeDescription);
+      builder.append("=");
+      if (initialSubstring != null)
+      {
+        valueToFilterString(builder, initialSubstring);
+      }
+      for (final ByteString anySubstring : anySubstrings)
+      {
+        builder.append('*');
+        valueToFilterString(builder, anySubstring);
+      }
+      builder.append('*');
+      if (finalSubstring != null)
+      {
+        valueToFilterString(builder, finalSubstring);
+      }
+      builder.append(')');
+      return builder;
+    }
+
+
+
+    public StringBuilder visitUnrecognizedFilter(final StringBuilder builder,
+        final byte filterTag, final ByteString filterBytes)
+    {
+      // Fake up a representation.
+      builder.append('(');
+      builder.append(byteToHex(filterTag));
+      builder.append(':');
+      StaticUtils.toHex(filterBytes, builder);
+      builder.append(')');
+      return builder;
+    }
+  };
+
+  // RFC 4526 - TRUE filter.
+  private static final Filter TRUE = new Filter(new AndImpl(Collections
+      .<Filter> emptyList()));
+
+
+
+  /**
+   * Returns the {@code absolute false} filter as defined in RFC 4526 which is
+   * comprised of an {@code or} filter containing zero components.
+   *
+   * @return The absolute false filter.
+   * @see <a href="http://tools.ietf.org/html/rfc4526">RFC 4526</a>
+   */
+  public static Filter getAbsoluteFalseFilter()
+  {
+    return FALSE;
+  }
+
+
+
+  /**
+   * Returns the {@code absolute true} filter as defined in RFC 4526 which is
+   * comprised of an {@code and} filter containing zero components.
+   *
+   * @return The absolute true filter.
+   * @see <a href="http://tools.ietf.org/html/rfc4526">RFC 4526</a>
+   */
+  public static Filter getAbsoluteTrueFilter()
+  {
+    return TRUE;
+  }
+
+
+
+  /**
+   * Returns the {@code objectClass} presence filter {@code (objectClass=*)}.
+   * <p>
+   * A call to this method is equivalent to but more efficient than the
+   * following code:
+   *
+   * <pre>
+   * Filter.present(&quot;objectClass&quot;);
+   * </pre>
+   *
+   * @return The {@code objectClass} presence filter {@code (objectClass=*)}.
+   */
+  public static Filter getObjectClassPresentFilter()
+  {
+    return OBJECT_CLASS_PRESENT;
+  }
+
+
+
+  /**
+   * Creates a new {@code and} filter using the provided list of sub-filters.
+   * <p>
+   * Creating a new {@code and} filter with a {@code null} or empty list of
+   * sub-filters is equivalent to calling {@link #getAbsoluteTrueFilter()}.
+   *
+   * @param subFilters
+   *          The list of sub-filters, may be empty or {@code null}.
+   * @return The newly created {@code and} filter.
+   */
+  public static Filter newAndFilter(final Collection<Filter> subFilters)
+  {
+    if (subFilters == null || subFilters.isEmpty())
+    {
+      // RFC 4526 - TRUE filter.
+      return getAbsoluteTrueFilter();
+    }
+    else if (subFilters.size() == 1)
+    {
+      final Filter subFilter = subFilters.iterator().next();
+      Validator.ensureNotNull(subFilter);
+      return new Filter(new AndImpl(Collections.singletonList(subFilter)));
+    }
+    else
+    {
+      final List<Filter> subFiltersList = new ArrayList<Filter>(subFilters
+          .size());
+      for (final Filter subFilter : subFilters)
+      {
+        Validator.ensureNotNull(subFilter);
+        subFiltersList.add(subFilter);
+      }
+      return new Filter(new AndImpl(Collections
+          .unmodifiableList(subFiltersList)));
+    }
+  }
+
+
+
+  /**
+   * Creates a new {@code and} filter using the provided list of sub-filters.
+   * <p>
+   * Creating a new {@code and} filter with a {@code null} or empty list of
+   * sub-filters is equivalent to calling {@link #getAbsoluteTrueFilter()}.
+   *
+   * @param subFilters
+   *          The list of sub-filters, may be empty or {@code null}.
+   * @return The newly created {@code and} filter.
+   */
+  public static Filter newAndFilter(final Filter... subFilters)
+  {
+    if ((subFilters == null) || (subFilters.length == 0))
+    {
+      // RFC 4526 - TRUE filter.
+      return getAbsoluteTrueFilter();
+    }
+    else if (subFilters.length == 1)
+    {
+      Validator.ensureNotNull(subFilters[0]);
+      return new Filter(new AndImpl(Collections.singletonList(subFilters[0])));
+    }
+    else
+    {
+      final List<Filter> subFiltersList = new ArrayList<Filter>(
+          subFilters.length);
+      for (final Filter subFilter : subFilters)
+      {
+        Validator.ensureNotNull(subFilter);
+        subFiltersList.add(subFilter);
+      }
+      return new Filter(new AndImpl(Collections
+          .unmodifiableList(subFiltersList)));
+    }
+  }
+
+
+
+  /**
+   * Creates a new {@code approximate match} filter using the provided attribute
+   * description and assertion value.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code approximate match} filter.
+   */
+  public static Filter newApproxMatchFilter(final String attributeDescription,
+      final ByteString assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new ApproxMatchImpl(attributeDescription, assertionValue));
+  }
+
+
+
+  /**
+   * Creates a new {@code approximate match} filter using the provided attribute
+   * description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code approximate match} filter.
+   */
+  public static Filter newApproxMatchFilter(final String attributeDescription,
+      final Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new ApproxMatchImpl(attributeDescription, ByteString
+        .valueOf(assertionValue)));
+  }
+
+
+
+  /**
+   * Creates a new {@code equality match} filter using the provided attribute
+   * description and assertion value.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code equality match} filter.
+   */
+  public static Filter newEqualityMatchFilter(
+      final String attributeDescription, final ByteString assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new EqualityMatchImpl(attributeDescription,
+        assertionValue));
+  }
+
+
+
+  /**
+   * Creates a new {@code equality match} filter using the provided attribute
+   * description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code equality match} filter.
+   */
+  public static Filter newEqualityMatchFilter(
+      final String attributeDescription, final Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new EqualityMatchImpl(attributeDescription, ByteString
+        .valueOf(assertionValue)));
+  }
+
+
+
+  /**
+   * Creates a new {@code extensible match} filter.
+   *
+   * @param matchingRule
+   *          The matching rule name, may be {@code null} if {@code
+   *          attributeDescription} is specified.
+   * @param attributeDescription
+   *          The attribute description, may be {@code null} if {@code
+   *          matchingRule} is specified.
+   * @param assertionValue
+   *          The assertion value.
+   * @param dnAttributes
+   *          Indicates whether DN matching should be performed.
+   * @return The newly created {@code extensible match} filter.
+   */
+  public static Filter newExtensibleMatchFilter(final String matchingRule,
+      final String attributeDescription, final ByteString assertionValue,
+      final boolean dnAttributes)
+  {
+    Validator.ensureTrue((matchingRule != null)
+        || (attributeDescription != null), "matchingRule and/or "
+        + "attributeDescription must not be null");
+    Validator.ensureNotNull(assertionValue);
+    return new Filter(new ExtensibleMatchImpl(matchingRule,
+        attributeDescription, assertionValue, dnAttributes));
+  }
+
+
+
+  /**
+   * Creates a new {@code extensible match} filter.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param matchingRule
+   *          The matching rule name, may be {@code null} if {@code
+   *          attributeDescription} is specified.
+   * @param attributeDescription
+   *          The attribute description, may be {@code null} if {@code
+   *          matchingRule} is specified.
+   * @param assertionValue
+   *          The assertion value.
+   * @param dnAttributes
+   *          Indicates whether DN matching should be performed.
+   * @return The newly created {@code extensible match} filter.
+   */
+  public static Filter newExtensibleMatchFilter(final String matchingRule,
+      final String attributeDescription, final Object assertionValue,
+      final boolean dnAttributes)
+  {
+    Validator.ensureTrue((matchingRule != null)
+        || (attributeDescription != null), "matchingRule and/or "
+        + "attributeDescription must not be null");
+    Validator.ensureNotNull(assertionValue);
+    return new Filter(new ExtensibleMatchImpl(matchingRule,
+        attributeDescription, ByteString.valueOf(assertionValue), dnAttributes));
+  }
+
+
+
+  /**
+   * Creates a new {@code greater or equal} filter using the provided attribute
+   * description and assertion value.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code greater or equal} filter.
+   */
+  public static Filter newGreaterOrEqualFilter(
+      final String attributeDescription, final ByteString assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new GreaterOrEqualImpl(attributeDescription,
+        assertionValue));
+  }
+
+
+
+  /**
+   * Creates a new {@code greater or equal} filter using the provided attribute
+   * description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code greater or equal} filter.
+   */
+  public static Filter newGreaterOrEqualFilter(
+      final String attributeDescription, final Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new GreaterOrEqualImpl(attributeDescription, ByteString
+        .valueOf(assertionValue)));
+  }
+
+
+
+  /**
+   * Creates a new {@code less or equal} filter using the provided attribute
+   * description and assertion value.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code less or equal} filter.
+   */
+  public static Filter newLessOrEqualFilter(final String attributeDescription,
+      final ByteString assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new LessOrEqualImpl(attributeDescription, assertionValue));
+  }
+
+
+
+  /**
+   * Creates a new {@code less or equal} filter using the provided attribute
+   * description and assertion value.
+   * <p>
+   * If {@code assertionValue} is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return The newly created {@code less or equal} filter.
+   */
+  public static Filter newLessOrEqualFilter(final String attributeDescription,
+      final Object assertionValue)
+  {
+    Validator.ensureNotNull(attributeDescription, assertionValue);
+    return new Filter(new LessOrEqualImpl(attributeDescription, ByteString
+        .valueOf(assertionValue)));
+  }
+
+
+
+  /**
+   * Creates a new {@code not} filter using the provided sub-filter.
+   *
+   * @param subFilter
+   *          The sub-filter.
+   * @return The newly created {@code not} filter.
+   */
+  public static Filter newNotFilter(final Filter subFilter)
+  {
+    Validator.ensureNotNull(subFilter);
+    return new Filter(new NotImpl(subFilter));
+  }
+
+
+
+  /**
+   * Creates a new {@code or} filter using the provided list of sub-filters.
+   * <p>
+   * Creating a new {@code or} filter with a {@code null} or empty list of
+   * sub-filters is equivalent to calling {@link #getAbsoluteFalseFilter()}.
+   *
+   * @param subFilters
+   *          The list of sub-filters, may be empty or {@code null}.
+   * @return The newly created {@code or} filter.
+   */
+  public static Filter newOrFilter(final Collection<Filter> subFilters)
+  {
+    if (subFilters == null || subFilters.isEmpty())
+    {
+      // RFC 4526 - FALSE filter.
+      return getAbsoluteFalseFilter();
+    }
+    else if (subFilters.size() == 1)
+    {
+      final Filter subFilter = subFilters.iterator().next();
+      Validator.ensureNotNull(subFilter);
+      return new Filter(new OrImpl(Collections.singletonList(subFilter)));
+    }
+    else
+    {
+      final List<Filter> subFiltersList = new ArrayList<Filter>(subFilters
+          .size());
+      for (final Filter subFilter : subFilters)
+      {
+        Validator.ensureNotNull(subFilter);
+        subFiltersList.add(subFilter);
+      }
+      return new Filter(
+          new OrImpl(Collections.unmodifiableList(subFiltersList)));
+    }
+  }
+
+
+
+  /**
+   * Creates a new {@code or} filter using the provided list of sub-filters.
+   * <p>
+   * Creating a new {@code or} filter with a {@code null} or empty list of
+   * sub-filters is equivalent to calling {@link #getAbsoluteFalseFilter()}.
+   *
+   * @param subFilters
+   *          The list of sub-filters, may be empty or {@code null}.
+   * @return The newly created {@code or} filter.
+   */
+  public static Filter newOrFilter(final Filter... subFilters)
+  {
+    if ((subFilters == null) || (subFilters.length == 0))
+    {
+      // RFC 4526 - FALSE filter.
+      return getAbsoluteFalseFilter();
+    }
+    else if (subFilters.length == 1)
+    {
+      Validator.ensureNotNull(subFilters[0]);
+      return new Filter(new OrImpl(Collections.singletonList(subFilters[0])));
+    }
+    else
+    {
+      final List<Filter> subFiltersList = new ArrayList<Filter>(
+          subFilters.length);
+      for (final Filter subFilter : subFilters)
+      {
+        Validator.ensureNotNull(subFilter);
+        subFiltersList.add(subFilter);
+      }
+      return new Filter(
+          new OrImpl(Collections.unmodifiableList(subFiltersList)));
+    }
+  }
+
+
+
+  /**
+   * Creates a new {@code present} filter using the provided attribute
+   * description.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @return The newly created {@code present} filter.
+   */
+  public static Filter newPresentFilter(final String attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    if (toLowerCase(attributeDescription).equals("objectclass"))
+    {
+      return OBJECT_CLASS_PRESENT;
+    }
+    return new Filter(new PresentImpl(attributeDescription));
+  }
+
+
+
+  /**
+   * Creates a new {@code substrings} filter using the provided attribute
+   * description, {@code initial}, {@code final}, and {@code any} sub-strings.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param initialSubstring
+   *          The initial sub-string, may be {@code null} if either {@code
+   *          finalSubstring} or {@code anySubstrings} are specified.
+   * @param anySubstrings
+   *          The final sub-string, may be {@code null} or empty if either
+   *          {@code finalSubstring} or {@code initialSubstring} are specified.
+   * @param finalSubstring
+   *          The final sub-string, may be {@code null}, may be {@code null} if
+   *          either {@code initialSubstring} or {@code anySubstrings} are
+   *          specified.
+   * @return The newly created {@code substrings} filter.
+   */
+  public static Filter newSubstringsFilter(final String attributeDescription,
+      final ByteString initialSubstring,
+      final Collection<ByteString> anySubstrings,
+      final ByteString finalSubstring)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    Validator
+        .ensureTrue((initialSubstring != null) || (finalSubstring != null)
+            || ((anySubstrings != null) && (anySubstrings.size() > 0)),
+            "at least one substring (initial, any or final)"
+                + " must be specified");
+
+    List<ByteString> anySubstringList;
+    if ((anySubstrings == null) || (anySubstrings.size() == 0))
+    {
+      anySubstringList = Collections.emptyList();
+    }
+    else if (anySubstrings.size() == 1)
+    {
+      final ByteString anySubstring = anySubstrings.iterator().next();
+      Validator.ensureNotNull(anySubstring);
+      anySubstringList = Collections.singletonList(anySubstring);
+    }
+    else
+    {
+      anySubstringList = new ArrayList<ByteString>(anySubstrings.size());
+      for (final ByteString anySubstring : anySubstrings)
+      {
+        Validator.ensureNotNull(anySubstring);
+
+        anySubstringList.add(anySubstring);
+      }
+      anySubstringList = Collections.unmodifiableList(anySubstringList);
+    }
+
+    return new Filter(new SubstringsImpl(attributeDescription,
+        initialSubstring, anySubstringList, finalSubstring));
+  }
+
+
+
+  /**
+   * Creates a new {@code substrings} filter using the provided attribute
+   * description, {@code initial}, {@code final}, and {@code any} sub-strings.
+   * <p>
+   * Any substrings which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param initialSubstring
+   *          The initial sub-string, may be {@code null} if either {@code
+   *          finalSubstring} or {@code anySubstrings} are specified.
+   * @param anySubstrings
+   *          The final sub-string, may be {@code null} or empty if either
+   *          {@code finalSubstring} or {@code initialSubstring} are specified.
+   * @param finalSubstring
+   *          The final sub-string, may be {@code null}, may be {@code null} if
+   *          either {@code initialSubstring} or {@code anySubstrings} are
+   *          specified.
+   * @return The newly created {@code substrings} filter.
+   */
+  public static Filter newSubstringsFilter(final String attributeDescription,
+      final Object initialSubstring, final Collection<?> anySubstrings,
+      final Object finalSubstring)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    Validator
+        .ensureTrue((initialSubstring != null) || (finalSubstring != null)
+            || ((anySubstrings != null) && (anySubstrings.size() > 0)),
+            "at least one substring (initial, any or final)"
+                + " must be specified");
+
+    List<ByteString> anySubstringList;
+    if ((anySubstrings == null) || (anySubstrings.size() == 0))
+    {
+      anySubstringList = Collections.emptyList();
+    }
+    else if (anySubstrings.size() == 1)
+    {
+      final Object anySubstring = anySubstrings.iterator().next();
+      Validator.ensureNotNull(anySubstring);
+      anySubstringList = Collections.singletonList(ByteString
+          .valueOf(anySubstring));
+    }
+    else
+    {
+      anySubstringList = new ArrayList<ByteString>(anySubstrings.size());
+      for (final Object anySubstring : anySubstrings)
+      {
+        Validator.ensureNotNull(anySubstring);
+
+        anySubstringList.add(ByteString.valueOf(anySubstring));
+      }
+      anySubstringList = Collections.unmodifiableList(anySubstringList);
+    }
+
+    return new Filter(new SubstringsImpl(attributeDescription,
+        initialSubstring != null ? ByteString.valueOf(initialSubstring) : null,
+        anySubstringList, finalSubstring != null ? ByteString
+            .valueOf(finalSubstring) : null));
+  }
+
+
+
+  /**
+   * Creates a new {@code unrecognized} filter using the provided ASN1 filter
+   * tag and content. This type of filter should be used for filters which are
+   * not part of the standard filter definition.
+   *
+   * @param filterTag
+   *          The ASN.1 tag.
+   * @param filterBytes
+   *          The filter content.
+   * @return The newly created {@code unrecognized} filter.
+   */
+  public static Filter newUnrecognizedFilter(final byte filterTag,
+      final ByteString filterBytes)
+  {
+    Validator.ensureNotNull(filterBytes);
+    return new Filter(new UnrecognizedImpl(filterTag, filterBytes));
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of a filter as a {@code
+   * Filter}.
+   *
+   * @param string
+   *          The LDAP string representation of a filter.
+   * @return The parsed {@code Filter}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code string} is not a valid LDAP string representation of a
+   *           filter.
+   */
+  public static Filter valueOf(final String string)
+      throws LocalizedIllegalArgumentException
+  {
+    Validator.ensureNotNull(string);
+
+    // If the filter is enclosed in a pair of single quotes it
+    // is invalid (issue #1024).
+    if ((string.length() > 1) && string.startsWith("'") && string.endsWith("'"))
+    {
+      final LocalizableMessage message = ERR_LDAP_FILTER_ENCLOSED_IN_APOSTROPHES
+          .get(string);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    try
+    {
+      if (string.startsWith("("))
+      {
+        if (string.endsWith(")"))
+        {
+          return valueOf0(string, 1, string.length() - 1);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_LDAP_FILTER_MISMATCHED_PARENTHESES
+              .get(string, 1, string.length());
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+      else
+      {
+        // We tolerate the top level filter component not being surrounded
+        // by parentheses.
+        return valueOf0(string, 0, string.length());
+      }
+    }
+    catch (final LocalizedIllegalArgumentException liae)
+    {
+      throw liae;
+    }
+    catch (final Exception e)
+    {
+      final LocalizableMessage message = ERR_LDAP_FILTER_UNCAUGHT_EXCEPTION
+          .get(string, String.valueOf(e));
+      throw new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  // Converts an assertion value to a substring filter.
+  private static Filter assertionValue2SubstringFilter(
+      final String filterString, final String attrType, final int equalPos,
+      final int endPos) throws LocalizedIllegalArgumentException
+  {
+    // Get a binary representation of the value.
+    final byte[] valueBytes = getBytes(filterString.substring(equalPos, endPos));
+
+    // Find the locations of all the asterisks in the value. Also, check to
+    // see if there are any escaped values, since they will need special
+    // treatment.
+    boolean hasEscape = false;
+    final LinkedList<Integer> asteriskPositions = new LinkedList<Integer>();
+    for (int i = 0; i < valueBytes.length; i++)
+    {
+      if (valueBytes[i] == 0x2A) // The asterisk.
+      {
+        asteriskPositions.add(i);
+      }
+      else if (valueBytes[i] == 0x5C) // The backslash.
+      {
+        hasEscape = true;
+      }
+    }
+
+    // If there were no asterisks, then this isn't a substring filter.
+    if (asteriskPositions.isEmpty())
+    {
+      final LocalizableMessage message = ERR_LDAP_FILTER_SUBSTRING_NO_ASTERISKS
+          .get(filterString, equalPos + 1, endPos);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // If the value starts with an asterisk, then there is no subInitial
+    // component. Otherwise, parse out the subInitial.
+    ByteString subInitial;
+    int firstPos = asteriskPositions.removeFirst();
+    if (firstPos == 0)
+    {
+      subInitial = null;
+    }
+    else
+    {
+      if (hasEscape)
+      {
+        final ByteStringBuilder buffer = new ByteStringBuilder(firstPos);
+        escapeHexChars(buffer, attrType, valueBytes, 0, firstPos, equalPos);
+        subInitial = buffer.toByteString();
+      }
+      else
+      {
+        subInitial = ByteString.wrap(valueBytes, 0, firstPos);
+      }
+    }
+
+    // Next, process through the rest of the asterisks to get the subAny values.
+    final ArrayList<ByteString> subAny = new ArrayList<ByteString>();
+    for (final int asteriskPos : asteriskPositions)
+    {
+      final int length = asteriskPos - firstPos - 1;
+
+      if (hasEscape)
+      {
+        final ByteStringBuilder buffer = new ByteStringBuilder(length);
+        escapeHexChars(buffer, attrType, valueBytes, firstPos + 1, asteriskPos,
+            equalPos);
+        subAny.add(buffer.toByteString());
+        buffer.clear();
+      }
+      else
+      {
+        subAny.add(ByteString.wrap(valueBytes, firstPos + 1, length));
+      }
+      firstPos = asteriskPos;
+    }
+
+    // Finally, see if there is anything after the last asterisk, which would be
+    // the subFinal value.
+    ByteString subFinal;
+    if (firstPos == (valueBytes.length - 1))
+    {
+      subFinal = null;
+    }
+    else
+    {
+      final int length = valueBytes.length - firstPos - 1;
+
+      if (hasEscape)
+      {
+        final ByteStringBuilder buffer = new ByteStringBuilder(length);
+        escapeHexChars(buffer, attrType, valueBytes, firstPos + 1,
+            valueBytes.length, equalPos);
+        subFinal = buffer.toByteString();
+      }
+      else
+      {
+        subFinal = ByteString.wrap(valueBytes, firstPos + 1, length);
+      }
+    }
+    return new Filter(
+        new SubstringsImpl(attrType, subInitial, subAny, subFinal));
+  }
+
+
+
+  private static void escapeHexChars(final ByteStringBuilder valueBuffer,
+      final String string, final byte[] valueBytes, final int fromIndex,
+      final int len, final int errorIndex)
+      throws LocalizedIllegalArgumentException
+  {
+    for (int i = fromIndex; i < len; i++)
+    {
+      if (valueBytes[i] == 0x5C) // The backslash character
+      {
+        // The next two bytes must be the hex characters that comprise
+        // the binary value.
+        if ((i + 2) >= valueBytes.length)
+        {
+          final LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE
+              .get(string, errorIndex + i + 1);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        byte byteValue = 0;
+        switch (valueBytes[++i])
+        {
+        case 0x30: // '0'
+          break;
+        case 0x31: // '1'
+          byteValue = (byte) 0x10;
+          break;
+        case 0x32: // '2'
+          byteValue = (byte) 0x20;
+          break;
+        case 0x33: // '3'
+          byteValue = (byte) 0x30;
+          break;
+        case 0x34: // '4'
+          byteValue = (byte) 0x40;
+          break;
+        case 0x35: // '5'
+          byteValue = (byte) 0x50;
+          break;
+        case 0x36: // '6'
+          byteValue = (byte) 0x60;
+          break;
+        case 0x37: // '7'
+          byteValue = (byte) 0x70;
+          break;
+        case 0x38: // '8'
+          byteValue = (byte) 0x80;
+          break;
+        case 0x39: // '9'
+          byteValue = (byte) 0x90;
+          break;
+        case 0x41: // 'A'
+        case 0x61: // 'a'
+          byteValue = (byte) 0xA0;
+          break;
+        case 0x42: // 'B'
+        case 0x62: // 'b'
+          byteValue = (byte) 0xB0;
+          break;
+        case 0x43: // 'C'
+        case 0x63: // 'c'
+          byteValue = (byte) 0xC0;
+          break;
+        case 0x44: // 'D'
+        case 0x64: // 'd'
+          byteValue = (byte) 0xD0;
+          break;
+        case 0x45: // 'E'
+        case 0x65: // 'e'
+          byteValue = (byte) 0xE0;
+          break;
+        case 0x46: // 'F'
+        case 0x66: // 'f'
+          byteValue = (byte) 0xF0;
+          break;
+        default:
+          final LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE
+              .get(string, errorIndex + i + 1);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        switch (valueBytes[++i])
+        {
+        case 0x30: // '0'
+          break;
+        case 0x31: // '1'
+          byteValue |= (byte) 0x01;
+          break;
+        case 0x32: // '2'
+          byteValue |= (byte) 0x02;
+          break;
+        case 0x33: // '3'
+          byteValue |= (byte) 0x03;
+          break;
+        case 0x34: // '4'
+          byteValue |= (byte) 0x04;
+          break;
+        case 0x35: // '5'
+          byteValue |= (byte) 0x05;
+          break;
+        case 0x36: // '6'
+          byteValue |= (byte) 0x06;
+          break;
+        case 0x37: // '7'
+          byteValue |= (byte) 0x07;
+          break;
+        case 0x38: // '8'
+          byteValue |= (byte) 0x08;
+          break;
+        case 0x39: // '9'
+          byteValue |= (byte) 0x09;
+          break;
+        case 0x41: // 'A'
+        case 0x61: // 'a'
+          byteValue |= (byte) 0x0A;
+          break;
+        case 0x42: // 'B'
+        case 0x62: // 'b'
+          byteValue |= (byte) 0x0B;
+          break;
+        case 0x43: // 'C'
+        case 0x63: // 'c'
+          byteValue |= (byte) 0x0C;
+          break;
+        case 0x44: // 'D'
+        case 0x64: // 'd'
+          byteValue |= (byte) 0x0D;
+          break;
+        case 0x45: // 'E'
+        case 0x65: // 'e'
+          byteValue |= (byte) 0x0E;
+          break;
+        case 0x46: // 'F'
+        case 0x66: // 'f'
+          byteValue |= (byte) 0x0F;
+          break;
+        default:
+          final LocalizableMessage message = ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE
+              .get(string, errorIndex + i + 1);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+
+        valueBuffer.append(byteValue);
+      }
+      else
+      {
+        valueBuffer.append(valueBytes[i]);
+      }
+    }
+  }
+
+
+
+  private static Filter valueOf0(final String string,
+      final int beginIndex /* inclusive */, final int endIndex /* exclusive */)
+      throws LocalizedIllegalArgumentException
+  {
+    if (beginIndex >= endIndex)
+    {
+      final LocalizableMessage message = ERR_LDAP_FILTER_STRING_NULL.get();
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    final int index = beginIndex;
+    final char c = string.charAt(index);
+
+    if (c == '&')
+    {
+      final List<Filter> subFilters = valueOfFilterList(string, index + 1,
+          endIndex);
+      if (subFilters.isEmpty())
+      {
+        return getAbsoluteTrueFilter();
+      }
+      else
+      {
+        return new Filter(new AndImpl(subFilters));
+      }
+    }
+    else if (c == '|')
+    {
+      final List<Filter> subFilters = valueOfFilterList(string, index + 1,
+          endIndex);
+      if (subFilters.isEmpty())
+      {
+        return getAbsoluteFalseFilter();
+      }
+      else
+      {
+        return new Filter(new OrImpl(subFilters));
+      }
+    }
+    else if (c == '!')
+    {
+      if ((string.charAt(index + 1) != '(')
+          || (string.charAt(endIndex - 1) != ')'))
+      {
+        final LocalizableMessage message = ERR_LDAP_FILTER_COMPOUND_MISSING_PARENTHESES
+            .get(string, index, endIndex - 1);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+      final List<Filter> subFilters = valueOfFilterList(string, index + 1,
+          endIndex);
+      if (subFilters.size() != 1)
+      {
+        final LocalizableMessage message = ERR_LDAP_FILTER_NOT_EXACTLY_ONE.get(
+            string, index, endIndex);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+      return new Filter(new NotImpl(subFilters.get(0)));
+    }
+    else
+    {
+      // It must be a simple filter. It must have an equal sign at some
+      // point, so find it.
+      int equalPos = -1;
+      for (int i = index; i < endIndex; i++)
+      {
+        if (string.charAt(i) == '=')
+        {
+          equalPos = i;
+          break;
+        }
+      }
+
+      if (equalPos <= index)
+      {
+        final LocalizableMessage message = ERR_LDAP_FILTER_NO_EQUAL_SIGN.get(
+            string, index, endIndex);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Look at the character immediately before the equal sign,
+      // because it may help determine the filter type.
+      String attributeDescription;
+      ByteString assertionValue;
+
+      switch (string.charAt(equalPos - 1))
+      {
+      case '~':
+        attributeDescription = valueOfAttributeDescription(string, index,
+            equalPos - 1);
+        assertionValue = valueOfAssertionValue(string, equalPos + 1, endIndex);
+        return new Filter(new ApproxMatchImpl(attributeDescription,
+            assertionValue));
+      case '>':
+        attributeDescription = valueOfAttributeDescription(string, index,
+            equalPos - 1);
+        assertionValue = valueOfAssertionValue(string, equalPos + 1, endIndex);
+        return new Filter(new GreaterOrEqualImpl(attributeDescription,
+            assertionValue));
+      case '<':
+        attributeDescription = valueOfAttributeDescription(string, index,
+            equalPos - 1);
+        assertionValue = valueOfAssertionValue(string, equalPos + 1, endIndex);
+        return new Filter(new LessOrEqualImpl(attributeDescription,
+            assertionValue));
+      case ':':
+        return valueOfExtensibleFilter(string, index, equalPos, endIndex);
+      default:
+        attributeDescription = valueOfAttributeDescription(string, index,
+            equalPos);
+        return valueOfGenericFilter(string, attributeDescription, equalPos + 1,
+            endIndex);
+      }
+    }
+  }
+
+
+
+  private static ByteString valueOfAssertionValue(final String string,
+      final int startIndex, final int endIndex)
+      throws LocalizedIllegalArgumentException
+  {
+    boolean hasEscape = false;
+    final byte[] valueBytes = getBytes(string.substring(startIndex, endIndex));
+    for (final byte valueByte : valueBytes)
+    {
+      if (valueByte == 0x5C) // The backslash character
+      {
+        hasEscape = true;
+        break;
+      }
+    }
+
+    if (hasEscape)
+    {
+      final ByteStringBuilder valueBuffer = new ByteStringBuilder(
+          valueBytes.length);
+      escapeHexChars(valueBuffer, string, valueBytes, 0, valueBytes.length,
+          startIndex);
+      return valueBuffer.toByteString();
+    }
+    else
+    {
+      return ByteString.wrap(valueBytes);
+    }
+  }
+
+
+
+  private static String valueOfAttributeDescription(final String string,
+      final int startIndex, final int endIndex)
+      throws LocalizedIllegalArgumentException
+  {
+    // The part of the filter string before the equal sign should be the
+    // attribute type. Make sure that the characters it contains are
+    // acceptable for attribute types, including those allowed by
+    // attribute name exceptions (ASCII letters and digits, the dash,
+    // and the underscore). We also need to allow attribute options,
+    // which includes the semicolon and the equal sign.
+    final String attrType = string.substring(startIndex, endIndex);
+    for (int i = 0; i < attrType.length(); i++)
+    {
+      switch (attrType.charAt(i))
+      {
+      case '-':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case ';':
+      case '=':
+      case 'A':
+      case 'B':
+      case 'C':
+      case 'D':
+      case 'E':
+      case 'F':
+      case 'G':
+      case 'H':
+      case 'I':
+      case 'J':
+      case 'K':
+      case 'L':
+      case 'M':
+      case 'N':
+      case 'O':
+      case 'P':
+      case 'Q':
+      case 'R':
+      case 'S':
+      case 'T':
+      case 'U':
+      case 'V':
+      case 'W':
+      case 'X':
+      case 'Y':
+      case 'Z':
+      case '_':
+      case 'a':
+      case 'b':
+      case 'c':
+      case 'd':
+      case 'e':
+      case 'f':
+      case 'g':
+      case 'h':
+      case 'i':
+      case 'j':
+      case 'k':
+      case 'l':
+      case 'm':
+      case 'n':
+      case 'o':
+      case 'p':
+      case 'q':
+      case 'r':
+      case 's':
+      case 't':
+      case 'u':
+      case 'v':
+      case 'w':
+      case 'x':
+      case 'y':
+      case 'z':
+        // These are all OK.
+        break;
+
+      case '.':
+      case '/':
+      case ':':
+      case '<':
+      case '>':
+      case '?':
+      case '@':
+      case '[':
+      case '\\':
+      case ']':
+      case '^':
+      case '`':
+        // These are not allowed, but they are explicitly called out
+        // because they are included in the range of values between '-'
+        // and 'z', and making sure all possible characters are included
+        // can help make the switch statement more efficient. We'll fall
+        // through to the default clause to reject them.
+      default:
+        final LocalizableMessage message = ERR_LDAP_FILTER_INVALID_CHAR_IN_ATTR_TYPE
+            .get(attrType, String.valueOf(attrType.charAt(i)), i);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+    }
+
+    return attrType;
+  }
+
+
+
+  private static Filter valueOfExtensibleFilter(final String string,
+      final int startIndex, final int equalIndex, final int endIndex)
+      throws LocalizedIllegalArgumentException
+  {
+    String attributeDescription = null;
+    boolean dnAttributes = false;
+    String matchingRule = null;
+
+    // Look at the first character. If it is a colon, then it must be
+    // followed by either the string "dn" or the matching rule ID. If it
+    // is not, then must be the attribute type.
+    final String lowerLeftStr = toLowerCase(string.substring(startIndex,
+        equalIndex));
+    if (string.charAt(startIndex) == ':')
+    {
+      // See if it starts with ":dn". Otherwise, it much be the matching
+      // rule ID.
+      if (lowerLeftStr.startsWith(":dn:"))
+      {
+        dnAttributes = true;
+
+        if ((startIndex + 4) < (equalIndex - 1))
+        {
+          matchingRule = string.substring(startIndex + 4, equalIndex - 1);
+        }
+      }
+      else
+      {
+        matchingRule = string.substring(startIndex + 1, equalIndex - 1);
+      }
+    }
+    else
+    {
+      final int colonPos = string.indexOf(':', startIndex);
+      if (colonPos < 0)
+      {
+        final LocalizableMessage message = ERR_LDAP_FILTER_EXTENSIBLE_MATCH_NO_COLON
+            .get(string, startIndex);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      attributeDescription = string.substring(startIndex, colonPos);
+
+      // If there is anything left, then it should be ":dn" and/or ":"
+      // followed by the matching rule ID.
+      if (colonPos < (equalIndex - 1))
+      {
+        if (lowerLeftStr.startsWith(":dn:", colonPos - startIndex))
+        {
+          dnAttributes = true;
+
+          if ((colonPos + 4) < (equalIndex - 1))
+          {
+            matchingRule = string.substring(colonPos + 4, equalIndex - 1);
+          }
+        }
+        else
+        {
+          matchingRule = string.substring(colonPos + 1, equalIndex - 1);
+        }
+      }
+    }
+
+    // Parse out the attribute value.
+    final ByteString matchValue = valueOfAssertionValue(string, equalIndex + 1,
+        endIndex);
+
+    // Make sure that the filter has at least one of an attribute
+    // description and/or a matching rule ID.
+    if ((attributeDescription == null) && (matchingRule == null))
+    {
+      final LocalizableMessage message = ERR_LDAP_FILTER_EXTENSIBLE_MATCH_NO_AD_OR_MR
+          .get(string, startIndex);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    return new Filter(new ExtensibleMatchImpl(matchingRule,
+        attributeDescription, matchValue, dnAttributes));
+  }
+
+
+
+  private static List<Filter> valueOfFilterList(final String string,
+      final int startIndex, final int endIndex)
+      throws LocalizedIllegalArgumentException
+  {
+    // If the end index is equal to the start index, then there are no
+    // components.
+    if (startIndex >= endIndex)
+    {
+      return Collections.emptyList();
+    }
+
+    // At least one sub-filter.
+    Filter firstFilter = null;
+    List<Filter> subFilters = null;
+
+    // The first and last characters must be parentheses. If not, then
+    // that's an error.
+    if ((string.charAt(startIndex) != '(')
+        || (string.charAt(endIndex - 1) != ')'))
+    {
+      final LocalizableMessage message = ERR_LDAP_FILTER_COMPOUND_MISSING_PARENTHESES
+          .get(string, startIndex, endIndex);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    // Iterate through the characters in the value. Whenever an open
+    // parenthesis is found, locate the corresponding close parenthesis
+    // by counting the number of intermediate open/close parentheses.
+    int pendingOpens = 0;
+    int openIndex = -1;
+    for (int i = startIndex; i < endIndex; i++)
+    {
+      final char c = string.charAt(i);
+      if (c == '(')
+      {
+        if (openIndex < 0)
+        {
+          openIndex = i;
+        }
+        pendingOpens++;
+      }
+      else if (c == ')')
+      {
+        pendingOpens--;
+        if (pendingOpens == 0)
+        {
+          final Filter subFilter = valueOf0(string, openIndex + 1, i);
+          if (subFilters != null)
+          {
+            subFilters.add(subFilter);
+          }
+          else if (firstFilter != null)
+          {
+            subFilters = new LinkedList<Filter>();
+            subFilters.add(firstFilter);
+            subFilters.add(subFilter);
+            firstFilter = null;
+          }
+          else
+          {
+            firstFilter = subFilter;
+          }
+          openIndex = -1;
+        }
+        else if (pendingOpens < 0)
+        {
+          final LocalizableMessage message = ERR_LDAP_FILTER_NO_CORRESPONDING_OPEN_PARENTHESIS
+              .get(string, i);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+      else if (pendingOpens <= 0)
+      {
+        final LocalizableMessage message = ERR_LDAP_FILTER_COMPOUND_MISSING_PARENTHESES
+            .get(string, startIndex, endIndex);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+    }
+
+    // At this point, we have parsed the entire set of filter
+    // components. The list of open parenthesis positions must be empty.
+    if (pendingOpens != 0)
+    {
+      final LocalizableMessage message = ERR_LDAP_FILTER_NO_CORRESPONDING_CLOSE_PARENTHESIS
+          .get(string, openIndex);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    if (subFilters != null)
+    {
+      return Collections.unmodifiableList(subFilters);
+    }
+    else
+    {
+      return Collections.singletonList(firstFilter);
+    }
+  }
+
+
+
+  private static Filter valueOfGenericFilter(final String string,
+      final String attributeDescription, final int startIndex,
+      final int endIndex) throws LocalizedIllegalArgumentException
+  {
+    final int asteriskIdx = string.indexOf('*', startIndex);
+    if (startIndex >= endIndex)
+    {
+      // Equality filter with empty assertion value.
+      return new Filter(new EqualityMatchImpl(attributeDescription, ByteString
+          .empty()));
+    }
+    else if ((endIndex - startIndex == 1) && (string.charAt(startIndex) == '*'))
+    {
+      // Single asterisk is a present filter.
+      return newPresentFilter(attributeDescription);
+    }
+    else if (asteriskIdx > 0 && asteriskIdx <= endIndex)
+    {
+      // Substring filter.
+      return assertionValue2SubstringFilter(string, attributeDescription,
+          startIndex, endIndex);
+    }
+    else
+    {
+      // equality filter.
+      final ByteString assertionValue = valueOfAssertionValue(string,
+          startIndex, endIndex);
+      return new Filter(new EqualityMatchImpl(attributeDescription,
+          assertionValue));
+    }
+  }
+
+
+
+  /**
+   * Appends a properly-cleaned version of the provided value to the given
+   * builder so that it can be safely used in string representations of this
+   * search filter. The formatting changes that may be performed will be in
+   * compliance with the specification in RFC 2254.
+   *
+   * @param builder
+   *          The builder to which the "safe" version of the value will be
+   *          appended.
+   * @param value
+   *          The value to be appended to the builder.
+   */
+  private static void valueToFilterString(final StringBuilder builder,
+      final ByteString value)
+  {
+    // Get the binary representation of the value and iterate through
+    // it to see if there are any unsafe characters. If there are,
+    // then escape them and replace them with a two-digit hex
+    // equivalent.
+    builder.ensureCapacity(builder.length() + value.length());
+    for (int i = 0; i < value.length(); i++)
+    {
+      // TODO: this is a bit overkill - it will escape all non-ascii
+      // chars!
+      final byte b = value.byteAt(i);
+      if (((b & 0x7F) != b) || // Not 7-bit clean
+          (b <= 0x1F) || // Below the printable character range
+          (b == 0x28) || // Open parenthesis
+          (b == 0x29) || // Close parenthesis
+          (b == 0x2A) || // Asterisk
+          (b == 0x5C) || // Backslash
+          (b == 0x7F)) // Delete character
+      {
+        builder.append('\\');
+        builder.append(byteToHex(b));
+      }
+      else
+      {
+        builder.append((char) b);
+      }
+    }
+  }
+
+
+
+  private final Impl pimpl;
+
+
+
+  private Filter(final Impl pimpl)
+  {
+    this.pimpl = pimpl;
+  }
+
+
+
+  /**
+   * Applies a {@code FilterVisitor} to this {@code Filter}.
+   *
+   * @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 filter visitor.
+   * @param p
+   *          Optional additional visitor parameter.
+   * @return A result as specified by the visitor.
+   */
+  public <R, P> R accept(final FilterVisitor<R, P> v, final P p)
+  {
+    return pimpl.accept(v, p);
+  }
+
+
+
+  /**
+   * Returns a {@code Matcher} which can be used to compare this {@code Filter}
+   * against entries using the default schema.
+   *
+   * @return The {@code Matcher}.
+   */
+  public Matcher matcher()
+  {
+    return new Matcher(this, Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Returns a {@code Matcher} which can be used to compare this {@code Filter}
+   * against entries using the provided {@code Schema}.
+   *
+   * @param schema
+   *          The schema which the {@code Matcher} should use for comparisons.
+   * @return The {@code Matcher}.
+   */
+  public Matcher matcher(final Schema schema)
+  {
+    return new Matcher(this, schema);
+  }
+
+
+
+  /**
+   * Indicates whether this {@code Filter} matches the provided {@code Entry}
+   * using the schema associated with the entry.
+   * <p>
+   * Calling this method is equivalent to the following:
+   *
+   * <pre>
+   * boolean b = matcher(entry.getSchema()).matches(entry);
+   * </pre>
+   *
+   * @param entry
+   *          The entry to be matched.
+   * @return {@code true} if this {@code Filter} matches the provided {@code
+   *         Entry}.
+   */
+  public ConditionResult matches(final Entry entry)
+  {
+    return matcher(Schema.getDefaultSchema()).matches(entry);
+  }
+
+
+
+  /**
+   * Returns a {@code String} whose contents is the LDAP string representation
+   * of this {@code Filter}.
+   *
+   * @return The LDAP string representation of this {@code Filter}.
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    return pimpl.accept(TO_STRING_VISITOR, builder).toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FilterVisitor.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FilterVisitor.java
new file mode 100644
index 0000000..e8d56eb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FilterVisitor.java
@@ -0,0 +1,234 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.List;
+
+
+
+/**
+ * A visitor of {@code Filter}s, in the style of the visitor design pattern.
+ * <p>
+ * Classes implementing this interface can query filters in a type-safe manner.
+ * When a visitor is passed to a filter's accept method, the corresponding visit
+ * method most applicable to that filter 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 FilterVisitor<R, P>
+{
+
+  /**
+   * Visits an {@code and} filter.
+   * <p>
+   * <b>Implementation note</b>: for the purposes of matching an empty
+   * sub-filter list should always evaluate to {@code true} as per RFC 4526.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param subFilters
+   *          The unmodifiable list of sub-filters.
+   * @return Returns a visitor specified result.
+   */
+  R visitAndFilter(P p, List<Filter> subFilters);
+
+
+
+  /**
+   * Visits an {@code approximate match} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return Returns a visitor specified result.
+   */
+  R visitApproxMatchFilter(P p, String attributeDescription,
+      ByteString assertionValue);
+
+
+
+  /**
+   * Visits an {@code equality match} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return Returns a visitor specified result.
+   */
+  R visitEqualityMatchFilter(P p, String attributeDescription,
+      ByteString assertionValue);
+
+
+
+  /**
+   * Visits an {@code extensible} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param matchingRule
+   *          The matching rule name, may be {@code null} if {@code
+   *          attributeDescription} is specified.
+   * @param attributeDescription
+   *          The attribute description, may be {@code null} if {@code
+   *          matchingRule} is specified.
+   * @param assertionValue
+   *          The assertion value.
+   * @param dnAttributes
+   *          Indicates whether DN matching should be performed.
+   * @return Returns a visitor specified result.
+   */
+  R visitExtensibleMatchFilter(P p, String matchingRule,
+      String attributeDescription, ByteString assertionValue,
+      boolean dnAttributes);
+
+
+
+  /**
+   * Visits a {@code greater or equal} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return Returns a visitor specified result.
+   */
+  R visitGreaterOrEqualFilter(P p, String attributeDescription,
+      ByteString assertionValue);
+
+
+
+  /**
+   * Visits a {@code less or equal} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param attributeDescription
+   *          The attribute description.
+   * @param assertionValue
+   *          The assertion value.
+   * @return Returns a visitor specified result.
+   */
+  R visitLessOrEqualFilter(P p, String attributeDescription,
+      ByteString assertionValue);
+
+
+
+  /**
+   * Visits a {@code not} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param subFilter
+   *          The sub-filter.
+   * @return Returns a visitor specified result.
+   */
+  R visitNotFilter(P p, Filter subFilter);
+
+
+
+  /**
+   * Visits an {@code or} filter.
+   * <p>
+   * <b>Implementation note</b>: for the purposes of matching an empty
+   * sub-filter list should always evaluate to {@code false} as per RFC 4526.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param subFilters
+   *          The unmodifiable list of sub-filters.
+   * @return Returns a visitor specified result.
+   */
+  R visitOrFilter(P p, List<Filter> subFilters);
+
+
+
+  /**
+   * Visits a {@code present} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param attributeDescription
+   *          The attribute description.
+   * @return Returns a visitor specified result.
+   */
+  R visitPresentFilter(P p, String attributeDescription);
+
+
+
+  /**
+   * Visits a {@code substrings} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param attributeDescription
+   *          The attribute description.
+   * @param initialSubstring
+   *          The initial sub-string, may be {@code null}.
+   * @param anySubstrings
+   *          The unmodifiable list of any sub-strings, may be empty.
+   * @param finalSubstring
+   *          The final sub-string, may be {@code null}.
+   * @return Returns a visitor specified result.
+   */
+  R visitSubstringsFilter(P p, String attributeDescription,
+      ByteString initialSubstring, List<ByteString> anySubstrings,
+      ByteString finalSubstring);
+
+
+
+  /**
+   * Visits an {@code unrecognized} filter.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param filterTag
+   *          The ASN.1 tag.
+   * @param filterBytes
+   *          The filter content.
+   * @return Returns a visitor specified result.
+   */
+  R visitUnrecognizedFilter(P p, byte filterTag, ByteString filterBytes);
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FutureResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FutureResult.java
new file mode 100644
index 0000000..5211a20
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/FutureResult.java
@@ -0,0 +1,139 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+
+
+/**
+ * A handle which can be used to retrieve the Result of an asynchronous Request.
+ *
+ * @param <S>
+ *          The type of result returned by this future.
+ */
+public interface FutureResult<S> extends Future<S>
+{
+  /**
+   * Attempts to cancel the request. This attempt will fail if the request has
+   * already completed or has already been cancelled. If successful, then
+   * cancellation results in an abandon or cancel request (if configured) being
+   * sent to the server.
+   * <p>
+   * After this method returns, subsequent calls to {@link #isDone} will always
+   * return {@code true}. Subsequent calls to {@link #isCancelled} will always
+   * return {@code true} if this method returned {@code true}.
+   *
+   * @param mayInterruptIfRunning
+   *          {@code true} if the thread executing executing the response
+   *          handler should be interrupted; otherwise, in-progress response
+   *          handlers are allowed to complete.
+   * @return {@code false} if the request could not be cancelled, typically
+   *         because it has already completed normally; {@code true} otherwise.
+   */
+  boolean cancel(boolean mayInterruptIfRunning);
+
+
+
+  /**
+   * Waits if necessary for the request to complete, and then returns the result
+   * if the request succeeded. If the request failed (i.e. a non-successful
+   * result code was obtained) then the result is thrown as an
+   * {@link ErrorResultException}.
+   *
+   * @return The result, but only if the result code indicates that the request
+   *         succeeded.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   */
+  S get() throws ErrorResultException, InterruptedException;
+
+
+
+  /**
+   * Waits if necessary for at most the given time for the request to complete,
+   * and then returns the result if the request succeeded. If the request failed
+   * (i.e. a non-successful result code was obtained) then the result is thrown
+   * as an {@link ErrorResultException}.
+   *
+   * @param timeout
+   *          The maximum time to wait.
+   * @param unit
+   *          The time unit of the timeout argument.
+   * @return The result, but only if the result code indicates that the request
+   *         succeeded.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws TimeoutException
+   *           If the wait timed out.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   */
+  S get(long timeout, TimeUnit unit) throws ErrorResultException,
+      TimeoutException, InterruptedException;
+
+
+
+  /**
+   * Returns the request ID of the request if appropriate.
+   *
+   * @return The request ID, or {@code -1} if there is no request ID.
+   */
+  int getRequestID();
+
+
+
+  /**
+   * Returns {@code true} if the request was cancelled before it completed
+   * normally.
+   *
+   * @return {@code true} if the request was cancelled before it completed
+   *         normally, otherwise {@code false}.
+   */
+  boolean isCancelled();
+
+
+
+  /**
+   * Returns {@code true} if the request has completed.
+   * <p>
+   * Completion may be due to normal termination, an exception, or cancellation.
+   * In all of these cases, this method will return {@code true}.
+   *
+   * @return {@code true} if the request has completed, otherwise {@code false}.
+   */
+  boolean isDone();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/HeartBeatConnectionFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/HeartBeatConnectionFactory.java
new file mode 100644
index 0000000..77a29cb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/HeartBeatConnectionFactory.java
@@ -0,0 +1,405 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.responses.SearchResultReference;
+
+import com.sun.opends.sdk.util.AsynchronousConnectionDecorator;
+import com.sun.opends.sdk.util.FutureResultTransformer;
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An heart beat connection factory can be used to create connections that sends
+ * a periodic search request to a Directory Server.
+ */
+final class HeartBeatConnectionFactory extends AbstractConnectionFactory
+{
+  /**
+   * An asynchronous connection that sends heart beats and supports all
+   * operations.
+   */
+  private final class AsynchronousConnectionImpl extends
+      AsynchronousConnectionDecorator implements ConnectionEventListener,
+      SearchResultHandler
+  {
+    private long lastSuccessfulPing;
+
+    private FutureResult<Result> lastPingFuture;
+
+
+
+    private AsynchronousConnectionImpl(final AsynchronousConnection connection)
+    {
+      super(connection);
+    }
+
+
+
+    @Override
+    public void handleConnectionClosed()
+    {
+      notifyClosed();
+    }
+
+
+
+    @Override
+    public void handleConnectionError(final boolean isDisconnectNotification,
+        final ErrorResultException error)
+    {
+      notifyClosed();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean handleEntry(final SearchResultEntry entry)
+    {
+      // Ignore.
+      return true;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      connection.close(Requests.newUnbindRequest(), "Heartbeat retured error: "
+          + error);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean handleReference(final SearchResultReference reference)
+    {
+      // Ignore.
+      return true;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleResult(final Result result)
+    {
+      lastSuccessfulPing = System.currentTimeMillis();
+    }
+
+
+
+    @Override
+    public void handleUnsolicitedNotification(final ExtendedResult notification)
+    {
+      // Do nothing
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isValid()
+    {
+      return connection.isValid()
+          && (lastSuccessfulPing <= 0 || System.currentTimeMillis()
+              - lastSuccessfulPing < unit.toMillis(interval) * 2);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+      final StringBuilder builder = new StringBuilder();
+      builder.append("HeartBeatConnection(");
+      builder.append(connection);
+      builder.append(')');
+      return builder.toString();
+    }
+
+
+
+    private void notifyClosed()
+    {
+      synchronized (activeConnections)
+      {
+        connection.removeConnectionEventListener(this);
+        activeConnections.remove(this);
+
+        if (activeConnections.isEmpty())
+        {
+          // This is the last active connection, so stop the heart beat.
+          heartBeatFuture.cancel(false);
+        }
+      }
+    }
+  }
+
+
+
+  private final class FutureResultImpl extends
+      FutureResultTransformer<AsynchronousConnection, AsynchronousConnection>
+      implements ResultHandler<AsynchronousConnection>
+  {
+
+    private FutureResultImpl(
+        final ResultHandler<? super AsynchronousConnection> handler)
+    {
+      super(handler);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected AsynchronousConnection transformResult(
+        final AsynchronousConnection connection) throws ErrorResultException
+    {
+      final AsynchronousConnectionImpl heartBeatConnection = new AsynchronousConnectionImpl(
+          connection);
+      synchronized (activeConnections)
+      {
+        connection.addConnectionEventListener(heartBeatConnection);
+        if (activeConnections.isEmpty())
+        {
+          // This is the first active connection, so start the heart beat.
+          heartBeatFuture = scheduler.scheduleWithFixedDelay(
+              new HeartBeatRunnable(), 0, interval, unit);
+        }
+        activeConnections.add(heartBeatConnection);
+      }
+      return heartBeatConnection;
+    }
+
+  }
+
+
+
+  private final class HeartBeatRunnable implements Runnable
+  {
+    private HeartBeatRunnable()
+    {
+      // Nothing to do.
+    }
+
+
+
+    @Override
+    public void run()
+    {
+      synchronized (activeConnections)
+      {
+        for (final AsynchronousConnectionImpl connection : activeConnections)
+        {
+          if (connection.lastPingFuture == null
+              || connection.lastPingFuture.isDone())
+          {
+            connection.lastPingFuture = connection.search(heartBeat,
+                connection, null);
+          }
+        }
+      }
+    }
+  }
+
+
+
+  private final SearchRequest heartBeat;
+
+  private final long interval;
+
+  private final ScheduledExecutorService scheduler;
+
+  private final TimeUnit unit;
+
+  private final List<AsynchronousConnectionImpl> activeConnections;
+
+  private final ConnectionFactory factory;
+
+  private static final SearchRequest DEFAULT_SEARCH = Requests
+      .newSearchRequest("", SearchScope.BASE_OBJECT, "(objectClass=*)", "1.1");
+
+  private ScheduledFuture<?> heartBeatFuture;
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections in order to detect that they are still alive every 10 seconds
+   * using the default scheduler.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   */
+  HeartBeatConnectionFactory(final ConnectionFactory factory)
+  {
+    this(factory, 10, TimeUnit.SECONDS, DEFAULT_SEARCH, StaticUtils
+        .getDefaultScheduler());
+  }
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections in order to detect that they are still alive using the
+   * specified frequency and the default scheduler.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   * @param interval
+   *          The interval between keepalive pings.
+   * @param unit
+   *          The time unit for the interval between keepalive pings.
+   */
+  HeartBeatConnectionFactory(final ConnectionFactory factory,
+      final long interval, final TimeUnit unit)
+  {
+    this(factory, interval, unit, DEFAULT_SEARCH, StaticUtils
+        .getDefaultScheduler());
+  }
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections using the specified search request in order to detect that they
+   * are still alive.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   * @param interval
+   *          The interval between keepalive pings.
+   * @param unit
+   *          The time unit for the interval between keepalive pings.
+   * @param heartBeat
+   *          The search request to use for keepalive pings.
+   */
+  HeartBeatConnectionFactory(final ConnectionFactory factory,
+      final long interval, final TimeUnit unit, final SearchRequest heartBeat)
+  {
+    this(factory, interval, unit, heartBeat, StaticUtils.getDefaultScheduler());
+  }
+
+
+
+  /**
+   * Creates a new heart-beat connection factory which will create connections
+   * using the provided connection factory and periodically ping any created
+   * connections using the specified search request in order to detect that they
+   * are still alive.
+   *
+   * @param factory
+   *          The connection factory to use for creating connections.
+   * @param interval
+   *          The interval between keepalive pings.
+   * @param unit
+   *          The time unit for the interval between keepalive pings.
+   * @param heartBeat
+   *          The search request to use for keepalive pings.
+   * @param scheduler
+   *          The scheduler which should for periodically sending keepalive
+   *          pings.
+   */
+  HeartBeatConnectionFactory(final ConnectionFactory factory,
+      final long interval, final TimeUnit unit, final SearchRequest heartBeat,
+      final ScheduledExecutorService scheduler)
+  {
+    Validator.ensureNotNull(factory, heartBeat, unit, scheduler);
+    Validator.ensureTrue(interval >= 0, "negative timeout");
+
+    this.heartBeat = heartBeat;
+    this.interval = interval;
+    this.unit = unit;
+    this.activeConnections = new LinkedList<AsynchronousConnectionImpl>();
+    this.factory = factory;
+    this.scheduler = scheduler;
+  }
+
+
+
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> handler)
+  {
+    final FutureResultImpl future = new FutureResultImpl(handler);
+    future.setFutureResult(factory.getAsynchronousConnection(future));
+    return future;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("HeartBeatConnectionFactory(");
+    builder.append(String.valueOf(factory));
+    builder.append(')');
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/IntermediateResponseHandler.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/IntermediateResponseHandler.java
new file mode 100644
index 0000000..43573da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/IntermediateResponseHandler.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.IntermediateResponse;
+
+
+
+/**
+ * A completion handler for consuming intermediate responses returned from
+ * extended operations, or other operations for which an appropriate control was
+ * sent.
+ * <p>
+ * {@link Connection} objects support intermediate responses for extended
+ * operations only via the {@link Connection#extendedRequest}
+ * method. {@link AsynchronousConnection} objects support intermediate responses
+ * for extended operations, and all other operation types for which appropriate
+ * controls were used. When no handler is provided any intermediate responses
+ * will be discarded.
+ * <p>
+ * The {@link #handleIntermediateResponse} method is invoked each time a
+ * Intermediate Response is returned from the Directory Server.
+ * <p>
+ * Implementations of these methods should complete in a timely manner so as to
+ * avoid keeping the invoking thread from dispatching to other completion
+ * handlers.
+ */
+public interface IntermediateResponseHandler
+{
+  /**
+   * Invoked each time an intermediate response is returned from the Directory
+   * Server.
+   *
+   * @param response
+   *          The intermediate response.
+   * @return {@code true} if this handler should continue to be notified of any
+   *         remaining intermediate responses, or {@code false} if the remaining
+   *         responses should be skipped for some reason (e.g. a client side
+   *         size limit has been reached).
+   */
+  boolean handleIntermediateResponse(IntermediateResponse response);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/InternalConnectionFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/InternalConnectionFactory.java
new file mode 100644
index 0000000..90d248e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/InternalConnectionFactory.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import com.sun.opends.sdk.ldap.InternalConnection;
+import com.sun.opends.sdk.util.CompletedFutureResult;
+
+
+
+/**
+ * A special {@code ConnectionFactory} which waits for internal connection
+ * requests and binds them to a {@link ServerConnection} created using the
+ * provided {@link ServerConnectionFactory}.
+ * <p>
+ * When processing requests, {@code ServerConnection} implementations are passed
+ * an integer as the first parameter. This integer represents a pseudo
+ * {@code requestID} which is incremented for each successive internal request
+ * on a per connection basis. The request ID may be useful for logging purposes.
+ * <p>
+ * An {@code InternalConnectionFactory} does not require
+ * {@code ServerConnection} implementations to return a result when processing
+ * requests. However, it is recommended that implementations do always return
+ * results even for abandoned requests. This is because application client
+ * threads may block indefinitely waiting for results.
+ *
+ * @param <C>
+ *          The type of client context.
+ */
+final class InternalConnectionFactory<C> extends AbstractConnectionFactory
+{
+
+  private final ServerConnectionFactory<C, Integer> factory;
+
+  private final C clientContext;
+
+
+
+  InternalConnectionFactory(final ServerConnectionFactory<C, Integer> factory,
+      final C clientContext)
+  {
+    this.factory = factory;
+    this.clientContext = clientContext;
+  }
+
+
+
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> handler)
+  {
+    final ServerConnection<Integer> serverConnection;
+    try
+    {
+      serverConnection = factory.handleAccept(clientContext);
+    }
+    catch (final ErrorResultException e)
+    {
+      if (handler != null)
+      {
+        handler.handleErrorResult(e);
+      }
+      return new CompletedFutureResult<AsynchronousConnection>(e);
+    }
+
+    final InternalConnection connection = new InternalConnection(
+        serverConnection);
+    if (handler != null)
+    {
+      handler.handleResult(connection);
+    }
+    return new CompletedFutureResult<AsynchronousConnection>(connection);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("InternalConnectionFactory(");
+    builder.append(String.valueOf(clientContext));
+    builder.append(',');
+    builder.append(String.valueOf(factory));
+    builder.append(')');
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/KeyManagers.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/KeyManagers.java
new file mode 100644
index 0000000..4d2322f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/KeyManagers.java
@@ -0,0 +1,398 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.security.*;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class contains methods for creating common types of key manager.
+ */
+public final class KeyManagers
+{
+  /**
+   * This class implements an X.509 key manager that will be used to wrap an
+   * existing key manager and makes it possible to configure which
+   * certificate(s) should be used for client and/or server operations. The
+   * certificate selection will be based on the alias (also called the nickname)
+   * of the certificate.
+   */
+  private static final class SelectCertificate extends X509ExtendedKeyManager
+  {
+    private final String alias;
+    private final X509KeyManager keyManager;
+
+
+
+    private SelectCertificate(final X509KeyManager keyManager,
+        final String alias)
+    {
+      this.keyManager = keyManager;
+      this.alias = alias;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String chooseClientAlias(final String[] keyType,
+        final Principal[] issuers, final Socket socket)
+    {
+      for (final String type : keyType)
+      {
+        final String[] clientAliases = keyManager.getClientAliases(type,
+            issuers);
+        if (clientAliases != null)
+        {
+          for (final String clientAlias : clientAliases)
+          {
+            if (clientAlias.equals(alias))
+            {
+              return alias;
+            }
+          }
+        }
+      }
+
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String chooseEngineClientAlias(final String[] keyType,
+        final Principal[] issuers, final SSLEngine engine)
+    {
+      for (final String type : keyType)
+      {
+        final String[] clientAliases = keyManager.getClientAliases(type,
+            issuers);
+        if (clientAliases != null)
+        {
+          for (final String clientAlias : clientAliases)
+          {
+            if (clientAlias.equals(alias))
+            {
+              return alias;
+            }
+          }
+        }
+      }
+
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String chooseEngineServerAlias(final String keyType,
+        final Principal[] issuers, final SSLEngine engine)
+    {
+      final String[] serverAliases = keyManager.getServerAliases(keyType,
+          issuers);
+      if (serverAliases != null)
+      {
+        for (final String serverAlias : serverAliases)
+        {
+          if (serverAlias.equalsIgnoreCase(alias))
+          {
+            return serverAlias;
+          }
+        }
+      }
+
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String chooseServerAlias(final String keyType,
+        final Principal[] issuers, final Socket socket)
+    {
+      final String[] serverAliases = keyManager.getServerAliases(keyType,
+          issuers);
+      if (serverAliases != null)
+      {
+        for (final String serverAlias : serverAliases)
+        {
+          if (serverAlias.equals(alias))
+          {
+            return alias;
+          }
+        }
+      }
+
+      return null;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public X509Certificate[] getCertificateChain(final String alias)
+    {
+      return keyManager.getCertificateChain(alias);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String[] getClientAliases(final String keyType,
+        final Principal[] issuers)
+    {
+      return keyManager.getClientAliases(keyType, issuers);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PrivateKey getPrivateKey(final String alias)
+    {
+      return keyManager.getPrivateKey(alias);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String[] getServerAliases(final String keyType,
+        final Principal[] issuers)
+    {
+      return keyManager.getServerAliases(keyType, issuers);
+    }
+  }
+
+
+
+  /**
+   * Creates a new {@code X509KeyManager} which will use the named key store
+   * file for retrieving certificates. It will use the default key store format
+   * for the JVM (e.g. {@code JKS}) and will not use a password to open the key
+   * store.
+   *
+   * @param file
+   *          The key store file name.
+   * @return A new {@code X509KeyManager} which will use the named key store
+   *         file for retrieving certificates.
+   * @throws GeneralSecurityException
+   *           If the key store could not be loaded, perhaps due to incorrect
+   *           format, or missing algorithms.
+   * @throws IOException
+   *           If the key store file could not be found or could not be read.
+   * @throws NullPointerException
+   *           If {@code file} was {@code null}.
+   */
+  public static X509KeyManager useKeyStoreFile(final String file)
+      throws GeneralSecurityException, IOException, NullPointerException
+  {
+    return useKeyStoreFile(file, null, null);
+  }
+
+
+
+  /**
+   * Creates a new {@code X509KeyManager} which will use the named key store
+   * file for retrieving certificates. It will use the provided key store format
+   * and password.
+   *
+   * @param file
+   *          The key store file name.
+   * @param password
+   *          The key store password, which may be {@code null}.
+   * @param format
+   *          The key store format, which may be {@code null} to indicate that
+   *          the default key store format for the JVM (e.g. {@code JKS}) should
+   *          be used.
+   * @return A new {@code X509KeyManager} which will use the named key store
+   *         file for retrieving certificates.
+   * @throws GeneralSecurityException
+   *           If the key store could not be loaded, perhaps due to incorrect
+   *           format, or missing algorithms.
+   * @throws IOException
+   *           If the key store file could not be found or could not be read.
+   * @throws NullPointerException
+   *           If {@code file} was {@code null}.
+   */
+  public static X509KeyManager useKeyStoreFile(final String file,
+      final char[] password, final String format)
+      throws GeneralSecurityException, IOException, NullPointerException
+  {
+    Validator.ensureNotNull(file);
+
+    final File keyStoreFile = new File(file);
+    final String keyStoreFormat = format != null ? format : KeyStore
+        .getDefaultType();
+
+    final KeyStore keyStore = KeyStore.getInstance(keyStoreFormat);
+
+    FileInputStream fos = null;
+    try
+    {
+      fos = new FileInputStream(keyStoreFile);
+      keyStore.load(fos, password);
+    }
+    finally
+    {
+      if (fos != null)
+      {
+        try
+        {
+          fos.close();
+        }
+        catch (final IOException ignored)
+        {
+          // Ignore.
+        }
+      }
+    }
+
+    final KeyManagerFactory kmf = KeyManagerFactory
+        .getInstance(KeyManagerFactory.getDefaultAlgorithm());
+    kmf.init(keyStore, password);
+
+    X509KeyManager x509km = null;
+    for (final KeyManager km : kmf.getKeyManagers())
+    {
+      if (km instanceof X509KeyManager)
+      {
+        x509km = (X509KeyManager) km;
+        break;
+      }
+    }
+
+    if (x509km == null)
+    {
+      throw new NoSuchAlgorithmException();
+    }
+
+    return x509km;
+  }
+
+
+
+  /**
+   * Creates a new {@code X509KeyManager} which will use a PKCS#11 token for
+   * retrieving certificates.
+   *
+   * @param password
+   *          The password to use for accessing the PKCS#11 token, which may be
+   *          {@code null} if no password is required.
+   * @return A new {@code X509KeyManager} which will use a PKCS#11 token for
+   *         retrieving certificates.
+   * @throws GeneralSecurityException
+   *           If the PKCS#11 token could not be accessed, perhaps due to
+   *           incorrect password, or missing algorithms.
+   * @throws IOException
+   *           If the PKCS#11 token could not be found or could not be read.
+   */
+  public static X509KeyManager usePKCS11Token(final char[] password)
+      throws GeneralSecurityException, IOException
+  {
+    final KeyStore keyStore = KeyStore.getInstance("PKCS11");
+    keyStore.load(null, password);
+    final KeyManagerFactory kmf = KeyManagerFactory
+        .getInstance(KeyManagerFactory.getDefaultAlgorithm());
+    kmf.init(keyStore, password);
+
+    X509KeyManager x509km = null;
+    for (final KeyManager km : kmf.getKeyManagers())
+    {
+      if (km instanceof X509KeyManager)
+      {
+        x509km = (X509KeyManager) km;
+        break;
+      }
+    }
+
+    if (x509km == null)
+    {
+      throw new NoSuchAlgorithmException();
+    }
+
+    return x509km;
+  }
+
+
+
+  /**
+   * Returns a new {@code X509KeyManager} which selects the named certificate
+   * from the provided {@code X509KeyManager}.
+   *
+   * @param alias
+   *          The nickname of the certificate that should be selected for
+   *          operations involving this key manager.
+   * @param keyManager
+   *          The key manager to be filtered.
+   * @return The filtered key manager.
+   * @throws NullPointerException
+   *           If {@code keyManager} or {@code alias} was {@code null}.
+   */
+  public static X509KeyManager useSingleCertificate(final String alias,
+      final X509KeyManager keyManager) throws NullPointerException
+  {
+    Validator.ensureNotNull(alias, keyManager);
+    return new SelectCertificate(keyManager, alias);
+  }
+
+
+
+  // Prevent insantiation.
+  private KeyManagers()
+  {
+    // Nothing to do.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPClientContext.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPClientContext.java
new file mode 100644
index 0000000..22a2f93
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPClientContext.java
@@ -0,0 +1,171 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.net.InetSocketAddress;
+
+import javax.net.ssl.SSLContext;
+
+import org.opends.sdk.responses.ExtendedResult;
+
+
+
+/**
+ * An LDAP client which has connected to a {@link ServerConnectionFactory}. An
+ * LDAP client context can be used to query information about the client's
+ * connection such as their network address, as well as managing the state of
+ * the connection.
+ */
+public interface LDAPClientContext
+{
+
+  /**
+   * Disconnects the client without sending a disconnect notification.
+   * <p>
+   * <b>Server connections:</b> invoking this method causes
+   * {@link ServerConnection#handleConnectionDisconnected
+   * handleConnectionDisconnected} to be called before this method returns.
+   */
+  void disconnect();
+
+
+
+  /**
+   * Disconnects the client and sends a disconnect notification, if possible,
+   * containing the provided result code and diagnostic message.
+   * <p>
+   * <b>Server connections:</b> invoking this method causes
+   * {@link ServerConnection#handleConnectionDisconnected
+   * handleConnectionDisconnected} to be called before this method returns.
+   *
+   * @param resultCode
+   *          The result code which should be included with the disconnect
+   *          notification.
+   * @param message
+   *          The diagnostic message, which may be empty or {@code null}
+   *          indicating that none was provided.
+   */
+  void disconnect(ResultCode resultCode, String message);
+
+
+
+  /**
+   * Returns the {@code InetSocketAddress} associated with the local system.
+   *
+   * @return The {@code InetSocketAddress} associated with the local system.
+   */
+  InetSocketAddress getLocalAddress();
+
+
+
+  /**
+   * Returns the {@code InetSocketAddress} associated with the remote system.
+   *
+   * @return The {@code InetSocketAddress} associated with the remote system.
+   */
+  InetSocketAddress getPeerAddress();
+
+
+
+  /**
+   * Returns the strongest cipher strength currently in use by the underlying
+   * connection.
+   *
+   * @return The strongest cipher strength currently in use by the underlying
+   *         connection.
+   */
+  int getSecurityStrengthFactor();
+
+
+
+  /**
+   * Returns {@code true} if the underlying connection has been closed as a
+   * result of a client disconnect, a fatal connection error, or a server-side
+   * {@link #disconnect}.
+   * <p>
+   * This method provides a polling mechanism which can be used by synchronous
+   * request handler implementations to detect connection termination.
+   * <p>
+   * <b>Server connections:</b> this method will always return {@code true} when
+   * called from within {@link ServerConnection#handleConnectionClosed
+   * handleConnectionClosed},
+   * {@link ServerConnection#handleConnectionDisconnected
+   * handleConnectionDisconnected}, or
+   * {@link ServerConnection#handleConnectionError handleConnectionError}.
+   *
+   * @return {@code true} if the underlying connection has been closed.
+   */
+  boolean isClosed();
+
+
+
+  /**
+   * Sends an unsolicited notification to the client.
+   *
+   * @param notification
+   *          The notification to send.
+   */
+  void sendUnsolicitedNotification(ExtendedResult notification);
+
+
+
+  /**
+   * Starts the SASL integrity and/or confidentiality protection layer on the
+   * underlying connection if possible.
+   *
+   * @param bindContext
+   *          The negotiated bind context that can be used to encode and decode
+   *          data on the connection.
+   */
+  void startSASL(ConnectionSecurityLayer bindContext);
+
+
+
+  /**
+   * Starts the TLS/SSL security layer on the underlying connection if possible.
+   *
+   * @param sslContext
+   *          The {@code SSLContext} which should be used to secure the
+   * @param protocols
+   *          Names of all the protocols to enable or {@code null} to use the
+   *          default protocols.
+   * @param suites
+   *          Names of all the suites to enable or {@code null} to use the
+   *          default cipher suites.
+   * @param wantClientAuth
+   *          Set to {@code true} if client authentication is requested, or
+   *          {@code false} if no client authentication is desired.
+   * @param needClientAuth
+   *          Set to {@code true} if client authentication is required, or
+   *          {@code false} if no client authentication is desired.
+   */
+  void startTLS(SSLContext sslContext, String[] protocols, String[] suites,
+      boolean wantClientAuth, boolean needClientAuth);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPConnectionFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPConnectionFactory.java
new file mode 100644
index 0000000..a632071
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPConnectionFactory.java
@@ -0,0 +1,244 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+
+import com.sun.opends.sdk.ldap.LDAPConnectionFactoryImpl;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A factory class which can be used to obtain connections to an LDAP Directory
+ * Server.
+ */
+public final class LDAPConnectionFactory implements ConnectionFactory
+{
+  // We implement the factory using the pimpl idiom in order have
+  // cleaner Javadoc which does not expose implementation methods from
+  // AbstractConnectionFactory.
+
+  private final LDAPConnectionFactoryImpl impl;
+
+
+
+  /**
+   * Creates a new LDAP connection factory which can be used to create LDAP
+   * connections to the Directory Server at the provided address.
+   *
+   * @param address
+   *          The address of the Directory Server.
+   * @throws NullPointerException
+   *           If {@code address} was {@code null}.
+   */
+  public LDAPConnectionFactory(final SocketAddress address)
+      throws NullPointerException
+  {
+    this(address, new LDAPOptions());
+  }
+
+
+
+  /**
+   * Creates a new LDAP connection factory which can be used to create LDAP
+   * connections to the Directory Server at the provided address.
+   *
+   * @param address
+   *          The address of the Directory Server.
+   * @param options
+   *          The LDAP options to use when creating connections.
+   * @throws NullPointerException
+   *           If {@code address} or {@code options} was {@code null}.
+   */
+  public LDAPConnectionFactory(final SocketAddress address,
+      final LDAPOptions options) throws NullPointerException
+  {
+    Validator.ensureNotNull(address, options);
+    this.impl = new LDAPConnectionFactoryImpl(address, options);
+  }
+
+
+
+  /**
+   * Creates a new LDAP connection factory which can be used to create LDAP
+   * connections to the Directory Server at the provided host and port address.
+   *
+   * @param host
+   *          The host name.
+   * @param port
+   *          The port number.
+   * @throws NullPointerException
+   *           If {@code host} was {@code null}.
+   */
+  public LDAPConnectionFactory(final String host, final int port)
+      throws NullPointerException
+  {
+    this(host, port, new LDAPOptions());
+  }
+
+
+
+  /**
+   * Creates a new LDAP connection factory which can be used to create LDAP
+   * connections to the Directory Server at the provided host and port address.
+   *
+   * @param host
+   *          The host name.
+   * @param port
+   *          The port number.
+   * @param options
+   *          The LDAP options to use when creating connections.
+   * @throws NullPointerException
+   *           If {@code host} or {@code options} was {@code null}.
+   */
+  public LDAPConnectionFactory(final String host, final int port,
+      final LDAPOptions options) throws NullPointerException
+  {
+    Validator.ensureNotNull(host, options);
+    final SocketAddress address = new InetSocketAddress(host, port);
+    this.impl = new LDAPConnectionFactoryImpl(address, options);
+  }
+
+
+
+  /**
+   * Returns the {@code InetAddress} that this LDAP listener is listening on.
+   *
+   * @return The {@code InetAddress} that this LDAP listener is listening on, or
+   *         {@code null} if it is unknown.
+   */
+  public InetAddress getAddress()
+  {
+    final SocketAddress socketAddress = getSocketAddress();
+    if (socketAddress instanceof InetSocketAddress)
+    {
+      final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
+      return inetSocketAddress.getAddress();
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> handler)
+  {
+    return impl.getAsynchronousConnection(handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Connection getConnection() throws ErrorResultException,
+      InterruptedException
+  {
+    return impl.getConnection();
+  }
+
+
+
+  /**
+   * Returns the host name that this LDAP listener is listening on.
+   *
+   * @return The host name that this LDAP listener is listening on, or
+   *         {@code null} if it is unknown.
+   */
+  public String getHostname()
+  {
+    final SocketAddress socketAddress = getSocketAddress();
+    if (socketAddress instanceof InetSocketAddress)
+    {
+      final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
+      return inetSocketAddress.getHostName();
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Returns the port that this LDAP listener is listening on.
+   *
+   * @return The port that this LDAP listener is listening on, or {@code -1} if
+   *         it is unknown.
+   */
+  public int getPort()
+  {
+    final SocketAddress socketAddress = getSocketAddress();
+    if (socketAddress instanceof InetSocketAddress)
+    {
+      final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
+      return inetSocketAddress.getPort();
+    }
+    else
+    {
+      return -1;
+    }
+  }
+
+
+
+  /**
+   * Returns the address that this LDAP listener is listening on.
+   *
+   * @return The address that this LDAP listener is listening on.
+   */
+  public SocketAddress getSocketAddress()
+  {
+    return impl.getSocketAddress();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return impl.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListener.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListener.java
new file mode 100644
index 0000000..619abaa
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListener.java
@@ -0,0 +1,383 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+
+import com.sun.opends.sdk.ldap.LDAPListenerImpl;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An LDAP server connection listener which waits for LDAP connection requests
+ * to come in over the network and binds them to a {@link ServerConnection}
+ * created using the provided {@link ServerConnectionFactory}.
+ * <p>
+ * When processing requests, {@code ServerConnection} implementations are passed
+ * an integer as the first parameter. This integer represents the
+ * {@code requestID} associated with the client request and corresponds to the
+ * {@code requestID} passed as a parameter to abandon and cancel extended
+ * requests. The request ID may also be useful for logging purposes.
+ * <p>
+ * An {@code LDAPListener} does not require {@code ServerConnection}
+ * implementations to return a result when processing requests. More
+ * specifically, an {@code LDAPListener} does not maintain any internal state
+ * information associated with each request which must be released. This is
+ * useful when implementing LDAP abandon operations which may prevent results
+ * being sent for abandoned operations.
+ * <p>
+ * The following code illustrates how to create a simple LDAP server:
+ *
+ * <pre>
+ * class MyClientConnection implements ServerConnection&lt;Integer&gt;
+ * {
+ *   private final LDAPClientContext clientContext;
+ *
+ *
+ *
+ *   private MyClientConnection(LDAPClientContext clientContext)
+ *   {
+ *     this.clientContext = clientContext;
+ *   }
+ *
+ *
+ *
+ *   public void add(Integer requestID, AddRequest request,
+ *       ResultHandler&lt;Result&gt; handler,
+ *       IntermediateResponseHandler intermediateResponseHandler)
+ *       throws UnsupportedOperationException
+ *   {
+ *     // ...
+ *   }
+ *
+ *   // ...
+ *
+ * }
+ *
+ *
+ *
+ * class MyServer implements
+ *     ServerConnectionFactory&lt;LDAPClientContext, RequestContext&gt;
+ * {
+ *   public ServerConnection&lt;RequestContext&gt; accept(LDAPClientContext context)
+ *   {
+ *     System.out.println(&quot;Connection from: &quot; + context.getPeerAddress());
+ *     return new MyClientConnection(context);
+ *   }
+ * }
+ *
+ *
+ *
+ * public static void main(String[] args) throws Exception
+ * {
+ *   LDAPListener listener = new LDAPListener(1389, new MyServer());
+ *
+ *   // ...
+ *
+ *   listener.close();
+ * }
+ * </pre>
+ */
+public final class LDAPListener implements Closeable
+{
+  // We implement the factory using the pimpl idiom in order have
+  // cleaner Javadoc which does not expose implementation methods.
+
+  private final LDAPListenerImpl impl;
+
+
+
+  /**
+   * Creates a new LDAP listener implementation which will listen for LDAP
+   * client connections at the provided address.
+   *
+   * @param port
+   *          The port to listen on.
+   * @param factory
+   *          The server connection factory which will be used to create server
+   *          connections.
+   * @throws IOException
+   *           If an error occurred while trying to listen on the provided
+   *           address.
+   * @throws NullPointerException
+   *           If {code factory} was {@code null}.
+   */
+  public LDAPListener(final int port,
+      final ServerConnectionFactory<LDAPClientContext, Integer> factory)
+      throws IOException, NullPointerException
+  {
+    this(port, factory, new LDAPListenerOptions());
+  }
+
+
+
+  /**
+   * Creates a new LDAP listener implementation which will listen for LDAP
+   * client connections at the provided address.
+   *
+   * @param port
+   *          The port to listen on.
+   * @param factory
+   *          The server connection factory which will be used to create server
+   *          connections.
+   * @param options
+   *          The LDAP listener options.
+   * @throws IOException
+   *           If an error occurred while trying to listen on the provided
+   *           address.
+   * @throws NullPointerException
+   *           If {code factory} or {@code options} was {@code null}.
+   */
+  public LDAPListener(final int port,
+      final ServerConnectionFactory<LDAPClientContext, Integer> factory,
+      final LDAPListenerOptions options) throws IOException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(factory, options);
+    final SocketAddress address = new InetSocketAddress(port);
+    this.impl = new LDAPListenerImpl(address, factory, options);
+  }
+
+
+
+  /**
+   * Creates a new LDAP listener implementation which will listen for LDAP
+   * client connections at the provided address.
+   *
+   * @param address
+   *          The address to listen on.
+   * @param factory
+   *          The server connection factory which will be used to create server
+   *          connections.
+   * @throws IOException
+   *           If an error occurred while trying to listen on the provided
+   *           address.
+   * @throws NullPointerException
+   *           If {@code address} or {code factory} was {@code null}.
+   */
+  public LDAPListener(final SocketAddress address,
+      final ServerConnectionFactory<LDAPClientContext, Integer> factory)
+      throws IOException, NullPointerException
+  {
+    this(address, factory, new LDAPListenerOptions());
+  }
+
+
+
+  /**
+   * Creates a new LDAP listener implementation which will listen for LDAP
+   * client connections at the provided address.
+   *
+   * @param address
+   *          The address to listen on.
+   * @param factory
+   *          The server connection factory which will be used to create server
+   *          connections.
+   * @param options
+   *          The LDAP listener options.
+   * @throws IOException
+   *           If an error occurred while trying to listen on the provided
+   *           address.
+   * @throws NullPointerException
+   *           If {@code address}, {code factory}, or {@code options} was
+   *           {@code null}.
+   */
+  public LDAPListener(final SocketAddress address,
+      final ServerConnectionFactory<LDAPClientContext, Integer> factory,
+      final LDAPListenerOptions options) throws IOException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(address, factory, options);
+    this.impl = new LDAPListenerImpl(address, factory, options);
+  }
+
+
+
+  /**
+   * Creates a new LDAP listener implementation which will listen for LDAP
+   * client connections at the provided address.
+   *
+   * @param host
+   *          The address to listen on.
+   * @param port
+   *          The port to listen on.
+   * @param factory
+   *          The server connection factory which will be used to create server
+   *          connections.
+   * @throws IOException
+   *           If an error occurred while trying to listen on the provided
+   *           address.
+   * @throws NullPointerException
+   *           If {@code host} or {code factory} was {@code null}.
+   */
+  public LDAPListener(final String host, final int port,
+      final ServerConnectionFactory<LDAPClientContext, Integer> factory)
+      throws IOException, NullPointerException
+  {
+    this(host, port, factory, new LDAPListenerOptions());
+  }
+
+
+
+  /**
+   * Creates a new LDAP listener implementation which will listen for LDAP
+   * client connections at the provided address.
+   *
+   * @param host
+   *          The address to listen on.
+   * @param port
+   *          The port to listen on.
+   * @param factory
+   *          The server connection factory which will be used to create server
+   *          connections.
+   * @param options
+   *          The LDAP listener options.
+   * @throws IOException
+   *           If an error occurred while trying to listen on the provided
+   *           address.
+   * @throws NullPointerException
+   *           If {@code host}, {code factory}, or {@code options} was
+   *           {@code null}.
+   */
+  public LDAPListener(final String host, final int port,
+      final ServerConnectionFactory<LDAPClientContext, Integer> factory,
+      final LDAPListenerOptions options) throws IOException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(host, factory, options);
+    final SocketAddress address = new InetSocketAddress(host, port);
+    this.impl = new LDAPListenerImpl(address, factory, options);
+  }
+
+
+
+  /**
+   * Closes this LDAP connection listener.
+   */
+  @Override
+  public void close()
+  {
+    impl.close();
+  }
+
+
+
+  /**
+   * Returns the {@code InetAddress} that this LDAP listener is listening on.
+   *
+   * @return The {@code InetAddress} that this LDAP listener is listening on, or
+   *         {@code null} if it is unknown.
+   */
+  public InetAddress getAddress()
+  {
+    final SocketAddress socketAddress = getSocketAddress();
+    if (socketAddress instanceof InetSocketAddress)
+    {
+      final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
+      return inetSocketAddress.getAddress();
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Returns the host name that this LDAP listener is listening on.
+   *
+   * @return The host name that this LDAP listener is listening on, or
+   *         {@code null} if it is unknown.
+   */
+  public String getHostname()
+  {
+    final SocketAddress socketAddress = getSocketAddress();
+    if (socketAddress instanceof InetSocketAddress)
+    {
+      final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
+      return inetSocketAddress.getHostName();
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  /**
+   * Returns the port that this LDAP listener is listening on.
+   *
+   * @return The port that this LDAP listener is listening on, or {@code -1} if
+   *         it is unknown.
+   */
+  public int getPort()
+  {
+    final SocketAddress socketAddress = getSocketAddress();
+    if (socketAddress instanceof InetSocketAddress)
+    {
+      final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
+      return inetSocketAddress.getPort();
+    }
+    else
+    {
+      return -1;
+    }
+  }
+
+
+
+  /**
+   * Returns the address that this LDAP listener is listening on.
+   *
+   * @return The address that this LDAP listener is listening on.
+   */
+  public SocketAddress getSocketAddress()
+  {
+    return impl.getSocketAddress();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    return impl.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListenerOptions.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListenerOptions.java
new file mode 100644
index 0000000..a2b5815
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPListenerOptions.java
@@ -0,0 +1,229 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import javax.net.ssl.SSLContext;
+
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Common options for LDAP listeners.
+ */
+public final class LDAPListenerOptions
+{
+
+  private SSLContext sslContext;
+
+  private DecodeOptions decodeOptions;
+
+  private int backlog;
+
+  private TCPNIOTransport transport;
+
+
+
+  /**
+   * Creates a new set of listener options with default settings. SSL will not
+   * be enabled, and a default set of decode options will be used.
+   */
+  public LDAPListenerOptions()
+  {
+    this.sslContext = null;
+    this.backlog = 0;
+    this.decodeOptions = new DecodeOptions();
+    this.transport = null;
+  }
+
+
+
+  /**
+   * Creates a new set of listener options having the same initial set of
+   * options as the provided set of listener options.
+   *
+   * @param options
+   *          The set of listener options to be copied.
+   */
+  public LDAPListenerOptions(final LDAPListenerOptions options)
+  {
+    this.sslContext = options.sslContext;
+    this.backlog = options.backlog;
+    this.decodeOptions = new DecodeOptions(options.decodeOptions);
+    this.transport = options.transport;
+  }
+
+
+
+  /**
+   * Returns the maximum queue length for incoming connections requests. If a
+   * connection request arrives when the queue is full, the connection is
+   * refused. If the backlog is less than {@code 1} then a default value of
+   * {@code 50} will be used.
+   *
+   * @return The maximum queue length for incoming connections requests.
+   */
+  public final int getBacklog()
+  {
+    return backlog;
+  }
+
+
+
+  /**
+   * Returns the decoding options which will be used to control how requests and
+   * responses are decoded.
+   *
+   * @return The decoding options which will be used to control how requests and
+   *         responses are decoded (never {@code null}).
+   */
+  public final DecodeOptions getDecodeOptions()
+  {
+    return decodeOptions;
+  }
+
+
+
+  /**
+   * Returns the SSL context which will be used when initiating connections with
+   * the Directory Server. By default no SSL context will be used, indicating
+   * that connections will not be secured. If a non-{@code null} SSL context is
+   * returned then connections will be secured using either SSL or StartTLS.
+   *
+   * @return The SSL context which will be used when initiating secure
+   *         connections with the Directory Server, which may be {@code null}
+   *         indicating that connections will not be secured.
+   */
+  public final SSLContext getSSLContext()
+  {
+    return sslContext;
+  }
+
+
+
+  /**
+   * Returns the Grizzly TCP transport which will be used when initiating
+   * connections with the Directory Server. By default this method will return
+   * {@code null} indicating that the default transport factory should be
+   * used to obtain a TCP transport.
+   *
+   * @return The Grizzly TCP transport which will be used when initiating
+   *         connections with the Directory Server, or {@code null} if the
+   *         default transport factory should be used to obtain a TCP
+   *         transport.
+   */
+  public final TCPNIOTransport getTCPNIOTransport()
+  {
+    return transport;
+  }
+
+
+
+  /**
+   * Sets the maximum queue length for incoming connections requests. If a
+   * connection request arrives when the queue is full, the connection is
+   * refused. If the backlog is less than {@code 1} then a default value of
+   * {@code 50} will be used.
+   *
+   * @param backlog
+   *          The maximum queue length for incoming connections requests.
+   * @return A reference to this LDAP listener options.
+   */
+  public final LDAPListenerOptions setBacklog(final int backlog)
+  {
+    this.backlog = backlog;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the decoding options which will be used to control how requests and
+   * responses are decoded.
+   *
+   * @param decodeOptions
+   *          The decoding options which will be used to control how requests
+   *          and responses are decoded (never {@code null}).
+   * @return A reference to this LDAP listener options.
+   * @throws NullPointerException
+   *           If {@code decodeOptions} was {@code null}.
+   */
+  public final LDAPListenerOptions setDecodeOptions(
+      final DecodeOptions decodeOptions) throws NullPointerException
+  {
+    Validator.ensureNotNull(decodeOptions);
+    this.decodeOptions = decodeOptions;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the SSL context which will be used when initiating connections with
+   * the Directory Server. By default no SSL context will be used, indicating
+   * that connections will not be secured. If a non-{@code null} SSL context is
+   * returned then connections will be secured using either SSL or StartTLS.
+   *
+   * @param sslContext
+   *          The SSL context which will be used when initiating secure
+   *          connections with the Directory Server, which may be {@code null}
+   *          indicating that connections will not be secured.
+   * @return A reference to this LDAP listener options.
+   */
+  public final LDAPListenerOptions setSSLContext(final SSLContext sslContext)
+  {
+    this.sslContext = sslContext;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the Grizzly TCP transport which will be used when initiating
+   * connections with the Directory Server. By default this method will return
+   * {@code null} indicating that the default transport factory should be
+   * used to obtain a TCP transport.
+   *
+   * @param transport
+   *          The Grizzly TCP transport which will be used when initiating
+   *          connections with the Directory Server, or {@code null} if the
+   *          default transport factory should be used to obtain a TCP
+   *          transport.
+   * @return A reference to this connection options.
+   */
+  public final LDAPListenerOptions setTCPNIOTransport(
+      final TCPNIOTransport transport)
+  {
+    this.transport = transport;
+    return this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPOptions.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPOptions.java
new file mode 100644
index 0000000..ac0acaa
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPOptions.java
@@ -0,0 +1,350 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLContext;
+
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Common options for LDAP client connections.
+ */
+public final class LDAPOptions
+{
+  private SSLContext sslContext;
+
+  private boolean useStartTLS;
+
+  private long timeoutInMillis;
+
+  private DecodeOptions decodeOptions;
+
+  /**
+   * The list of cipher suite
+   */
+  private List<String> enabledCipherSuites = new LinkedList<String>();
+
+  /**
+   * the list of protocols
+   */
+  private List<String> enabledProtocols = new LinkedList<String>();
+
+  private TCPNIOTransport transport;
+
+
+
+  /**
+   * Creates a new set of connection options with default settings. SSL will not
+   * be enabled, and a default set of decode options will be used.
+   */
+  public LDAPOptions()
+  {
+    this.sslContext = null;
+    this.timeoutInMillis = 0;
+    this.useStartTLS = false;
+    this.decodeOptions = new DecodeOptions();
+    this.transport = null;
+  }
+
+
+
+  /**
+   * Creates a new set of connection options having the same initial set of
+   * options as the provided set of connection options.
+   *
+   * @param options
+   *          The set of connection options to be copied.
+   */
+  public LDAPOptions(final LDAPOptions options)
+  {
+    this.sslContext = options.sslContext;
+    this.timeoutInMillis = options.timeoutInMillis;
+    this.useStartTLS = options.useStartTLS;
+    this.decodeOptions = new DecodeOptions(options.decodeOptions);
+    this.enabledCipherSuites.addAll(options.getEnabledCipherSuites());
+    this.enabledProtocols.addAll(options.getEnabledProtocols());
+    this.transport = options.transport;
+  }
+
+
+
+  /**
+   * Returns the decoding options which will be used to control how requests and
+   * responses are decoded.
+   *
+   * @return The decoding options which will be used to control how requests and
+   *         responses are decoded (never {@code null}).
+   */
+  public final DecodeOptions getDecodeOptions()
+  {
+    return decodeOptions;
+  }
+
+
+
+  /**
+   * Returns the SSL context which will be used when initiating connections with
+   * the Directory Server. By default no SSL context will be used, indicating
+   * that connections will not be secured. If a non-{@code null} SSL context is
+   * returned then connections will be secured using either SSL or StartTLS
+   * depending on {@link #useStartTLS()}.
+   *
+   * @return The SSL context which will be used when initiating secure
+   *         connections with the Directory Server, which may be {@code null}
+   *         indicating that connections will not be secured.
+   */
+  public final SSLContext getSSLContext()
+  {
+    return sslContext;
+  }
+
+
+
+  /**
+   * Returns the Grizzly TCP transport which will be used when initiating
+   * connections with the Directory Server. By default this method will return
+   * {@code null} indicating that the default transport factory should be used
+   * to obtain a TCP transport.
+   *
+   * @return The Grizzly TCP transport which will be used when initiating
+   *         connections with the Directory Server, or {@code null} if the
+   *         default transport factory should be used to obtain a TCP transport.
+   */
+  public final TCPNIOTransport getTCPNIOTransport()
+  {
+    return transport;
+  }
+
+
+
+  /**
+   * Returns the operation timeout in the specified unit.
+   *
+   * @param unit
+   *          The time unit of use.
+   * @return The operation timeout.
+   */
+  public final long getTimeout(final TimeUnit unit)
+  {
+    return unit.convert(timeoutInMillis, TimeUnit.MILLISECONDS);
+  }
+
+
+
+  /**
+   * Sets the decoding options which will be used to control how requests and
+   * responses are decoded.
+   *
+   * @param decodeOptions
+   *          The decoding options which will be used to control how requests
+   *          and responses are decoded (never {@code null}).
+   * @return A reference to this LDAP connection options.
+   * @throws NullPointerException
+   *           If {@code decodeOptions} was {@code null}.
+   */
+  public final LDAPOptions setDecodeOptions(final DecodeOptions decodeOptions)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(decodeOptions);
+    this.decodeOptions = decodeOptions;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the SSL context which will be used when initiating connections with
+   * the Directory Server. By default no SSL context will be used, indicating
+   * that connections will not be secured. If a non-{@code null} SSL context is
+   * returned then connections will be secured using either SSL or StartTLS
+   * depending on {@link #useStartTLS()}.
+   *
+   * @param sslContext
+   *          The SSL context which will be used when initiating secure
+   *          connections with the Directory Server, which may be {@code null}
+   *          indicating that connections will not be secured.
+   * @return A reference to this LDAP connection options.
+   */
+  public final LDAPOptions setSSLContext(final SSLContext sslContext)
+  {
+    this.sslContext = sslContext;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the Grizzly TCP transport which will be used when initiating
+   * connections with the Directory Server. By default this method will return
+   * {@code null} indicating that the default transport factory will be used to
+   * obtain a TCP transport.
+   *
+   * @param transport
+   *          The Grizzly TCP transport which will be used when initiating
+   *          connections with the Directory Server, or {@code null} if the
+   *          default transport factory should be used to obtain a TCP
+   *          transport.
+   * @return A reference to this LDAP connection options.
+   */
+  public final LDAPOptions setTCPNIOTransport(final TCPNIOTransport transport)
+  {
+    this.transport = transport;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the operation timeout. If the response is not received from the
+   * Directory Server in the timeout period, the operation will be abandoned and
+   * an error result returned. A timeout setting of 0 disables timeout limits.
+   *
+   * @param timeout
+   *          The operation timeout to use.
+   * @param unit
+   *          the time unit of the time argument.
+   * @return A reference to this LDAP connection options.
+   */
+  public final LDAPOptions setTimeout(final long timeout, final TimeUnit unit)
+  {
+    this.timeoutInMillis = unit.toMillis(timeout);
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not SSL or StartTLS should be used for securing
+   * connections when an SSL context is specified. By default SSL will be used
+   * in preference to StartTLS.
+   *
+   * @param useStartTLS
+   *          {@code true} if StartTLS should be used for securing connections
+   *          when an SSL context is specified, otherwise {@code false}
+   *          indicating that SSL should be used.
+   * @return A reference to this LDAP connection options.
+   */
+  public final LDAPOptions setUseStartTLS(final boolean useStartTLS)
+  {
+    this.useStartTLS = useStartTLS;
+    return this;
+  }
+
+
+
+  /**
+   * Indicates whether or not SSL or StartTLS should be used for securing
+   * connections when an SSL context is specified. By default SSL will be used
+   * in preference to StartTLS.
+   *
+   * @return {@code true} if StartTLS should be used for securing connections
+   *         when an SSL context is specified, otherwise {@code false}
+   *         indicating that SSL should be used.
+   */
+  public final boolean useStartTLS()
+  {
+    return useStartTLS;
+  }
+
+  /**
+   * Adds the protocol versions enabled for secure connections with the
+   * Directory Server.
+   *
+   * The protocols must be supported by the SSLContext specified in
+   * {@link #setSSLContext(SSLContext)}. Following a successful call to
+   * this method, only the protocols listed in the protocols parameter are
+   * enabled for use.
+   *
+   * @param protocols Names of all the protocols to enable.
+   * @return A reference to this LDAP connection options.
+   */
+  public final LDAPOptions addEnabledProtocol(String... protocols)
+  {
+    for (final String protocol : protocols)
+    {
+      this.enabledProtocols.add(Validator.ensureNotNull(protocol));
+    }
+    return this;
+  }
+
+  /**
+   * Adds the cipher suites enabled for secure connections with the
+   * Directory Server.
+   *
+   * The suites must be supported by the SSLContext specified in
+   * {@link #setSSLContext(SSLContext)}. Following a successful call to
+   * this method, only the suites listed in the protocols parameter are
+   * enabled for use.
+   *
+   * @param suites Names of all the suites to enable.
+   * @return A reference to this LDAP connection options.
+   */
+  public final LDAPOptions addEnabledCipherSuite(String... suites)
+  {
+    for (final String suite : suites)
+    {
+      this.enabledCipherSuites.add(Validator.ensureNotNull(suite));
+    }
+    return this;
+  }
+
+  /**
+   * Returns the names of the protocol versions which are currently enabled
+   * for secure connections with the Directory Server.
+   *
+   * @return an array of protocols or empty set if the default protocols
+   * are to be used.
+   */
+  public final List<String> getEnabledProtocols()
+  {
+    return this.enabledProtocols;
+  }
+
+  /**
+   * Returns the names of the protocol versions which are currently enabled
+   * for secure connections with the Directory Server.
+   *
+   * @return an array of protocols or empty set if the default protocols
+   * are to be used.
+   */
+  public final List<String> getEnabledCipherSuites()
+  {
+    return this.enabledCipherSuites;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPUrl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPUrl.java
new file mode 100644
index 0000000..37d5938
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LDAPUrl.java
@@ -0,0 +1,978 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.*;
+
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An LDAP URL as defined in RFC 4516. In addition, the secure ldap (ldaps://)
+ * is also supported. LDAP URLs have the following format:
+ *
+ * <PRE>
+ * "ldap[s]://" [ <I>hostName</I> [":" <I>portNumber</I>] ]
+ *          "/" <I>distinguishedName</I>
+ *          ["?" <I>attributeList</I>
+ *              ["?" <I>scope</I> "?" <I>filterString</I> ] ]
+ * </PRE>
+ *
+ * Where:
+ * <UL>
+ * <LI>all text within double-quotes are literal
+ * <LI><CODE><I>hostName</I></CODE> and <CODE><I>portNumber</I></CODE> identify
+ * the location of the LDAP server.
+ * <LI><CODE><I>distinguishedName</I></CODE> is the name of an entry within the
+ * given directory (the entry represents the starting point of the search).
+ * <LI><CODE><I>attributeList</I></CODE> contains a list of attributes to
+ * retrieve (if null, fetch all attributes). This is a comma-delimited list of
+ * attribute names.
+ * <LI><CODE><I>scope</I></CODE> is one of the following:
+ * <UL>
+ * <LI><CODE>base</CODE> indicates that this is a search only for the specified
+ * entry
+ * <LI><CODE>one</CODE> indicates that this is a search for matching entries one
+ * level under the specified entry (and not including the entry itself)
+ * <LI><CODE>sub</CODE> indicates that this is a search for matching entries at
+ * all levels under the specified entry (including the entry itself)
+ * <LI><CODE>subordinates</CODE> indicates that this is a search for matching
+ * entries all levels under the specified entry (excluding the entry itself)
+ * </UL>
+ * If not specified, <CODE><I>scope</I></CODE> is <CODE>base</CODE> by default.
+ * <LI><CODE><I>filterString</I></CODE> is a human-readable representation of
+ * the search criteria. If no filter is provided, then a default of "{@code
+ * (objectClass=*)}" should be assumed.
+ * </UL>
+ * The same encoding rules for other URLs (e.g. HTTP) apply for LDAP URLs.
+ * Specifically, any "illegal" characters are escaped with
+ * <CODE>%<I>HH</I></CODE>, where <CODE><I>HH</I></CODE> represent the two hex
+ * digits which correspond to the ASCII value of the character. This encoding is
+ * only legal (or necessary) on the DN and filter portions of the URL.
+ * <P>
+ * Note that this class does not implement extensions.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc4516">RFC 4516 - Lightweight
+ *      Directory Access Protocol (LDAP): Uniform Resource Locator</a>
+ */
+public final class LDAPUrl
+{
+  /**
+   * The scheme corresponding to an LDAP URL. RFC 4516 mandates only ldap scheme
+   * but we support "ldaps" too.
+   */
+  private final boolean isSecured;
+
+  /**
+   * The host name corresponding to an LDAP URL.
+   */
+  private final String host;
+
+  /**
+   * The port number corresponding to an LDAP URL.
+   */
+  private final int port;
+
+  /**
+   * The distinguished name corresponding to an LDAP URL.
+   */
+  private final DN name;
+
+  /**
+   * The search scope corresponding to an LDAP URL.
+   */
+  private final SearchScope scope;
+
+  /**
+   * The search filter corresponding to an LDAP URL.
+   */
+  private final Filter filter;
+
+  /**
+   * The attributes that need to be searched.
+   */
+  private final List<String> attributes;
+
+  /**
+   * The String value of LDAP URL.
+   */
+  private final String urlString;
+
+  /**
+   * Normalized ldap URL.
+   */
+  private String normalizedURL;
+
+  /**
+   * The default scheme to be used with LDAP URL.
+   */
+  private static final String DEFAULT_URL_SCHEME = "ldap";
+
+  /**
+   * The SSL-based scheme allowed to be used with LDAP URL.
+   */
+  private static final String SSL_URL_SCHEME = "ldaps";
+
+  /**
+   * The default host.
+   */
+  private static final String DEFAULT_HOST = "localhost";
+
+  /**
+   * The default non-SSL port.
+   */
+  private static final int DEFAULT_PORT = 389;
+
+  /**
+   * The default SSL port.
+   */
+  private static final int DEFAULT_SSL_PORT = 636;
+
+  /**
+   * The default filter.
+   */
+  private static final Filter DEFAULT_FILTER = Filter
+      .getObjectClassPresentFilter();
+
+  /**
+   * The default search scope.
+   */
+  private static final SearchScope DEFAULT_SCOPE = SearchScope.BASE_OBJECT;
+
+  /**
+   * The default distinguished name.
+   */
+  private static final DN DEFAULT_DN = DN.rootDN();
+
+  /**
+   * The % encoding character.
+   */
+  private static final char PERCENT_ENCODING_CHAR = '%';
+
+  /**
+   * The ? character.
+   */
+  private static final char QUESTION_CHAR = '?';
+
+  /**
+   * The slash (/) character.
+   */
+  private static final char SLASH_CHAR = '/';
+
+  /**
+   * The comma (,) character.
+   */
+  private static final char COMMA_CHAR = ',';
+
+  /**
+   * The colon (:) character.
+   */
+  private static final char COLON_CHAR = ':';
+
+  /**
+   * Set containing characters that do not need to be encoded.
+   */
+  private static final Set<Character> VALID_CHARS = new HashSet<Character>();
+
+  static
+  {
+    // Refer to RFC 3986 for more details.
+    final char[] delims = { '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';',
+        '=', '.', '-', '_', '~' };
+    for (final char c : delims)
+    {
+      VALID_CHARS.add(c);
+    }
+
+    for (char c = 'a'; c <= 'z'; c++)
+    {
+      VALID_CHARS.add(c);
+    }
+
+    for (char c = 'A'; c <= 'Z'; c++)
+    {
+      VALID_CHARS.add(c);
+    }
+
+    for (char c = '0'; c <= '9'; c++)
+    {
+      VALID_CHARS.add(c);
+    }
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of an LDAP URL using the
+   * default schema.
+   *
+   * @param url
+   *          The LDAP string representation of an LDAP URL.
+   * @return The parsed LDAP URL.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code url} is not a valid LDAP string representation of an
+   *           LDAP URL.
+   * @throws NullPointerException
+   *           If {@code url} was {@code null}.
+   */
+  public static LDAPUrl valueOf(final String url)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return valueOf(url, Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of an LDAP URL using the
+   * provided schema.
+   *
+   * @param url
+   *          The LDAP string representation of an LDAP URL.
+   * @param schema
+   *          The schema to use when parsing the LDAP URL.
+   * @return The parsed LDAP URL.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code url} is not a valid LDAP string representation of an
+   *           LDAP URL.
+   * @throws NullPointerException
+   *           If {@code url} or {@code schema} was {@code null}.
+   */
+  public static LDAPUrl valueOf(final String url, final Schema schema)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(url, schema);
+    return new LDAPUrl(url, schema);
+  }
+
+
+
+  private static int decodeHex(final String url, final int index,
+      final char hexChar) throws LocalizedIllegalArgumentException
+  {
+    if (hexChar >= '0' && hexChar <= '9')
+    {
+      return hexChar - '0';
+    }
+    else if (hexChar >= 'A' && hexChar <= 'F')
+    {
+      return hexChar - 'A' + 10;
+    }
+    else if (hexChar >= 'a' && hexChar <= 'f')
+    {
+      return hexChar - 'a' + 10;
+    }
+
+    final LocalizableMessage msg = ERR_LDAPURL_INVALID_HEX_BYTE.get(url, index);
+    throw new LocalizedIllegalArgumentException(msg);
+  }
+
+
+
+  private static void percentDecoder(final String urlString, final int index,
+      final String s, final StringBuilder decoded)
+      throws LocalizedIllegalArgumentException
+  {
+    Validator.ensureNotNull(s, decoded);
+    decoded.append(s);
+
+    int srcPos = 0, dstPos = 0;
+
+    while (srcPos < decoded.length())
+    {
+      if (decoded.charAt(srcPos) != '%')
+      {
+        if (srcPos != dstPos)
+        {
+          decoded.setCharAt(dstPos, decoded.charAt(srcPos));
+        }
+        srcPos++;
+        dstPos++;
+        continue;
+      }
+      decoded.setCharAt(dstPos, (char) ((decodeHex(urlString, index + srcPos
+          + 1, decoded.charAt(srcPos + 1)) << 4) | (decodeHex(urlString, index
+          + srcPos + 2, decoded.charAt(srcPos + 2)))));
+      dstPos++;
+      srcPos += 3;
+    }
+    decoded.setLength(dstPos);
+  }
+
+
+
+  /**
+   * This method performs the percent-encoding as defined in section 2.1 of RFC
+   * 3986.
+   *
+   * @param urlElement
+   *          The element of the URL that needs to be percent encoded.
+   * @param encodedBuffer
+   *          The buffer that contains the final percent encoded value.
+   */
+  private static void percentEncoder(final String urlElement,
+      final StringBuilder encodedBuffer)
+  {
+    Validator.ensureNotNull(urlElement);
+    for (int count = 0; count < urlElement.length(); count++)
+    {
+      final char c = urlElement.charAt(count);
+      if (VALID_CHARS.contains(c))
+      {
+        encodedBuffer.append(c);
+      }
+      else
+      {
+        encodedBuffer.append(PERCENT_ENCODING_CHAR);
+        encodedBuffer.append(Integer.toHexString(c));
+      }
+    }
+  }
+
+
+
+  /**
+   * Creates a new LDAP URL referring to a single entry on the specified server.
+   * The LDAP URL with have base object scope and the filter {@code
+   * (objectClass=*)}.
+   *
+   * @param isSecured
+   *          {@code true} if this LDAP URL should use LDAPS or {@code false} if
+   *          it should use LDAP.
+   * @param host
+   *          The name or IP address in dotted format of the LDAP server. For
+   *          example, {@code ldap.server1.com} or {@code 192.202.185.90}. Use
+   *          {@code null} for the local host.
+   * @param port
+   *          The port number of the LDAP server, or {@code null} to use the
+   *          default port (389 for LDAP and 636 for LDAPS).
+   * @param name
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed, or {@code null} to specify the root
+   *          DSE.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code port} was less than 1 or greater than 65535.
+   */
+  public LDAPUrl(final boolean isSecured, final String host,
+      final Integer port, final DN name)
+      throws LocalizedIllegalArgumentException
+  {
+    this(isSecured, host, port, name, DEFAULT_SCOPE, DEFAULT_FILTER);
+  }
+
+
+
+  /**
+   * Creates a new LDAP URL including the full set of parameters for a search
+   * request.
+   *
+   * @param isSecured
+   *          {@code true} if this LDAP URL should use LDAPS or {@code false} if
+   *          it should use LDAP.
+   * @param host
+   *          The name or IP address in dotted format of the LDAP server. For
+   *          example, {@code ldap.server1.com} or {@code 192.202.185.90}. Use
+   *          {@code null} for the local host.
+   * @param port
+   *          The port number of the LDAP server, or {@code null} to use the
+   *          default port (389 for LDAP and 636 for LDAPS).
+   * @param name
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed, or {@code null} to specify the root
+   *          DSE.
+   * @param scope
+   *          The search scope, or {@code null} to specify base scope.
+   * @param filter
+   *          The search filter, or {@code null} to specify the filter {@code
+   *          (objectClass=*)}.
+   * @param attributes
+   *          The list of attributes to be included in the search results.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code port} was less than 1 or greater than 65535.
+   */
+  public LDAPUrl(final boolean isSecured, final String host,
+      final Integer port, final DN name, final SearchScope scope,
+      final Filter filter, final String... attributes)
+      throws LocalizedIllegalArgumentException
+  {
+    // The buffer storing the encoded url.
+    final StringBuilder urlBuffer = new StringBuilder();
+
+    // build the scheme.
+    this.isSecured = isSecured;
+    if (this.isSecured)
+    {
+      urlBuffer.append(SSL_URL_SCHEME);
+    }
+    else
+    {
+      urlBuffer.append(DEFAULT_URL_SCHEME);
+    }
+    urlBuffer.append("://");
+
+    if (host == null)
+    {
+      this.host = DEFAULT_HOST;
+    }
+    else
+    {
+      this.host = host;
+      urlBuffer.append(this.host);
+    }
+
+    int listenPort = DEFAULT_PORT;
+    if (port == null)
+    {
+      listenPort = isSecured ? DEFAULT_SSL_PORT : DEFAULT_PORT;
+    }
+    else
+    {
+      listenPort = port.intValue();
+      if (listenPort < 1 || listenPort > 65535)
+      {
+        final LocalizableMessage msg = ERR_LDAPURL_BAD_PORT.get(listenPort);
+        throw new LocalizedIllegalArgumentException(msg);
+      }
+      urlBuffer.append(COLON_CHAR);
+      urlBuffer.append(listenPort);
+    }
+
+    this.port = listenPort;
+
+    // We need a slash irrespective of dn is defined or not.
+    urlBuffer.append(SLASH_CHAR);
+    if (name != null)
+    {
+      this.name = name;
+      percentEncoder(name.toString(), urlBuffer);
+    }
+    else
+    {
+      this.name = DEFAULT_DN;
+    }
+
+    // Add attributes.
+    urlBuffer.append(QUESTION_CHAR);
+    switch (attributes.length)
+    {
+    case 0:
+      this.attributes = Collections.emptyList();
+      break;
+    case 1:
+      this.attributes = Collections.singletonList(attributes[0]);
+      urlBuffer.append(attributes[0]);
+      break;
+    default:
+      this.attributes = Collections.unmodifiableList(Arrays.asList(attributes));
+      urlBuffer.append(attributes[0]);
+      for (int i = 1; i < attributes.length; i++)
+      {
+        urlBuffer.append(COMMA_CHAR);
+        urlBuffer.append(attributes[i]);
+      }
+      break;
+    }
+
+    // Add the scope.
+    urlBuffer.append(QUESTION_CHAR);
+    if (scope != null)
+    {
+      this.scope = scope;
+      urlBuffer.append(scope);
+    }
+    else
+    {
+      this.scope = DEFAULT_SCOPE;
+    }
+
+    // Add the search filter.
+    urlBuffer.append(QUESTION_CHAR);
+    if (filter != null)
+    {
+      this.filter = filter;
+      urlBuffer.append(this.filter);
+    }
+    else
+    {
+      this.filter = DEFAULT_FILTER;
+    }
+
+    urlString = urlBuffer.toString();
+  }
+
+
+
+  private LDAPUrl(final String urlString, final Schema schema)
+      throws LocalizedIllegalArgumentException
+  {
+    this.urlString = urlString;
+
+    // Parse the url and build the LDAP URL.
+    final int schemeIdx = urlString.indexOf("://");
+    if (schemeIdx < 0)
+    {
+      final LocalizableMessage msg = ERR_LDAPURL_NO_SCHEME.get(urlString);
+      throw new LocalizedIllegalArgumentException(msg);
+    }
+    final String scheme = StaticUtils.toLowerCase(urlString.substring(0,
+        schemeIdx));
+
+    if (scheme.equalsIgnoreCase(DEFAULT_URL_SCHEME))
+    {
+      // Default ldap scheme.
+      isSecured = false;
+    }
+    else if (scheme.equalsIgnoreCase(SSL_URL_SCHEME))
+    {
+      isSecured = true;
+    }
+    else
+    {
+      final LocalizableMessage msg = ERR_LDAPURL_BAD_SCHEME.get(urlString,
+          scheme);
+      throw new LocalizedIllegalArgumentException(msg);
+    }
+
+    final int urlLength = urlString.length();
+    final int hostPortIdx = urlString.indexOf(SLASH_CHAR, schemeIdx + 3);
+    final StringBuilder builder = new StringBuilder();
+    if (hostPortIdx < 0)
+    {
+      // We got anything here like the host and port?
+      if (urlLength > (schemeIdx + 3))
+      {
+        final String hostAndPort = urlString
+            .substring(schemeIdx + 3, urlLength);
+        port = parseHostPort(urlString, hostAndPort, builder);
+        host = builder.toString();
+        builder.setLength(0);
+      }
+      else
+      {
+        // Nothing else is specified apart from the scheme.
+        // Use the default settings and return from here.
+        host = DEFAULT_HOST;
+        port = isSecured ? DEFAULT_SSL_PORT : DEFAULT_PORT;
+      }
+      name = DEFAULT_DN;
+      scope = DEFAULT_SCOPE;
+      filter = DEFAULT_FILTER;
+      attributes = Collections.emptyList();
+      return;
+    }
+
+    final String hostAndPort = urlString.substring(schemeIdx + 3, hostPortIdx);
+    // assign the host and port.
+    port = parseHostPort(urlString, hostAndPort, builder);
+    host = builder.toString();
+    builder.setLength(0);
+
+    // Parse the dn.
+    DN parsedDN = null;
+    final int dnIdx = urlString.indexOf(QUESTION_CHAR, hostPortIdx + 1);
+
+    if (dnIdx < 0)
+    {
+      // Whatever we have here is the dn.
+      final String dnStr = urlString.substring(hostPortIdx + 1, urlLength);
+      percentDecoder(urlString, hostPortIdx + 1, dnStr, builder);
+      try
+      {
+        parsedDN = DN.valueOf(builder.toString(), schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        final LocalizableMessage msg = ERR_LDAPURL_INVALID_DN.get(urlString, e
+            .getMessageObject());
+        throw new LocalizedIllegalArgumentException(msg);
+      }
+      builder.setLength(0);
+      name = parsedDN;
+      scope = DEFAULT_SCOPE;
+      filter = DEFAULT_FILTER;
+      attributes = Collections.emptyList();
+      return;
+    }
+
+    final String dnStr = urlString.substring(hostPortIdx + 1, dnIdx);
+    if (dnStr.length() == 0)
+    {
+      parsedDN = DEFAULT_DN;
+    }
+    else
+    {
+      percentDecoder(urlString, hostPortIdx + 1, dnStr, builder);
+      try
+      {
+        parsedDN = DN.valueOf(builder.toString(), schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        final LocalizableMessage msg = ERR_LDAPURL_INVALID_DN.get(urlString, e
+            .getMessageObject());
+        throw new LocalizedIllegalArgumentException(msg);
+      }
+      builder.setLength(0);
+    }
+    name = parsedDN;
+
+    // Find out the attributes.
+    final int attrIdx = urlString.indexOf(QUESTION_CHAR, dnIdx + 1);
+    if (attrIdx < 0)
+    {
+      attributes = Collections.emptyList();
+      scope = DEFAULT_SCOPE;
+      filter = DEFAULT_FILTER;
+      return;
+    }
+    else
+    {
+      final String attrDesc = urlString.substring(dnIdx + 1, attrIdx);
+      final StringTokenizer token = new StringTokenizer(attrDesc, String
+          .valueOf(COMMA_CHAR));
+      final List<String> parsedAttrs = new ArrayList<String>(token
+          .countTokens());
+      while (token.hasMoreElements())
+      {
+        parsedAttrs.add(token.nextToken());
+      }
+      attributes = Collections.unmodifiableList(parsedAttrs);
+    }
+
+    // Find the scope.
+    final int scopeIdx = urlString.indexOf(QUESTION_CHAR, attrIdx + 1);
+    SearchScope parsedScope = SearchScope.BASE_OBJECT;
+    if (scopeIdx < 0)
+    {
+      scope = DEFAULT_SCOPE;
+      filter = DEFAULT_FILTER;
+      return;
+    }
+    else
+    {
+      String scopeDef = urlString.substring(attrIdx + 1, scopeIdx);
+      scopeDef = StaticUtils.toLowerCase(scopeDef);
+      for (final SearchScope sscope : SearchScope.values())
+      {
+        if (sscope.toString().equals(scopeDef))
+        {
+          parsedScope = sscope;
+          break;
+        }
+      }
+    }
+    scope = parsedScope;
+
+    // Last one is filter.
+    final String parsedFilter = urlString.substring(scopeIdx + 1, urlLength);
+    if (parsedFilter.length() > 0)
+    {
+      // Clear what we already have.
+      builder.setLength(0);
+      percentDecoder(urlString, scopeIdx + 1, parsedFilter, builder);
+      try
+      {
+        this.filter = Filter.valueOf(builder.toString());
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        final LocalizableMessage msg = ERR_LDAPURL_INVALID_FILTER.get(
+            urlString, e.getMessageObject());
+        throw new LocalizedIllegalArgumentException(msg);
+      }
+    }
+    else
+    {
+      this.filter = DEFAULT_FILTER;
+    }
+  }
+
+
+
+  /**
+   * Creates a new search request containing the parameters of this LDAP URL.
+   *
+   * @return A new search request containing the parameters of this LDAP URL.
+   */
+  public SearchRequest asSearchRequest()
+  {
+    final SearchRequest request = Requests
+        .newSearchRequest(name, scope, filter);
+    for (final String a : attributes)
+    {
+      request.addAttribute(a);
+    }
+    return request;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean equals(final Object o)
+  {
+    if (o == this)
+    {
+      return true;
+    }
+    else if (o instanceof LDAPUrl)
+    {
+      final String s1 = toNormalizedString();
+      final String s2 = ((LDAPUrl) o).toNormalizedString();
+      return s1.equals(s2);
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the attributes to be included with
+   * each entry that matches the search criteria. Attributes that are sub-types
+   * of listed attributes are implicitly included. If the returned list is empty
+   * then all user attributes will be included by default.
+   *
+   * @return An unmodifiable list containing the attributes to be included with
+   *         each entry that matches the search criteria.
+   */
+  public List<String> getAttributes()
+  {
+    return attributes;
+  }
+
+
+
+  /**
+   * Returns the search filter associated with this LDAP URL.
+   *
+   * @return The search filter associated with this LDAP URL.
+   */
+  public Filter getFilter()
+  {
+    return filter;
+  }
+
+
+
+  /**
+   * Returns the name or IP address in dotted format of the LDAP server
+   * referenced by this LDAP URL. For example, {@code ldap.server1.com} or
+   * {@code 192.202.185.90}. Use {@code null} for the local host.
+   *
+   * @return A name or IP address in dotted format of the LDAP server referenced
+   *         by this LDAP URL.
+   */
+  public String getHost()
+  {
+    return host;
+  }
+
+
+
+  /**
+   * Returns the distinguished name of the base entry relative to which the
+   * search is to be performed.
+   *
+   * @return The distinguished name of the base entry relative to which the
+   *         search is to be performed.
+   */
+  public DN getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * Returns the port number of the LDAP server referenced by this LDAP URL.
+   *
+   * @return The port number of the LDAP server referenced by this LDAP URL.
+   */
+  public int getPort()
+  {
+    return port;
+  }
+
+
+
+  /**
+   * Returns the search scope associated with this LDAP URL.
+   *
+   * @return The search scope associated with this LDAP URL.
+   */
+  public SearchScope getScope()
+  {
+    return scope;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    final String s = toNormalizedString();
+    return s.hashCode();
+  }
+
+
+
+  /**
+   * Returns {@code true} if this LDAP URL should use LDAPS or {@code false} if
+   * it should use LDAP.
+   *
+   * @return {@code true} if this LDAP URL should use LDAPS or {@code false} if
+   *         it should use LDAP.
+   */
+  public boolean isSecure()
+  {
+    return isSecured;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return urlString;
+  }
+
+
+
+  private int parseHostPort(final String urlString, final String hostAndPort,
+      final StringBuilder host) throws LocalizedIllegalArgumentException
+  {
+    Validator.ensureNotNull(hostAndPort, port, host);
+    int urlPort = isSecured ? DEFAULT_SSL_PORT : DEFAULT_PORT;
+    if (hostAndPort.length() == 0)
+    {
+      host.append(DEFAULT_HOST);
+      return urlPort;
+    }
+    final int colonIdx = hostAndPort.indexOf(':');
+    if (colonIdx < 0)
+    {
+      // port is not specified.
+      host.append(hostAndPort);
+      return urlPort;
+    }
+    else
+    {
+      String s = hostAndPort.substring(0, colonIdx);
+      if (s.length() == 0)
+      {
+        // Use the default host as we allow only the port to be specified.
+        host.append(DEFAULT_HOST);
+      }
+      else
+      {
+        host.append(s);
+      }
+      s = hostAndPort.substring(colonIdx + 1, hostAndPort.length());
+      try
+      {
+        urlPort = Integer.parseInt(s);
+      }
+      catch (final NumberFormatException e)
+      {
+        final LocalizableMessage msg = ERR_LDAPURL_CANNOT_DECODE_PORT.get(
+            urlString, s);
+        throw new LocalizedIllegalArgumentException(msg);
+      }
+
+      // Check the validity of the port.
+      if (urlPort < 1 || urlPort > 65535)
+      {
+        final LocalizableMessage msg = ERR_LDAPURL_INVALID_PORT.get(urlString,
+            urlPort);
+        throw new LocalizedIllegalArgumentException(msg);
+      }
+    }
+    return urlPort;
+  }
+
+
+
+  private String toNormalizedString()
+  {
+    if (normalizedURL == null)
+    {
+      final StringBuilder builder = new StringBuilder();
+      if (this.isSecured)
+      {
+        builder.append(SSL_URL_SCHEME);
+      }
+      else
+      {
+        builder.append(DEFAULT_URL_SCHEME);
+      }
+      builder.append("://");
+      builder.append(host);
+      builder.append(COLON_CHAR);
+      builder.append(port);
+      builder.append(SLASH_CHAR);
+      percentEncoder(name.toString(), builder);
+      builder.append(QUESTION_CHAR);
+      final int sz = attributes.size();
+      for (int i = 0; i < sz; i++)
+      {
+        if (i > 0)
+        {
+          builder.append(COMMA_CHAR);
+        }
+        builder.append(attributes.get(i));
+      }
+      builder.append(QUESTION_CHAR);
+      builder.append(scope);
+      builder.append(QUESTION_CHAR);
+      percentEncoder(filter.toString(), builder);
+      normalizedURL = builder.toString();
+    }
+    return normalizedURL;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedAttribute.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedAttribute.java
new file mode 100644
index 0000000..5fb320a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedAttribute.java
@@ -0,0 +1,1045 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An implementation of the {@code Attribute} interface with predictable
+ * iteration order.
+ * <p>
+ * Internally, attribute values are stored in a linked list and it's this list
+ * which defines the iteration ordering, which is the order in which elements
+ * were inserted into the set (insertion-order). This ordering is particularly
+ * useful in LDAP where clients generally appreciate having things returned in
+ * the same order they were presented.
+ * <p>
+ * All operations are supported by this implementation.
+ */
+public final class LinkedAttribute extends AbstractAttribute
+{
+
+  private static abstract class Impl
+  {
+
+    abstract boolean add(LinkedAttribute attribute, ByteString value);
+
+
+
+    abstract void clear(LinkedAttribute attribute);
+
+
+
+    abstract boolean contains(LinkedAttribute attribute, ByteString value);
+
+
+
+    boolean containsAll(final LinkedAttribute attribute,
+        final Collection<?> values)
+    {
+      // TODO: could optimize if objects is a LinkedAttribute having the same
+      // equality matching rule.
+      for (final Object value : values)
+      {
+        if (!contains(attribute, ByteString.valueOf(value)))
+        {
+          return false;
+        }
+      }
+      return true;
+    }
+
+
+
+    abstract ByteString firstValue(LinkedAttribute attribute)
+        throws NoSuchElementException;
+
+
+
+    abstract Iterator<ByteString> iterator(LinkedAttribute attribute);
+
+
+
+    abstract boolean remove(LinkedAttribute attribute, ByteString value);
+
+
+
+    abstract <T> boolean retainAll(LinkedAttribute attribute,
+        Collection<T> values, Collection<? super T> missingValues);
+
+
+
+    abstract int size(LinkedAttribute attribute);
+  }
+
+
+
+  private static final class MultiValueImpl extends Impl
+  {
+
+    @Override
+    boolean add(final LinkedAttribute attribute, final ByteString value)
+    {
+      final ByteString normalizedValue = normalizeValue(attribute, value);
+      if (attribute.multipleValues.put(normalizedValue, value) == null)
+      {
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+
+
+    @Override
+    void clear(final LinkedAttribute attribute)
+    {
+      attribute.multipleValues = null;
+      attribute.pimpl = ZERO_VALUE_IMPL;
+    }
+
+
+
+    @Override
+    boolean contains(final LinkedAttribute attribute, final ByteString value)
+    {
+      return attribute.multipleValues.containsKey(normalizeValue(attribute,
+          value));
+    }
+
+
+
+    @Override
+    ByteString firstValue(final LinkedAttribute attribute)
+        throws NoSuchElementException
+    {
+      return attribute.multipleValues.values().iterator().next();
+    }
+
+
+
+    @Override
+    Iterator<ByteString> iterator(final LinkedAttribute attribute)
+    {
+      return new Iterator<ByteString>()
+      {
+        private Impl expectedImpl = MULTI_VALUE_IMPL;
+
+        private Iterator<ByteString> iterator = attribute.multipleValues
+            .values().iterator();
+
+
+
+        @Override
+        public boolean hasNext()
+        {
+          return iterator.hasNext();
+        }
+
+
+
+        @Override
+        public ByteString next()
+        {
+          if (attribute.pimpl != expectedImpl)
+          {
+            throw new ConcurrentModificationException();
+          }
+          else
+          {
+            return iterator.next();
+          }
+        }
+
+
+
+        @Override
+        public void remove()
+        {
+          if (attribute.pimpl != expectedImpl)
+          {
+            throw new ConcurrentModificationException();
+          }
+          else
+          {
+            iterator.remove();
+
+            // Resize if we have removed the second to last value.
+            if (attribute.multipleValues != null
+                && attribute.multipleValues.size() == 1)
+            {
+              resize(attribute);
+              iterator = attribute.pimpl.iterator(attribute);
+            }
+
+            // Always update since we may change to single or zero value
+            // impl.
+            expectedImpl = attribute.pimpl;
+          }
+        }
+
+      };
+    }
+
+
+
+    @Override
+    boolean remove(final LinkedAttribute attribute, final ByteString value)
+    {
+      final ByteString normalizedValue = normalizeValue(attribute, value);
+      if (attribute.multipleValues.remove(normalizedValue) != null)
+      {
+        resize(attribute);
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+
+
+    @Override
+    <T> boolean retainAll(final LinkedAttribute attribute,
+        final Collection<T> values, final Collection<? super T> missingValues)
+    {
+      // TODO: could optimize if objects is a LinkedAttribute having the same
+      // equality matching rule.
+      if (values.isEmpty())
+      {
+        clear(attribute);
+        return true;
+      }
+
+      final Map<ByteString, T> valuesToRetain = new HashMap<ByteString, T>(
+          values.size());
+      for (final T value : values)
+      {
+        valuesToRetain.put(
+            normalizeValue(attribute, ByteString.valueOf(value)), value);
+      }
+
+      boolean modified = false;
+      final Iterator<ByteString> iterator = attribute.multipleValues.keySet()
+          .iterator();
+      while (iterator.hasNext())
+      {
+        final ByteString normalizedValue = iterator.next();
+        if (valuesToRetain.remove(normalizedValue) == null)
+        {
+          modified = true;
+          iterator.remove();
+        }
+      }
+
+      if (missingValues != null)
+      {
+        missingValues.addAll(valuesToRetain.values());
+      }
+
+      resize(attribute);
+
+      return modified;
+    }
+
+
+
+    @Override
+    int size(final LinkedAttribute attribute)
+    {
+      return attribute.multipleValues.size();
+    }
+
+
+
+    private void resize(final LinkedAttribute attribute)
+    {
+      // May need to resize if initial size estimate was wrong (e.g. all
+      // values in added collection were the same).
+      switch (attribute.multipleValues.size())
+      {
+      case 0:
+        attribute.multipleValues = null;
+        attribute.pimpl = ZERO_VALUE_IMPL;
+        break;
+      case 1:
+        final Map.Entry<ByteString, ByteString> e = attribute.multipleValues
+            .entrySet().iterator().next();
+        attribute.singleValue = e.getValue();
+        attribute.normalizedSingleValue = e.getKey();
+        attribute.multipleValues = null;
+        attribute.pimpl = SINGLE_VALUE_IMPL;
+        break;
+      default:
+        // Nothing to do.
+        break;
+      }
+    }
+  }
+
+
+
+  private static final class SingleValueImpl extends Impl
+  {
+
+    @Override
+    boolean add(final LinkedAttribute attribute, final ByteString value)
+    {
+      final ByteString normalizedValue = normalizeValue(attribute, value);
+      if (attribute.normalizedSingleValue().equals(normalizedValue))
+      {
+        return false;
+      }
+
+      attribute.multipleValues = new LinkedHashMap<ByteString, ByteString>(2);
+      attribute.multipleValues.put(attribute.normalizedSingleValue,
+          attribute.singleValue);
+      attribute.multipleValues.put(normalizedValue, value);
+      attribute.singleValue = null;
+      attribute.normalizedSingleValue = null;
+      attribute.pimpl = MULTI_VALUE_IMPL;
+
+      return true;
+    }
+
+
+
+    @Override
+    void clear(final LinkedAttribute attribute)
+    {
+      attribute.singleValue = null;
+      attribute.normalizedSingleValue = null;
+      attribute.pimpl = ZERO_VALUE_IMPL;
+    }
+
+
+
+    @Override
+    boolean contains(final LinkedAttribute attribute, final ByteString value)
+    {
+      final ByteString normalizedValue = normalizeValue(attribute, value);
+      return attribute.normalizedSingleValue().equals(normalizedValue);
+    }
+
+
+
+    @Override
+    ByteString firstValue(final LinkedAttribute attribute)
+        throws NoSuchElementException
+    {
+      if (attribute.singleValue != null)
+      {
+        return attribute.singleValue;
+      }
+      else
+      {
+        throw new NoSuchElementException();
+      }
+    }
+
+
+
+    @Override
+    Iterator<ByteString> iterator(final LinkedAttribute attribute)
+    {
+      return new Iterator<ByteString>()
+      {
+        private Impl expectedImpl = SINGLE_VALUE_IMPL;
+
+        private boolean hasNext = true;
+
+
+
+        @Override
+        public boolean hasNext()
+        {
+          return hasNext;
+        }
+
+
+
+        @Override
+        public ByteString next()
+        {
+          if (attribute.pimpl != expectedImpl)
+          {
+            throw new ConcurrentModificationException();
+          }
+          else if (hasNext)
+          {
+            hasNext = false;
+            return attribute.singleValue;
+          }
+          else
+          {
+            throw new NoSuchElementException();
+          }
+        }
+
+
+
+        @Override
+        public void remove()
+        {
+          if (attribute.pimpl != expectedImpl)
+          {
+            throw new ConcurrentModificationException();
+          }
+          else if (hasNext || attribute.singleValue == null)
+          {
+            throw new IllegalStateException();
+          }
+          else
+          {
+            clear(attribute);
+            expectedImpl = attribute.pimpl;
+          }
+        }
+
+      };
+    }
+
+
+
+    @Override
+    boolean remove(final LinkedAttribute attribute, final ByteString value)
+    {
+      if (contains(attribute, value))
+      {
+        clear(attribute);
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+
+
+    @Override
+    <T> boolean retainAll(final LinkedAttribute attribute,
+        final Collection<T> values, final Collection<? super T> missingValues)
+    {
+      // TODO: could optimize if objects is a LinkedAttribute having the same
+      // equality matching rule.
+      if (values.isEmpty())
+      {
+        clear(attribute);
+        return true;
+      }
+
+      final ByteString normalizedSingleValue = attribute
+          .normalizedSingleValue();
+      boolean retained = false;
+      for (final T value : values)
+      {
+        final ByteString normalizedValue = normalizeValue(attribute,
+            ByteString.valueOf(value));
+        if (normalizedSingleValue.equals(normalizedValue))
+        {
+          if (missingValues == null)
+          {
+            // We can stop now.
+            return false;
+          }
+          retained = true;
+        }
+        else if (missingValues != null)
+        {
+          missingValues.add(value);
+        }
+      }
+
+      if (!retained)
+      {
+        clear(attribute);
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+
+
+    @Override
+    int size(final LinkedAttribute attribute)
+    {
+      return 1;
+    }
+  }
+
+
+
+  private static final class ZeroValueImpl extends Impl
+  {
+
+    @Override
+    boolean add(final LinkedAttribute attribute, final ByteString value)
+    {
+      attribute.singleValue = value;
+      attribute.pimpl = SINGLE_VALUE_IMPL;
+      return true;
+    }
+
+
+
+    @Override
+    void clear(final LinkedAttribute attribute)
+    {
+      // Nothing to do.
+    }
+
+
+
+    @Override
+    boolean contains(final LinkedAttribute attribute, final ByteString value)
+    {
+      return false;
+    }
+
+
+
+    @Override
+    boolean containsAll(final LinkedAttribute attribute,
+        final Collection<?> values)
+    {
+      return values.isEmpty();
+    }
+
+
+
+    @Override
+    ByteString firstValue(final LinkedAttribute attribute)
+        throws NoSuchElementException
+    {
+      throw new NoSuchElementException();
+    }
+
+
+
+    @Override
+    Iterator<ByteString> iterator(final LinkedAttribute attribute)
+    {
+      return new Iterator<ByteString>()
+      {
+        @Override
+        public boolean hasNext()
+        {
+          return false;
+        }
+
+
+
+        @Override
+        public ByteString next()
+        {
+          if (attribute.pimpl != ZERO_VALUE_IMPL)
+          {
+            throw new ConcurrentModificationException();
+          }
+          else
+          {
+            throw new NoSuchElementException();
+          }
+        }
+
+
+
+        @Override
+        public void remove()
+        {
+          if (attribute.pimpl != ZERO_VALUE_IMPL)
+          {
+            throw new ConcurrentModificationException();
+          }
+          else
+          {
+            throw new IllegalStateException();
+          }
+        }
+
+      };
+    }
+
+
+
+    @Override
+    boolean remove(final LinkedAttribute attribute, final ByteString value)
+    {
+      return false;
+    }
+
+
+
+    @Override
+    <T> boolean retainAll(final LinkedAttribute attribute,
+        final Collection<T> values, final Collection<? super T> missingValues)
+    {
+      if (missingValues != null)
+      {
+        missingValues.addAll(values);
+      }
+      return false;
+    }
+
+
+
+    @Override
+    int size(final LinkedAttribute attribute)
+    {
+      return 0;
+    }
+
+  }
+
+
+
+  /**
+   * An attribute factory which can be used to create new linked attributes.
+   */
+  public static final AttributeFactory FACTORY = new AttributeFactory()
+  {
+    @Override
+    public Attribute newAttribute(
+        final AttributeDescription attributeDescription)
+        throws NullPointerException
+    {
+      return new LinkedAttribute(attributeDescription);
+    }
+  };
+
+  private static final MultiValueImpl MULTI_VALUE_IMPL = new MultiValueImpl();
+
+  private static final SingleValueImpl SINGLE_VALUE_IMPL = new SingleValueImpl();
+
+  private static final ZeroValueImpl ZERO_VALUE_IMPL = new ZeroValueImpl();
+
+  private final AttributeDescription attributeDescription;
+
+  private Map<ByteString, ByteString> multipleValues = null;
+
+  private ByteString normalizedSingleValue = null;
+
+  private Impl pimpl = ZERO_VALUE_IMPL;
+
+  private ByteString singleValue = null;
+
+
+
+  /**
+   * Creates a new attribute having the same attribute description and attribute
+   * values as {@code attribute}.
+   *
+   * @param attribute
+   *          The attribute to be copied.
+   * @throws NullPointerException
+   *           If {@code attribute} was {@code null}.
+   */
+  public LinkedAttribute(final Attribute attribute) throws NullPointerException
+  {
+    this.attributeDescription = attribute.getAttributeDescription();
+
+    if (attribute instanceof LinkedAttribute)
+    {
+      final LinkedAttribute other = (LinkedAttribute) attribute;
+      this.pimpl = other.pimpl;
+      this.singleValue = other.singleValue;
+      this.normalizedSingleValue = other.normalizedSingleValue;
+      if (other.multipleValues != null)
+      {
+        this.multipleValues = new LinkedHashMap<ByteString, ByteString>(
+            other.multipleValues);
+      }
+    }
+    else
+    {
+      addAll(attribute);
+    }
+  }
+
+
+
+  /**
+   * Creates a new attribute having the specified attribute description and no
+   * attribute values.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  public LinkedAttribute(final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription);
+    this.attributeDescription = attributeDescription;
+  }
+
+
+
+  /**
+   * Creates a new attribute having the specified attribute description and
+   * single attribute value.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param value
+   *          The single attribute value.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code value} was {@code null}
+   *           .
+   */
+  public LinkedAttribute(final AttributeDescription attributeDescription,
+      final ByteString value) throws NullPointerException
+  {
+    this(attributeDescription);
+    add(value);
+  }
+
+
+
+  /**
+   * Creates a new attribute having the specified attribute description and
+   * attribute values.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param values
+   *          The attribute values.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code values} was
+   *           {@code null}.
+   */
+  public LinkedAttribute(final AttributeDescription attributeDescription,
+      final ByteString... values) throws NullPointerException
+  {
+    this(attributeDescription);
+    addAll(Arrays.asList(values));
+  }
+
+
+
+  /**
+   * Creates a new attribute having the specified attribute description and
+   * attribute values.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param values
+   *          The attribute values.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code values} was
+   *           {@code null}.
+   */
+  public LinkedAttribute(final AttributeDescription attributeDescription,
+      final Collection<ByteString> values) throws NullPointerException
+  {
+    this(attributeDescription);
+    addAll(values);
+  }
+
+
+
+  /**
+   * Creates a new attribute having the specified attribute description and no
+   * attribute values. The attribute description will be decoded using the
+   * default schema.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           default schema.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  public LinkedAttribute(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    this(AttributeDescription.valueOf(attributeDescription));
+  }
+
+
+
+  /**
+   * Creates a new attribute having the specified attribute description and
+   * single attribute value. The attribute description will be decoded using the
+   * default schema.
+   * <p>
+   * If {@code value} is not an instance of {@code ByteString} then it will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param value
+   *          The single attribute value.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           default schema.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code value} was {@code null}
+   *           .
+   */
+  public LinkedAttribute(final String attributeDescription, final Object value)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    this(attributeDescription);
+    add(ByteString.valueOf(value));
+  }
+
+
+
+  /**
+   * Creates a new attribute having the specified attribute description and
+   * attribute values. The attribute description will be decoded using the
+   * default schema.
+   * <p>
+   * Any attribute values which are not instances of {@code ByteString} will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeDescription
+   *          The attribute description.
+   * @param values
+   *          The attribute values.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           default schema.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} or {@code values} was
+   *           {@code null}.
+   */
+  public LinkedAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    this(attributeDescription);
+    for (final Object value : values)
+    {
+      add(ByteString.valueOf(value));
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean add(final ByteString value) throws NullPointerException
+  {
+    Validator.ensureNotNull(value);
+    return pimpl.add(this, value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean addAll(final Collection<? extends ByteString> values,
+      final Collection<? super ByteString> duplicateValues)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(values);
+
+    // TODO: could optimize if objects is a LinkedAttribute having the same
+    // equality matching rule.
+    boolean modified = false;
+    for (final ByteString value : values)
+    {
+      if (add(value))
+      {
+        modified = true;
+      }
+      else if (duplicateValues != null)
+      {
+        duplicateValues.add(value);
+      }
+    }
+    return modified;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void clear()
+  {
+    pimpl.clear(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean contains(final Object value) throws NullPointerException
+  {
+    Validator.ensureNotNull(value);
+    return pimpl.contains(this, ByteString.valueOf(value));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean containsAll(final Collection<?> values)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(values);
+    return pimpl.containsAll(this, values);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString firstValue() throws NoSuchElementException
+  {
+    return pimpl.firstValue(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AttributeDescription getAttributeDescription()
+  {
+    return attributeDescription;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Iterator<ByteString> iterator()
+  {
+    return pimpl.iterator(this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean remove(final Object value) throws NullPointerException
+  {
+    Validator.ensureNotNull(value);
+    return pimpl.remove(this, ByteString.valueOf(value));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public <T> boolean removeAll(final Collection<T> values,
+      final Collection<? super T> missingValues) throws NullPointerException
+  {
+    Validator.ensureNotNull(values);
+
+    // TODO: could optimize if objects is a LinkedAttribute having the same
+    // equality matching rule.
+    boolean modified = false;
+    for (final T value : values)
+    {
+      if (remove(ByteString.valueOf(value)))
+      {
+        modified = true;
+      }
+      else if (missingValues != null)
+      {
+        missingValues.add(value);
+      }
+    }
+    return modified;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public <T> boolean retainAll(final Collection<T> values,
+      final Collection<? super T> missingValues) throws NullPointerException
+  {
+    Validator.ensureNotNull(values);
+    return pimpl.retainAll(this, values, missingValues);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int size()
+  {
+    return pimpl.size(this);
+  }
+
+
+
+  // Lazily computes the normalized single value.
+  private ByteString normalizedSingleValue()
+  {
+    if (normalizedSingleValue == null)
+    {
+      normalizedSingleValue = normalizeValue(this, singleValue);
+    }
+    return normalizedSingleValue;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedHashMapEntry.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedHashMapEntry.java
new file mode 100644
index 0000000..3dd847e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LinkedHashMapEntry.java
@@ -0,0 +1,188 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.LinkedHashMap;
+
+import org.opends.sdk.requests.Requests;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An implementation of the {@code Entry} interface which uses a
+ * {@code LinkedHashMap} for storing attributes. Attributes are returned in the
+ * same order that they were added to the entry. All operations are supported by
+ * this implementation.
+ * <p>
+ * A {@code LinkedHashMapEntry} stores references to attributes which have been
+ * added using the {@link #addAttribute} methods. Attributes sharing the same
+ * attribute description are merged by adding the values of the new attribute to
+ * the existing attribute. More specifically, the existing attribute must be
+ * modifiable for the merge to succeed. Similarly, the {@link #removeAttribute}
+ * methods remove the specified values from the existing attribute. The
+ * {@link #replaceAttribute} methods remove the existing attribute (if present)
+ * and store a reference to the new attribute - neither the new or existing
+ * attribute need to be modifiable in this case.
+ */
+public final class LinkedHashMapEntry extends AbstractMapEntry
+{
+  /**
+   * An entry factory which can be used to create new linked hash map entries.
+   */
+  public static final EntryFactory FACTORY = new EntryFactory()
+  {
+    public Entry newEntry(final DN name) throws NullPointerException
+    {
+      return new LinkedHashMapEntry(name);
+    }
+  };
+
+
+
+  /**
+   * Creates an entry having the same distinguished name, attributes, and object
+   * classes of the provided entry. This constructor performs a deep copy of
+   * {@code entry} and will copy each attribute as a {@link LinkedAttribute}.
+   * <p>
+   * A shallow copy constructor is provided by
+   * {@link #LinkedHashMapEntry(Entry)}.
+   *
+   * @param entry
+   *          The entry to be copied.
+   * @return A deep copy of {@code entry}.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   * @see #LinkedHashMapEntry(Entry)
+   */
+  public static LinkedHashMapEntry deepCopyOfEntry(final Entry entry)
+      throws NullPointerException
+  {
+    LinkedHashMapEntry copy = new LinkedHashMapEntry(entry.getName());
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      copy.addAttribute(new LinkedAttribute(attribute));
+    }
+    return copy;
+  }
+
+
+
+  /**
+   * Creates an entry with an empty (root) distinguished name and no attributes.
+   */
+  public LinkedHashMapEntry()
+  {
+    this(DN.rootDN());
+  }
+
+
+
+  /**
+   * Creates an empty entry using the provided distinguished name and no
+   * attributes.
+   *
+   * @param name
+   *          The distinguished name of this entry.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public LinkedHashMapEntry(final DN name) throws NullPointerException
+  {
+    super(Validator.ensureNotNull(name),
+        new LinkedHashMap<AttributeDescription, Attribute>());
+  }
+
+
+
+  /**
+   * Creates an entry having the same distinguished name, attributes, and object
+   * classes of the provided entry. This constructor performs a shallow copy of
+   * {@code entry} and will not copy the attributes contained in {@code entry}.
+   * <p>
+   * A deep copy constructor is provided by {@link #deepCopyOfEntry(Entry)}
+   *
+   * @param entry
+   *          The entry to be copied.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   * @see #deepCopyOfEntry(Entry)
+   */
+  public LinkedHashMapEntry(final Entry entry) throws NullPointerException
+  {
+    this(entry.getName());
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      addAttribute(attribute);
+    }
+  }
+
+
+
+  /**
+   * Creates an empty entry using the provided distinguished name decoded using
+   * the default schema.
+   *
+   * @param name
+   *          The distinguished name of this entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public LinkedHashMapEntry(final String name)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    this(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * Creates a new entry using the provided lines of LDIF decoded using the
+   * default schema.
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing the an LDIF add change record or an LDIF
+   *          entry record.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  public LinkedHashMapEntry(final String... ldifLines)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    this(Requests.newAddRequest(ldifLines));
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancer.java
new file mode 100644
index 0000000..4dd63d9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancer.java
@@ -0,0 +1,100 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import com.sun.opends.sdk.util.CompletedFutureResult;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A load balancing connection factory allocates connections using the provided
+ * algorithm.
+ */
+final class LoadBalancer extends AbstractConnectionFactory
+{
+  private final LoadBalancingAlgorithm algorithm;
+
+
+
+  /**
+   * Creates a new load balancer using the provided algorithm.
+   *
+   * @param algorithm
+   *          The load balancing algorithm which will be used to obtain the next
+   *          connection factory.
+   */
+  public LoadBalancer(final LoadBalancingAlgorithm algorithm)
+  {
+    Validator.ensureNotNull(algorithm);
+    this.algorithm = algorithm;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<AsynchronousConnection> getAsynchronousConnection(
+      final ResultHandler<? super AsynchronousConnection> resultHandler)
+  {
+    final ConnectionFactory factory;
+
+    try
+    {
+      factory = algorithm.getConnectionFactory();
+    }
+    catch (final ErrorResultException e)
+    {
+      if (resultHandler != null)
+      {
+        resultHandler.handleErrorResult(e);
+      }
+      return new CompletedFutureResult<AsynchronousConnection>(e);
+    }
+
+    return factory.getAsynchronousConnection(resultHandler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("LoadBalancer(");
+    builder.append(String.valueOf(algorithm));
+    builder.append(')');
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancingAlgorithm.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancingAlgorithm.java
new file mode 100644
index 0000000..fc81c3d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LoadBalancingAlgorithm.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * A load balancing algorithm distributes connection requests across one or more
+ * underlying connection factories in an implementation defined manner.
+ *
+ * @see Connections#newLoadBalancer(LoadBalancingAlgorithm) newLoadBalancer
+ */
+public interface LoadBalancingAlgorithm
+{
+  /**
+   * Returns a connection factory which should be used in order to satisfy the
+   * next connection request.
+   *
+   * @return The connection factory.
+   * @throws ErrorResultException
+   *           If no connection factories are available for use.
+   */
+  ConnectionFactory getConnectionFactory() throws ErrorResultException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableException.java
new file mode 100644
index 0000000..85396b2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableException.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+/**
+ * This interface should be implemented by any exception interfaces that expose
+ * a localizable error message.
+ */
+public interface LocalizableException
+{
+  /**
+   * Returns the message that explains the problem that occurred.
+   *
+   * @return The message that explains the problem that occurred.
+   */
+  LocalizableMessage getMessageObject();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessage.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessage.java
new file mode 100755
index 0000000..d38f7ec
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessage.java
@@ -0,0 +1,527 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Formattable;
+import java.util.Formatter;
+import java.util.IllegalFormatException;
+import java.util.Locale;
+
+import com.sun.opends.sdk.util.LocalizableMessageDescriptor;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A localizable message whose {@code String} representation can be retrieved in
+ * one or more locales. A message is localized each time it is converted to a
+ * {@code String} using one of its {@link #toString} methods.
+ * <p>
+ * Localizable messages are particularly useful in situations where a message a
+ * destined for multiple recipients, potentially in different locales. For
+ * example, a server application may record a message in its log file using its
+ * default locale, but also send the same message to the client using the
+ * client's locale (if known).
+ * <p>
+ * In most cases messages are intended for use in a locale-sensitive manner
+ * although this class defines convenience methods for creating
+ * uninternationalized messages whose {@code String} representation is always
+ * the same regardless of the requested locale.
+ * <p>
+ * This class implements {@code CharSequence} so that messages can be supplied
+ * as arguments to other messages. This way messages can be composed of
+ * fragments of other messages if necessary.
+ *
+ * @see LocalizableMessageBuilder
+ */
+public final class LocalizableMessage implements CharSequence, Formattable,
+    Comparable<LocalizableMessage>
+{
+  static
+  {
+    LocalizableMessageDescriptor.messageFactory = new LocalizableMessageDescriptor.MessageFactory()
+    {
+
+      public LocalizableMessage newMessage(
+          final LocalizableMessageDescriptor descriptor, final Object... args)
+      {
+        return new LocalizableMessage(descriptor, args);
+      }
+    };
+  }
+
+  /**
+   * Represents an empty message string.
+   */
+  public static final LocalizableMessage EMPTY = LocalizableMessage.raw("");
+
+  // Variable used to workaround a bug in AIX Java 1.6
+  // TODO: remove this code once the JDK issue referenced in 3077 is
+  // closed.
+  private static final boolean IS_AIX_POST5 = isAIXPost5();
+
+
+
+  /**
+   * Creates an uninternationalized message whose {@code String} representation
+   * is always the same regardless of the requested locale.
+   * <p>
+   * Note that the types for {@code args} must be consistent with any argument
+   * specifiers appearing in {@code formatString} according to the rules of
+   * {@link java.util.Formatter}. A mismatch in type information will cause this
+   * message to render without argument substitution. Before using this method
+   * you should be sure that the message you are creating is not locale
+   * sensitive. If it is locale sensitive consider defining an appropriate
+   * {@link LocalizableMessageDescriptor}.
+   *
+   * @param formatString
+   *          The raw message format string.
+   * @param args
+   *          The raw message parameters.
+   * @return An uninternationalized messages whose {@code String} representation
+   *         is always the same regardless of the requested locale.
+   * @throws NullPointerException
+   *           If {@code formatString} was {@code null}.
+   */
+  public static LocalizableMessage raw(final CharSequence formatString,
+      final Object... args) throws NullPointerException
+  {
+    Validator.ensureNotNull(formatString);
+    return new LocalizableMessageDescriptor.Raw(formatString).get(args);
+  }
+
+
+
+  /**
+   * Creates a new message whose content is the {@code String} representation of
+   * the provided {@code Object}.
+   *
+   * @param object
+   *          The object to be converted to a message, may be {@code null}.
+   * @return The new message.
+   */
+  public static LocalizableMessage valueOf(final Object object)
+  {
+    if (object instanceof LocalizableMessage)
+    {
+      return (LocalizableMessage) object;
+    }
+    else if (object instanceof LocalizableMessageBuilder)
+    {
+      return ((LocalizableMessageBuilder) object).toMessage();
+    }
+    else
+    {
+      return new LocalizableMessageDescriptor.Raw(String.valueOf(object)).get();
+    }
+  }
+
+
+
+  /**
+   * Returns whether we are running post 1.5 on AIX or not.
+   *
+   * @return {@code true} if we are running post 1.5 on AIX and {@code false}
+   *         otherwise.
+   */
+  private static boolean isAIXPost5()
+  {
+    // TODO: remove this code once the JDK issue referenced in 3077 is
+    // closed.
+    boolean isJDK15 = false;
+    try
+    {
+      final String javaRelease = System.getProperty("java.version");
+      isJDK15 = javaRelease.startsWith("1.5");
+    }
+    catch (final Throwable t)
+    {
+      System.err.println("Cannot get the java version: " + t);
+    }
+    final boolean isAIX = "aix".equalsIgnoreCase(System.getProperty("os.name"));
+    return !isJDK15 && isAIX;
+  }
+
+
+
+  // Descriptor of this message.
+  private final LocalizableMessageDescriptor descriptor;
+
+  // Values used to replace argument specifiers in the format string.
+  private final Object[] args;
+
+
+
+  /**
+   * Creates a new parameterized message instance. See the class header for
+   * instructions on how to create messages outside of this package.
+   *
+   * @param descriptor
+   *          The message descriptor.
+   * @param args
+   *          The message parameters.
+   */
+  private LocalizableMessage(final LocalizableMessageDescriptor descriptor,
+      final Object... args)
+  {
+    this.descriptor = descriptor;
+    this.args = args;
+  }
+
+
+
+  /**
+   * Returns the {@code char} value at the specified index of the {@code String}
+   * representation of this message in the default locale.
+   *
+   * @param index
+   *          The index of the {@code char} value to be returned.
+   * @return The specified {@code char} value.
+   * @throws IndexOutOfBoundsException
+   *           If the {@code index} argument is negative or not less than
+   *           {@code length()}.
+   */
+  public char charAt(final int index) throws IndexOutOfBoundsException
+  {
+    return charAt(Locale.getDefault(), index);
+  }
+
+
+
+  /**
+   * Returns the {@code char} value at the specified index of the {@code String}
+   * representation of this message in the specified locale.
+   *
+   * @param locale
+   *          The locale.
+   * @param index
+   *          The index of the {@code char} value to be returned.
+   * @return The specified {@code char} value.
+   * @throws IndexOutOfBoundsException
+   *           If the {@code index} argument is negative or not less than
+   *           {@code length()}.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public char charAt(final Locale locale, final int index)
+      throws IndexOutOfBoundsException, NullPointerException
+  {
+    return toString(locale).charAt(index);
+  }
+
+
+
+  /**
+   * Compares this message with the specified message for order in the default
+   * locale. Returns a negative integer, zero, or a positive integer as this
+   * object is less than, equal to, or greater than the specified object.
+   *
+   * @param message
+   *          The message to be compared.
+   * @return A negative integer, zero, or a positive integer as this object is
+   *         less than, equal to, or greater than the specified object.
+   */
+  public int compareTo(final LocalizableMessage message)
+  {
+    return toString().compareTo(message.toString());
+  }
+
+
+
+  /**
+   * Returns {@code true} if the provided object is a message whose {@code
+   * String} representation is equal to the {@code String} representation of
+   * this message in the default locale.
+   *
+   * @param o
+   *          The object to be compared for equality with this message.
+   * @return {@code true} if this message is the equal to {@code o}, otherwise
+   *         {@code false}.
+   */
+  @Override
+  public boolean equals(final Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+    else if (o instanceof LocalizableMessage)
+    {
+      final LocalizableMessage message = (LocalizableMessage) o;
+      return toString().equals(message.toString());
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Formats this message using the provided {@link Formatter}.
+   *
+   * @param formatter
+   *          The {@link Formatter}.
+   * @param flags
+   *          The flags modify the output format. The value is interpreted as a
+   *          bitmask. Any combination of the following flags may be set:
+   *          {@link java.util.FormattableFlags#LEFT_JUSTIFY},
+   *          {@link java.util.FormattableFlags#UPPERCASE}, and
+   *          {@link java.util.FormattableFlags#ALTERNATE}. If no flags are set,
+   *          the default formatting of the implementing class will apply.
+   * @param width
+   *          The minimum number of characters to be written to the output. If
+   *          the length of the converted value is less than the {@code width}
+   *          then the output will be padded by white space until the total
+   *          number of characters equals width. The padding is at the beginning
+   *          by default. If the {@link java.util.FormattableFlags#LEFT_JUSTIFY}
+   *          flag is set then the padding will be at the end. If {@code width}
+   *          is {@code -1} then there is no minimum.
+   * @param precision
+   *          The maximum number of characters to be written to the output. The
+   *          precision is applied before the width, thus the output will be
+   *          truncated to {@code precision} characters even if the {@code
+   *          width} is greater than the {@code precision}. If {@code precision}
+   *          is {@code -1} then there is no explicit limit on the number of
+   *          characters.
+   * @throws IllegalFormatException
+   *           If any of the parameters are invalid. For specification of all
+   *           possible formatting errors, see the <a
+   *           href="../util/Formatter.html#detail">Details</a> section of the
+   *           formatter class specification.
+   */
+  public void formatTo(final Formatter formatter, final int flags,
+      final int width, final int precision) throws IllegalFormatException
+  {
+    // Ignores flags, width and precision for now.
+    // see javadoc for Formattable
+    final Locale l = formatter.locale();
+    formatter.format(l, descriptor.getFormatString(l), args);
+  }
+
+
+
+  /**
+   * Returns the hash code value for this message calculated using the hash code
+   * of the {@code String} representation of this message in the default locale.
+   *
+   * @return The hash code value for this message.
+   */
+  @Override
+  public int hashCode()
+  {
+    return toString().hashCode();
+  }
+
+
+
+  /**
+   * Returns the length of the {@code String} representation of this message in
+   * the default locale.
+   *
+   * @return The length of the {@code String} representation of this message in
+   *         the default locale.
+   */
+  public int length()
+  {
+    return length(Locale.getDefault());
+  }
+
+
+
+  /**
+   * Returns the length of the {@code String} representation of this message in
+   * the specified locale.
+   *
+   * @param locale
+   *          The locale.
+   * @return The length of the {@code String} representation of this message in
+   *         the specified locale.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public int length(final Locale locale) throws NullPointerException
+  {
+    return toString(locale).length();
+  }
+
+
+
+  /**
+   * Returns a new {@code CharSequence} which is a subsequence of the {@code
+   * String} representation of this message in the default locale. The
+   * subsequence starts with the {@code char} value at the specified index and
+   * ends with the {@code char} value at index {@code end - 1} . The length (in
+   * {@code char}s) of the returned sequence is {@code end - start}, so if
+   * {@code start == end} then an empty sequence is returned.
+   *
+   * @param start
+   *          The start index, inclusive.
+   * @param end
+   *          The end index, exclusive.
+   * @return The specified subsequence.
+   * @throws IndexOutOfBoundsException
+   *           If {@code start} or {@code end} are negative, if {@code end} is
+   *           greater than {@code length()}, or if {@code start} is greater
+   *           than {@code end}.
+   */
+  public CharSequence subSequence(final int start, final int end)
+      throws IndexOutOfBoundsException
+  {
+    return subSequence(Locale.getDefault(), start, end);
+  }
+
+
+
+  /**
+   * Returns a new {@code CharSequence} which is a subsequence of the {@code
+   * String} representation of this message in the specified locale. The
+   * subsequence starts with the {@code char} value at the specified index and
+   * ends with the {@code char} value at index {@code end - 1} . The length (in
+   * {@code char}s) of the returned sequence is {@code end - start}, so if
+   * {@code start == end} then an empty sequence is returned.
+   *
+   * @param locale
+   *          The locale.
+   * @param start
+   *          The start index, inclusive.
+   * @param end
+   *          The end index, exclusive.
+   * @return The specified subsequence.
+   * @throws IndexOutOfBoundsException
+   *           If {@code start} or {@code end} are negative, if {@code end} is
+   *           greater than {@code length()}, or if {@code start} is greater
+   *           than {@code end}.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public CharSequence subSequence(final Locale locale, final int start,
+      final int end) throws IndexOutOfBoundsException, NullPointerException
+  {
+    return toString(locale).subSequence(start, end);
+  }
+
+
+
+  /**
+   * Returns the {@code String} representation of this message in the default
+   * locale.
+   *
+   * @return The {@code String} representation of this message.
+   */
+  @Override
+  public String toString()
+  {
+    return toString(Locale.getDefault());
+  }
+
+
+
+  /**
+   * Returns the {@code String} representation of this message in the specified
+   * locale.
+   *
+   * @param locale
+   *          The locale.
+   * @return The {@code String} representation of this message.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public String toString(final Locale locale) throws NullPointerException
+  {
+    String s;
+    final String fmt = descriptor.getFormatString(locale);
+    if (descriptor.requiresFormatter())
+    {
+      try
+      {
+        // TODO: remove this code once the JDK issue referenced in 3077
+        // is closed.
+        if (IS_AIX_POST5)
+        {
+          // Java 6 in AIX Formatter does not handle properly
+          // Formattable arguments; this code is a workaround for the
+          // problem.
+          boolean changeType = false;
+          for (final Object o : args)
+          {
+            if (o instanceof Formattable)
+            {
+              changeType = true;
+              break;
+            }
+          }
+          if (changeType)
+          {
+            final Object[] newArgs = new Object[args.length];
+            for (int i = 0; i < args.length; i++)
+            {
+              if (args[i] instanceof Formattable)
+              {
+                newArgs[i] = args[i].toString();
+              }
+              else
+              {
+                newArgs[i] = args[i];
+              }
+            }
+            s = new Formatter(locale).format(locale, fmt, newArgs).toString();
+          }
+          else
+          {
+            s = new Formatter(locale).format(locale, fmt, args).toString();
+          }
+        }
+        else
+        {
+          s = new Formatter(locale).format(locale, fmt, args).toString();
+        }
+      }
+      catch (final IllegalFormatException e)
+      {
+        // This should not happend with any of our internal messages.
+        // However, this may happen for raw messages that have a
+        // mismatch between argument specifier type and argument type.
+        s = fmt;
+      }
+    }
+    else
+    {
+      s = fmt;
+    }
+    if (s == null)
+    {
+      s = "";
+    }
+    return s;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessageBuilder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessageBuilder.java
new file mode 100755
index 0000000..978c0bf
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizableMessageBuilder.java
@@ -0,0 +1,435 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2007-2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A mutable sequence of localizable messages and their parameters. As messages
+ * are appended they are translated to their string representation for storage
+ * using the locale specified in the constructor.
+ * <p>
+ * Note that before you use this class you should consider whether it is
+ * appropriate. In general composing messages by appending message to each other
+ * may not produce a message that is formatted appropriately for all locales.
+ * <p>
+ * It is usually better to create messages by composition. In other words you
+ * should create a base message that contains one or more string argument
+ * specifiers (%s) and define other message objects to use as replacement
+ * variables. In this way language translators have a change to reformat the
+ * message for a particular locale if necessary.
+ *
+ * @see LocalizableMessage
+ */
+public final class LocalizableMessageBuilder implements Appendable,
+    CharSequence, Serializable
+{
+
+  private static final long serialVersionUID = -3292823563904285315L;
+
+  // Used internally to store appended messages.
+  private final List<LocalizableMessage> messages = new LinkedList<LocalizableMessage>();
+
+
+
+  /**
+   * Creates a new message builder whose content is initially empty.
+   */
+  public LocalizableMessageBuilder()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * Creates a new message builder whose content is initially equal to the
+   * provided message.
+   *
+   * @param message
+   *          The initial content of the message builder.
+   * @throws NullPointerException
+   *           If {@code message} was {@code null}.
+   */
+  public LocalizableMessageBuilder(final LocalizableMessage message)
+      throws NullPointerException
+  {
+    append(message);
+  }
+
+
+
+  /**
+   * Creates a new message builder whose content is initially equal to the
+   * provided message builder.
+   *
+   * @param builder
+   *          The initial content of the message builder.
+   * @throws NullPointerException
+   *           If {@code builder} was {@code null}.
+   */
+  public LocalizableMessageBuilder(final LocalizableMessageBuilder builder)
+      throws NullPointerException
+  {
+    for (final LocalizableMessage message : builder.messages)
+    {
+      this.messages.add(message);
+    }
+  }
+
+
+
+  /**
+   * Creates a new message builder whose content is initially equal to the
+   * {@code String} representation of the provided {@code Object}.
+   *
+   * @param object
+   *          The initial content of the message builder, may be {@code null}.
+   */
+  public LocalizableMessageBuilder(final Object object)
+  {
+    append(object);
+  }
+
+
+
+  /**
+   * Appends the provided character to this message builder.
+   *
+   * @param c
+   *          The character to be appended.
+   * @return A reference to this message builder.
+   */
+  public LocalizableMessageBuilder append(final char c)
+  {
+    return append(LocalizableMessage.valueOf(c));
+  }
+
+
+
+  /**
+   * Appends the provided character sequence to this message builder.
+   *
+   * @param cs
+   *          The character sequence to be appended.
+   * @return A reference to this message builder.
+   * @throws NullPointerException
+   *           If {@code cs} was {@code null}.
+   */
+  public LocalizableMessageBuilder append(final CharSequence cs)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(cs);
+    return append((Object) cs);
+  }
+
+
+
+  /**
+   * Appends a subsequence of the provided character sequence to this message
+   * builder.
+   * <p>
+   * An invocation of this method of the form {@code append(cs, start, end)},
+   * behaves in exactly the same way as the invocation
+   *
+   * <pre>
+   * append(cs.subSequence(start, end))
+   * </pre>
+   *
+   * @param cs
+   *          The character sequence to be appended.
+   * @param start
+   *          The index of the first character in the subsequence.
+   * @param end
+   *          The index of the character following the last character in the
+   *          subsequence.
+   * @return A reference to this message builder.
+   * @throws IndexOutOfBoundsException
+   *           If {@code start} or {@code end} are negative, {@code start} is
+   *           greater than {@code end}, or {@code end} is greater than {@code
+   *           csq.length()}.
+   * @throws NullPointerException
+   *           If {@code cs} was {@code null}.
+   */
+  public LocalizableMessageBuilder append(final CharSequence cs,
+      final int start, final int end) throws IndexOutOfBoundsException,
+      NullPointerException
+  {
+    return append(cs.subSequence(start, end));
+  }
+
+
+
+  /**
+   * Appends the provided integer to this message builder.
+   *
+   * @param value
+   *          The integer to be appended.
+   * @return A reference to this message builder.
+   */
+  public LocalizableMessageBuilder append(final int value)
+  {
+    return append(LocalizableMessage.valueOf(value));
+  }
+
+
+
+  /**
+   * Appends the provided message to this message builder.
+   *
+   * @param message
+   *          The message to be appended.
+   * @return A reference to this message builder.
+   * @throws NullPointerException
+   *           If {@code message} was {@code null}.
+   */
+  public LocalizableMessageBuilder append(final LocalizableMessage message)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(message);
+    messages.add(message);
+    return this;
+  }
+
+
+
+  /**
+   * Appends the {@code String} representation of the provided {@code Object} to
+   * this message builder.
+   *
+   * @param object
+   *          The object to be appended, may be {@code null}.
+   * @return A reference to this message builder.
+   */
+  public LocalizableMessageBuilder append(final Object object)
+  {
+    return append(LocalizableMessage.valueOf(object));
+  }
+
+
+
+  /**
+   * Returns the {@code char} value at the specified index of the {@code String}
+   * representation of this message builder in the default locale.
+   *
+   * @param index
+   *          The index of the {@code char} value to be returned.
+   * @return The specified {@code char} value.
+   * @throws IndexOutOfBoundsException
+   *           If the {@code index} argument is negative or not less than
+   *           {@code length()}.
+   */
+  public char charAt(final int index) throws IndexOutOfBoundsException
+  {
+    return charAt(Locale.getDefault(), index);
+  }
+
+
+
+  /**
+   * Returns the {@code char} value at the specified index of the {@code String}
+   * representation of this message builder in the specified locale.
+   *
+   * @param locale
+   *          The locale.
+   * @param index
+   *          The index of the {@code char} value to be returned.
+   * @return The specified {@code char} value.
+   * @throws IndexOutOfBoundsException
+   *           If the {@code index} argument is negative or not less than
+   *           {@code length()}.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public char charAt(final Locale locale, final int index)
+      throws IndexOutOfBoundsException, NullPointerException
+  {
+    return toString(locale).charAt(index);
+  }
+
+
+
+  /**
+   * Returns the length of the {@code String} representation of this message
+   * builder in the default locale.
+   *
+   * @return The length of the {@code String} representation of this message
+   *         builder in the default locale.
+   */
+  public int length()
+  {
+    return length(Locale.getDefault());
+  }
+
+
+
+  /**
+   * Returns the length of the {@code String} representation of this message
+   * builder in the specified locale.
+   *
+   * @param locale
+   *          The locale.
+   * @return The length of the {@code String} representation of this message
+   *         builder in the specified locale.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public int length(final Locale locale) throws NullPointerException
+  {
+    return toString(locale).length();
+  }
+
+
+
+  /**
+   * Returns a new {@code CharSequence} which is a subsequence of the {@code
+   * String} representation of this message builder in the default locale. The
+   * subsequence starts with the {@code char} value at the specified index and
+   * ends with the {@code char} value at index {@code end - 1} . The length (in
+   * {@code char}s) of the returned sequence is {@code end - start}, so if
+   * {@code start == end} then an empty sequence is returned.
+   *
+   * @param start
+   *          The start index, inclusive.
+   * @param end
+   *          The end index, exclusive.
+   * @return The specified subsequence.
+   * @throws IndexOutOfBoundsException
+   *           If {@code start} or {@code end} are negative, if {@code end} is
+   *           greater than {@code length()}, or if {@code start} is greater
+   *           than {@code end}.
+   */
+  public CharSequence subSequence(final int start, final int end)
+      throws IndexOutOfBoundsException
+  {
+    return subSequence(Locale.getDefault(), start, end);
+  }
+
+
+
+  /**
+   * Returns a new {@code CharSequence} which is a subsequence of the {@code
+   * String} representation of this message builder in the specified locale. The
+   * subsequence starts with the {@code char} value at the specified index and
+   * ends with the {@code char} value at index {@code end - 1} . The length (in
+   * {@code char}s) of the returned sequence is {@code end - start}, so if
+   * {@code start == end} then an empty sequence is returned.
+   *
+   * @param locale
+   *          The locale.
+   * @param start
+   *          The start index, inclusive.
+   * @param end
+   *          The end index, exclusive.
+   * @return The specified subsequence.
+   * @throws IndexOutOfBoundsException
+   *           If {@code start} or {@code end} are negative, if {@code end} is
+   *           greater than {@code length()}, or if {@code start} is greater
+   *           than {@code end}.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public CharSequence subSequence(final Locale locale, final int start,
+      final int end) throws IndexOutOfBoundsException, NullPointerException
+  {
+    return toString(locale).subSequence(start, end);
+  }
+
+
+
+  /**
+   * Returns the {@link LocalizableMessage} representation of this message
+   * builder. Subsequent changes to this message builder will not modify the
+   * returned {@code LocalizableMessage}.
+   *
+   * @return The {@code LocalizableMessage} representation of this message
+   *         builder.
+   */
+  public LocalizableMessage toMessage()
+  {
+    if (messages.isEmpty())
+    {
+      return LocalizableMessage.EMPTY;
+    }
+
+    final int sz = messages.size();
+    final StringBuffer fmtString = new StringBuffer(sz * 2);
+    for (int i = 0; i < sz; i++)
+    {
+      fmtString.append("%s");
+    }
+
+    return LocalizableMessage.raw(fmtString, messages.toArray());
+  }
+
+
+
+  /**
+   * Returns the {@code String} representation of this message builder in the
+   * default locale.
+   *
+   * @return The {@code String} representation of this message builder.
+   */
+  @Override
+  public String toString()
+  {
+    return toString(Locale.getDefault());
+  }
+
+
+
+  /**
+   * Returns the {@code String} representation of this message builder in the
+   * specified locale.
+   *
+   * @param locale
+   *          The locale.
+   * @return The {@code String} representation of this message builder.
+   * @throws NullPointerException
+   *           If {@code locale} was {@code null}.
+   */
+  public String toString(final Locale locale) throws NullPointerException
+  {
+    final StringBuilder builder = new StringBuilder();
+    for (final LocalizableMessage message : messages)
+    {
+      builder.append(message.toString(locale));
+    }
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizedIllegalArgumentException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizedIllegalArgumentException.java
new file mode 100644
index 0000000..799d3f0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/LocalizedIllegalArgumentException.java
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * Thrown to indicate that a method has been passed an illegal or inappropriate
+ * argument.
+ * <p>
+ * A {@code LocalizedIllegalArgumentException} contains a localized error
+ * message which maybe used to provide the user with detailed diagnosis
+ * information. The localized message can be retrieved using the
+ * {@link #getMessageObject} method.
+ * <p>
+ * A {@code LocalizedIllegalArgumentException} is typically used to indicate
+ * problems parsing values such as distinguished names and filters.
+ */
+@SuppressWarnings("serial")
+public class LocalizedIllegalArgumentException extends IllegalArgumentException
+    implements LocalizableException
+{
+  // The I18N message associated with this exception.
+  private final LocalizableMessage message;
+
+
+
+  /**
+   * Creates a new localized illegal argument exception with the provided
+   * message.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   */
+  public LocalizedIllegalArgumentException(final LocalizableMessage message)
+  {
+    super(String.valueOf(message));
+    this.message = message;
+  }
+
+
+
+  /**
+   * Creates a new localized illegal argument exception with the provided
+   * message and cause.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   * @param cause
+   *          The cause which may be later retrieved by the {@link #getCause}
+   *          method. A {@code null} value is permitted, and indicates that the
+   *          cause is nonexistent or unknown.
+   */
+  public LocalizedIllegalArgumentException(final LocalizableMessage message,
+      final Throwable cause)
+  {
+    super(String.valueOf(message), cause);
+    this.message = message;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LocalizableMessage getMessageObject()
+  {
+    return this.message;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Matcher.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Matcher.java
new file mode 100644
index 0000000..5145c71
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Matcher.java
@@ -0,0 +1,845 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.util.StaticUtils.DEBUG_LOG;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+
+import org.opends.sdk.schema.MatchingRule;
+import org.opends.sdk.schema.MatchingRuleUse;
+import org.opends.sdk.schema.Schema;
+import org.opends.sdk.schema.UnknownSchemaElementException;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An interface for determining whether entries match a {@code Filter}.
+ */
+public final class Matcher
+{
+  private static final class AndMatcherImpl extends MatcherImpl
+  {
+    private final List<MatcherImpl> subMatchers;
+
+
+
+    private AndMatcherImpl(final List<MatcherImpl> subMatchers)
+    {
+      this.subMatchers = subMatchers;
+    }
+
+
+
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      ConditionResult r = ConditionResult.TRUE;
+      for (final MatcherImpl m : subMatchers)
+      {
+        final ConditionResult p = m.matches(entry);
+        if (p == ConditionResult.FALSE)
+        {
+          return p;
+        }
+        r = ConditionResult.and(r, p);
+      }
+      return r;
+    }
+  }
+
+
+
+  private static final class AssertionMatcherImpl extends MatcherImpl
+  {
+    private final Assertion assertion;
+
+    private final AttributeDescription attributeDescription;
+
+    private final boolean dnAttributes;
+
+    private final MatchingRule rule;
+
+    private final MatchingRuleUse ruleUse;
+
+
+
+    private AssertionMatcherImpl(
+        final AttributeDescription attributeDescription,
+        final MatchingRule rule, final MatchingRuleUse ruleUse,
+        final Assertion assertion, final boolean dnAttributes)
+    {
+      this.attributeDescription = attributeDescription;
+      this.rule = rule;
+      this.ruleUse = ruleUse;
+      this.assertion = assertion;
+      this.dnAttributes = dnAttributes;
+    }
+
+
+
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      ConditionResult r = ConditionResult.FALSE;
+      if (attributeDescription != null)
+      {
+        // If the matchingRule field is absent, the type field will be
+        // present and the default equality matching rule is used,
+        // and an equality match is performed for that type.
+
+        // If the type field is present and the matchingRule is present,
+        // the matchValue is compared against the specified attribute
+        // type and its subtypes.
+        final ConditionResult p = Matcher.matches(entry
+            .getAttribute(attributeDescription), rule, assertion);
+        if (p == ConditionResult.TRUE)
+        {
+          return p;
+        }
+        r = ConditionResult.or(r, p);
+      }
+      else
+      {
+        // If the type field is absent and the matchingRule is present,
+        // the matchValue is compared against all attributes in an entry
+        // that support that matchingRule.
+        for (final Attribute a : entry.getAllAttributes())
+        {
+          if (ruleUse.hasAttribute(a.getAttributeDescription()
+              .getAttributeType()))
+          {
+            final ConditionResult p = Matcher.matches(a, rule, assertion);
+            if (p == ConditionResult.TRUE)
+            {
+              return p;
+            }
+            r = ConditionResult.or(r, p);
+          }
+        }
+      }
+
+      if (dnAttributes)
+      {
+        // If the dnAttributes field is set to TRUE, the match is
+        // additionally applied against all the AttributeValueAssertions
+        // in an entry's distinguished name, and it evaluates to TRUE if
+        // there is at least one attribute or subtype in the
+        // distinguished name for which the filter item evaluates to
+        // TRUE.
+        final DN dn = entry.getName();
+        for (final RDN rdn : dn)
+        {
+          for (final AVA ava : rdn)
+          {
+            if (ruleUse.hasAttribute(ava.getAttributeType()))
+            {
+              final ConditionResult p = Matcher.matches(
+                  ava.getAttributeValue(), rule, assertion);
+              if (p == ConditionResult.TRUE)
+              {
+                return p;
+              }
+              r = ConditionResult.or(r, p);
+            }
+          }
+        }
+      }
+      return r;
+    }
+  }
+
+
+
+  private static class FalseMatcherImpl extends MatcherImpl
+  {
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      return ConditionResult.FALSE;
+    }
+  }
+
+
+
+  private static abstract class MatcherImpl
+  {
+    public abstract ConditionResult matches(Entry entry);
+  }
+
+
+
+  private static final class NotMatcherImpl extends MatcherImpl
+  {
+    private final MatcherImpl subFilter;
+
+
+
+    private NotMatcherImpl(final MatcherImpl subFilter)
+    {
+      this.subFilter = subFilter;
+    }
+
+
+
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      return ConditionResult.not(subFilter.matches(entry));
+    }
+  }
+
+
+
+  private static final class OrMatcherImpl extends MatcherImpl
+  {
+    private final List<MatcherImpl> subMatchers;
+
+
+
+    private OrMatcherImpl(final List<MatcherImpl> subMatchers)
+    {
+      this.subMatchers = subMatchers;
+    }
+
+
+
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      ConditionResult r = ConditionResult.FALSE;
+      for (final MatcherImpl m : subMatchers)
+      {
+        final ConditionResult p = m.matches(entry);
+        if (p == ConditionResult.TRUE)
+        {
+          return p;
+        }
+        r = ConditionResult.or(r, p);
+      }
+      return r;
+    }
+  }
+
+
+
+  private static final class PresentMatcherImpl extends MatcherImpl
+  {
+    private final AttributeDescription attribute;
+
+
+
+    private PresentMatcherImpl(final AttributeDescription attribute)
+    {
+      this.attribute = attribute;
+    }
+
+
+
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      return entry.getAttribute(attribute) == null ? ConditionResult.FALSE
+          : ConditionResult.TRUE;
+    }
+  }
+
+
+
+  private static class TrueMatcherImpl extends MatcherImpl
+  {
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      return ConditionResult.TRUE;
+    }
+  }
+
+
+
+  private static class UndefinedMatcherImpl extends MatcherImpl
+  {
+    @Override
+    public ConditionResult matches(final Entry entry)
+    {
+      return ConditionResult.UNDEFINED;
+    }
+  }
+
+
+
+  /**
+   * A visitor which is used to transform a filter into a matcher.
+   */
+  private static final class Visitor implements
+      FilterVisitor<MatcherImpl, Schema>
+  {
+    public MatcherImpl visitAndFilter(final Schema schema,
+        final List<Filter> subFilters)
+    {
+      if (subFilters.isEmpty())
+      {
+        if (DEBUG_LOG.isLoggable(Level.FINER))
+        {
+          DEBUG_LOG.finer("Empty add filter component. "
+              + "Will always return TRUE");
+        }
+        return TRUE;
+      }
+
+      final List<MatcherImpl> subMatchers = new ArrayList<MatcherImpl>(
+          subFilters.size());
+      for (final Filter f : subFilters)
+      {
+        subMatchers.add(f.accept(this, schema));
+      }
+      return new AndMatcherImpl(subMatchers);
+    }
+
+
+
+    public MatcherImpl visitApproxMatchFilter(final Schema schema,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      AttributeDescription ad;
+      MatchingRule rule;
+      Assertion assertion;
+
+      try
+      {
+        ad = AttributeDescription.valueOf(attributeDescription, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("Attribute description " + attributeDescription
+              + " is not recognized: " + e.toString());
+        }
+        return UNDEFINED;
+      }
+
+      if ((rule = ad.getAttributeType().getApproximateMatchingRule()) == null)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The attribute type " + attributeDescription
+              + " does not define an approximate matching rule");
+        }
+        return UNDEFINED;
+      }
+
+      try
+      {
+        assertion = rule.getAssertion(assertionValue);
+      }
+      catch (final DecodeException de)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
+        }
+        return UNDEFINED;
+      }
+      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
+    }
+
+
+
+    public MatcherImpl visitEqualityMatchFilter(final Schema schema,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      AttributeDescription ad;
+      MatchingRule rule;
+      Assertion assertion;
+
+      try
+      {
+        ad = AttributeDescription.valueOf(attributeDescription, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("Attribute description " + attributeDescription
+              + " is not recognized: " + e.toString());
+        }
+        return UNDEFINED;
+      }
+
+      if ((rule = ad.getAttributeType().getEqualityMatchingRule()) == null)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The attribute type " + attributeDescription
+              + " does not define an equality matching rule");
+        }
+        return UNDEFINED;
+      }
+
+      try
+      {
+        assertion = rule.getAssertion(assertionValue);
+      }
+      catch (final DecodeException de)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
+        }
+        return UNDEFINED;
+      }
+      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
+    }
+
+
+
+    public MatcherImpl visitExtensibleMatchFilter(final Schema schema,
+        final String matchingRule, final String attributeDescription,
+        final ByteString assertionValue, final boolean dnAttributes)
+    {
+      AttributeDescription ad = null;
+      MatchingRule rule = null;
+      MatchingRuleUse ruleUse = null;
+      Assertion assertion;
+
+      if (matchingRule != null)
+      {
+        try
+        {
+          rule = schema.getMatchingRule(matchingRule);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          if (DEBUG_LOG.isLoggable(Level.WARNING))
+          {
+            DEBUG_LOG.warning("Matching rule " + matchingRule
+                + " is not recognized: " + e.toString());
+          }
+          return UNDEFINED;
+        }
+      }
+
+      if (attributeDescription != null)
+      {
+        try
+        {
+          ad = AttributeDescription.valueOf(attributeDescription, schema);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          if (DEBUG_LOG.isLoggable(Level.WARNING))
+          {
+            DEBUG_LOG.warning("Attribute description " + attributeDescription
+                + " is not recognized: " + e.toString());
+          }
+          return UNDEFINED;
+        }
+
+        if (rule == null)
+        {
+          if ((rule = ad.getAttributeType().getEqualityMatchingRule()) == null)
+          {
+            if (DEBUG_LOG.isLoggable(Level.WARNING))
+            {
+              DEBUG_LOG.warning("The attribute type " + attributeDescription
+                  + " does not define an equality matching rule");
+            }
+            return UNDEFINED;
+          }
+        }
+        else
+        {
+          try
+          {
+            ruleUse = schema.getMatchingRuleUse(rule);
+          }
+          catch (final UnknownSchemaElementException e)
+          {
+            if (DEBUG_LOG.isLoggable(Level.WARNING))
+            {
+              DEBUG_LOG.warning("No matching rule use is defined for "
+                  + "matching rule " + matchingRule);
+              return UNDEFINED;
+            }
+          }
+          if (!ruleUse.hasAttribute(ad.getAttributeType()))
+          {
+            if (DEBUG_LOG.isLoggable(Level.WARNING))
+            {
+              DEBUG_LOG.warning("The matching rule " + matchingRule
+                  + " is not valid for attribute type " + attributeDescription);
+            }
+            return UNDEFINED;
+          }
+        }
+      }
+      else
+      {
+        try
+        {
+          ruleUse = schema.getMatchingRuleUse(rule);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          if (DEBUG_LOG.isLoggable(Level.WARNING))
+          {
+            DEBUG_LOG.warning("No matching rule use is defined for "
+                + "matching rule " + matchingRule);
+          }
+          return UNDEFINED;
+        }
+      }
+
+      try
+      {
+        assertion = rule.getAssertion(assertionValue);
+      }
+      catch (final DecodeException de)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
+        }
+        return UNDEFINED;
+      }
+      return new AssertionMatcherImpl(ad, rule, ruleUse, assertion,
+          dnAttributes);
+    }
+
+
+
+    public MatcherImpl visitGreaterOrEqualFilter(final Schema schema,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      AttributeDescription ad;
+      MatchingRule rule;
+      Assertion assertion;
+
+      try
+      {
+        ad = AttributeDescription.valueOf(attributeDescription, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("Attribute description " + attributeDescription
+              + " is not recognized: " + e.toString());
+        }
+        return UNDEFINED;
+      }
+
+      if ((rule = ad.getAttributeType().getOrderingMatchingRule()) == null)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The attribute type " + attributeDescription
+              + " does not define an ordering matching rule");
+        }
+        return UNDEFINED;
+      }
+
+      try
+      {
+        assertion = rule.getGreaterOrEqualAssertion(assertionValue);
+      }
+      catch (final DecodeException de)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
+        }
+        return UNDEFINED;
+      }
+      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
+    }
+
+
+
+    public MatcherImpl visitLessOrEqualFilter(final Schema schema,
+        final String attributeDescription, final ByteString assertionValue)
+    {
+      AttributeDescription ad;
+      MatchingRule rule;
+      Assertion assertion;
+
+      try
+      {
+        ad = AttributeDescription.valueOf(attributeDescription, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("Attribute description " + attributeDescription
+              + " is not recognized: " + e.toString());
+        }
+        return UNDEFINED;
+      }
+
+      if ((rule = ad.getAttributeType().getOrderingMatchingRule()) == null)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The attribute type " + attributeDescription
+              + " does not define an ordering matching rule");
+        }
+        return UNDEFINED;
+      }
+
+      try
+      {
+        assertion = rule.getLessOrEqualAssertion(assertionValue);
+      }
+      catch (final DecodeException de)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The assertion value " + assertionValue
+              + " is invalid: " + de.toString());
+        }
+        return UNDEFINED;
+      }
+      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
+    }
+
+
+
+    public MatcherImpl visitNotFilter(final Schema schema,
+        final Filter subFilter)
+    {
+      final MatcherImpl subMatcher = subFilter.accept(this, schema);
+      return new NotMatcherImpl(subMatcher);
+    }
+
+
+
+    public MatcherImpl visitOrFilter(final Schema schema,
+        final List<Filter> subFilters)
+    {
+      if (subFilters.isEmpty())
+      {
+        if (DEBUG_LOG.isLoggable(Level.FINER))
+        {
+          DEBUG_LOG.finer("Empty or filter component. "
+              + "Will always return FALSE");
+        }
+        return FALSE;
+      }
+
+      final List<MatcherImpl> subMatchers = new ArrayList<MatcherImpl>(
+          subFilters.size());
+      for (final Filter f : subFilters)
+      {
+        subMatchers.add(f.accept(this, schema));
+      }
+      return new OrMatcherImpl(subMatchers);
+    }
+
+
+
+    public MatcherImpl visitPresentFilter(final Schema schema,
+        final String attributeDescription)
+    {
+      AttributeDescription ad;
+      try
+      {
+        ad = AttributeDescription.valueOf(attributeDescription, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("Attribute description " + attributeDescription
+              + " is not recognized: " + e.toString());
+        }
+        return UNDEFINED;
+      }
+
+      return new PresentMatcherImpl(ad);
+    }
+
+
+
+    public MatcherImpl visitSubstringsFilter(final Schema schema,
+        final String attributeDescription, final ByteString initialSubstring,
+        final List<ByteString> anySubstrings, final ByteString finalSubstring)
+    {
+      AttributeDescription ad;
+      MatchingRule rule;
+      Assertion assertion;
+
+      try
+      {
+        ad = AttributeDescription.valueOf(attributeDescription, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("Attribute description " + attributeDescription
+              + " is not recognized: " + e.toString());
+        }
+        return UNDEFINED;
+      }
+
+      if ((rule = ad.getAttributeType().getSubstringMatchingRule()) == null)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG.warning("The attribute type " + attributeDescription
+              + " does not define an substring matching rule");
+        }
+        return UNDEFINED;
+      }
+
+      try
+      {
+        assertion = rule.getAssertion(initialSubstring, anySubstrings,
+            finalSubstring);
+      }
+      catch (final DecodeException de)
+      {
+        if (DEBUG_LOG.isLoggable(Level.WARNING))
+        {
+          DEBUG_LOG
+              .warning("The substring assertion values contain an invalid value: "
+                  + de.toString());
+        }
+        return UNDEFINED;
+      }
+      return new AssertionMatcherImpl(ad, rule, null, assertion, false);
+    }
+
+
+
+    public MatcherImpl visitUnrecognizedFilter(final Schema schema,
+        final byte filterTag, final ByteString filterBytes)
+    {
+      if (DEBUG_LOG.isLoggable(Level.WARNING))
+      {
+        DEBUG_LOG.warning("The type of filtering requested with tag "
+            + StaticUtils.byteToHex(filterTag) + " is not implemented");
+      }
+      return UNDEFINED;
+    }
+  }
+
+
+
+  private static final MatcherImpl FALSE = new FalseMatcherImpl();
+
+  private static final MatcherImpl TRUE = new TrueMatcherImpl();
+
+  private static final MatcherImpl UNDEFINED = new UndefinedMatcherImpl();
+
+  private static final FilterVisitor<MatcherImpl, Schema> VISITOR = new Visitor();
+
+
+
+  private static ConditionResult matches(final Attribute a,
+      final MatchingRule rule, final Assertion assertion)
+  {
+
+    ConditionResult r = ConditionResult.FALSE;
+    if (a != null)
+    {
+      for (final ByteString v : a)
+      {
+        switch (matches(v, rule, assertion))
+        {
+        case TRUE:
+          return ConditionResult.TRUE;
+        case UNDEFINED:
+          r = ConditionResult.UNDEFINED;
+        }
+      }
+    }
+    return r;
+  }
+
+
+
+  private static ConditionResult matches(final ByteString v,
+      final MatchingRule rule, final Assertion assertion)
+  {
+    try
+    {
+      final ByteString normalizedValue = rule.normalizeAttributeValue(v);
+      return assertion.matches(normalizedValue);
+    }
+    catch (final DecodeException de)
+    {
+      if (DEBUG_LOG.isLoggable(Level.WARNING))
+      {
+        DEBUG_LOG.warning("The attribute value " + v.toString() + " is "
+            + "invalid for matching rule " + rule.getNameOrOID()
+            + ". Possible schema error? : " + de.toString());
+      }
+      return ConditionResult.UNDEFINED;
+    }
+  }
+
+
+
+  private final MatcherImpl impl;
+
+
+
+  Matcher(final Filter filter, final Schema schema)
+  {
+    this.impl = filter.accept(VISITOR, schema);
+  }
+
+
+
+  /**
+   * Indicates whether this filter {@code Matcher} matches the provided {@code
+   * Entry}.
+   *
+   * @param entry
+   *          The entry to be matched.
+   * @return {@code true} if this filter {@code Matcher} matches the provided
+   *         {@code Entry}.
+   */
+  public ConditionResult matches(final Entry entry)
+  {
+    return impl.matches(entry);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Modification.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Modification.java
new file mode 100644
index 0000000..3f61b9c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/Modification.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A modification to be performed on an entry during a Modify operation.
+ */
+public final class Modification
+{
+  private final ModificationType modificationType;
+
+  private final Attribute attribute;
+
+
+
+  /**
+   * Creates a new modification having the provided modification type and
+   * attribute values to be updated. Note that while the returned {@code
+   * Modification} is immutable, the underlying attribute may not be. The
+   * following code ensures that the returned {@code Modification} is fully
+   * immutable:
+   *
+   * <pre>
+   * Modification change = new Modification(modificationType, Types
+   *     .unmodifiableAttribute(attribute));
+   * </pre>
+   *
+   * @param modificationType
+   *          The type of modification to be performed.
+   * @param attribute
+   *          The the attribute containing the values to be modified.
+   */
+  public Modification(final ModificationType modificationType,
+      final Attribute attribute)
+  {
+    Validator.ensureNotNull(modificationType, attribute);
+
+    this.modificationType = modificationType;
+    this.attribute = attribute;
+  }
+
+
+
+  /**
+   * Returns the attribute containing the values to be modified.
+   *
+   * @return The the attribute containing the values to be modified.
+   */
+  public Attribute getAttribute()
+  {
+    return attribute;
+  }
+
+
+
+  /**
+   * Returns the type of modification to be performed.
+   *
+   * @return The type of modification to be performed.
+   */
+  public ModificationType getModificationType()
+  {
+    return modificationType;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("Modification(modificationType=");
+    builder.append(modificationType);
+    builder.append(", attributeDescription=");
+    builder.append(attribute.getAttributeDescriptionAsString());
+    builder.append(", attributeValues={");
+    boolean firstValue = true;
+    for (final ByteString value : attribute)
+    {
+      if (!firstValue)
+      {
+        builder.append(", ");
+      }
+      builder.append(value);
+      firstValue = false;
+    }
+    builder.append("})");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ModificationType.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ModificationType.java
new file mode 100644
index 0000000..1751094
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ModificationType.java
@@ -0,0 +1,208 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * A Modify operation change type as defined in RFC 4511 section 4.6 is used to
+ * specify the type of modification being performed on an attribute.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.6">RFC 4511 -
+ *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4525">RFC 4525 - Lightweight
+ *      Directory Access Protocol (LDAP) Modify-Increment Extension </a>
+ */
+public final class ModificationType
+{
+  private static final ModificationType[] ELEMENTS = new ModificationType[4];
+
+  private static final List<ModificationType> IMMUTABLE_ELEMENTS = Collections
+      .unmodifiableList(Arrays.asList(ELEMENTS));
+
+  /**
+   * Add the values listed in the modification to the attribute, creating the
+   * attribute if necessary.
+   */
+  public static final ModificationType ADD = register(0, "add");
+
+  /**
+   * Delete the values listed in the modification from the attribute. If no
+   * values are listed, or if all current values of the attribute are listed,
+   * the entire attribute is removed.
+   */
+  public static final ModificationType DELETE = register(1, "delete");
+
+  /**
+   * Replace all existing values of the attribute with the new values listed in
+   * the modification, creating the attribute if it did not already exist. A
+   * replace with no listed values will delete the entire attribute if it
+   * exists, and it is ignored if the attribute does not exist.
+   */
+  public static final ModificationType REPLACE = register(2, "replace");
+
+  /**
+   * Increment all existing values of the attribute by the amount specified in
+   * the modification value.
+   */
+  public static final ModificationType INCREMENT = register(3, "increment");
+
+
+
+  /**
+   * Returns the modification change type having the specified integer value as
+   * defined in RFC 4511 section 4.6.
+   *
+   * @param intValue
+   *          The integer value of the modification change type.
+   * @return The modification change type, or {@code null} if there was no
+   *         modification change type associated with {@code intValue}.
+   */
+  public static ModificationType valueOf(final int intValue)
+  {
+    if (intValue < 0 || intValue >= ELEMENTS.length)
+    {
+      return null;
+    }
+    return ELEMENTS[intValue];
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the set of available modification
+   * change types indexed on their integer value as defined in RFC 4511 section
+   * 4.6.
+   *
+   * @return An unmodifiable list containing the set of available modification
+   *         change types.
+   */
+  public static List<ModificationType> values()
+  {
+    return IMMUTABLE_ELEMENTS;
+  }
+
+
+
+  /**
+   * Creates and registers a new modification change type with the application.
+   *
+   * @param intValue
+   *          The integer value of the modification change type as defined in
+   *          RFC 4511 section 4.6.
+   * @param name
+   *          The name of the modification change type.
+   * @return The new modification change type.
+   */
+  private static ModificationType register(final int intValue, final String name)
+  {
+    final ModificationType t = new ModificationType(intValue, name);
+    ELEMENTS[intValue] = t;
+    return t;
+  }
+
+
+
+  private final int intValue;
+
+  private final String name;
+
+
+
+  // Prevent direct instantiation.
+  private ModificationType(final int intValue, final String name)
+  {
+    this.intValue = intValue;
+    this.name = name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    else if (obj instanceof ModificationType)
+    {
+      return this.intValue == ((ModificationType) obj).intValue;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Returns the integer value of this modification change type as defined in
+   * RFC 4511 section 4.6.
+   *
+   * @return The integer value of this modification change type.
+   */
+  public int intValue()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Returns the string representation of this modification change type.
+   *
+   * @return The string representation of this modification change type.
+   */
+  @Override
+  public String toString()
+  {
+    return name;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/MultipleEntriesFoundException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/MultipleEntriesFoundException.java
new file mode 100644
index 0000000..cf7e736
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/MultipleEntriesFoundException.java
@@ -0,0 +1,51 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the requested
+ * single entry search operation or read operation failed because the Directory
+ * Server returned multiple matching entries (or search references) when only a
+ * single matching entry was expected. More specifically, this exception is used
+ * for the {@link ResultCode#CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED
+ * CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED} error result codes.
+ */
+@SuppressWarnings("serial")
+public class MultipleEntriesFoundException extends ErrorResultException
+{
+  MultipleEntriesFoundException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RDN.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RDN.java
new file mode 100644
index 0000000..149a8e4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RDN.java
@@ -0,0 +1,420 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_RDN_TYPE_NOT_FOUND;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.opends.sdk.schema.AttributeType;
+import org.opends.sdk.schema.Schema;
+import org.opends.sdk.schema.UnknownSchemaElementException;
+
+import com.sun.opends.sdk.util.Iterators;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * A relative distinguished name (RDN) as defined in RFC 4512 section 2.3 is the
+ * name of an entry relative to its immediate superior. An RDN is composed of an
+ * unordered set of one or more attribute value assertions (AVA) consisting of
+ * an attribute description with zero options and an attribute value. These AVAs
+ * are chosen to match attribute values (each a distinguished value) of the
+ * entry.
+ * <p>
+ * An entry's relative distinguished name must be unique among all immediate
+ * subordinates of the entry's immediate superior (i.e. all siblings).
+ * <p>
+ * The following are examples of string representations of RDNs:
+ *
+ * <pre>
+ * uid=12345
+ * ou=Engineering
+ * cn=Kurt Zeilenga+L=Redwood Shores
+ * </pre>
+ *
+ * The last is an example of a multi-valued RDN; that is, an RDN composed of
+ * multiple AVAs.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4512#section-2.3">RFC 4512 -
+ *      Lightweight Directory Access Protocol (LDAP): Directory Information
+ *      Models </a>
+ */
+public final class RDN implements Iterable<AVA>, Comparable<RDN>
+{
+  /**
+   * Parses the provided LDAP string representation of an RDN using the default
+   * schema.
+   *
+   * @param rdn
+   *          The LDAP string representation of a RDN.
+   * @return The parsed RDN.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code rdn} is not a valid LDAP string representation of a
+   *           RDN.
+   * @throws NullPointerException
+   *           If {@code rdn} was {@code null}.
+   */
+  public static RDN valueOf(final String rdn)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return valueOf(rdn, Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Parses the provided LDAP string representation of a RDN using the provided
+   * schema.
+   *
+   * @param rdn
+   *          The LDAP string representation of a RDN.
+   * @param schema
+   *          The schema to use when parsing the RDN.
+   * @return The parsed RDN.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code rdn} is not a valid LDAP string representation of a
+   *           RDN.
+   * @throws NullPointerException
+   *           If {@code rdn} or {@code schema} was {@code null}.
+   */
+  public static RDN valueOf(final String rdn, final Schema schema)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    final SubstringReader reader = new SubstringReader(rdn);
+    try
+    {
+      return decode(rdn, reader, schema);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      final LocalizableMessage message = ERR_RDN_TYPE_NOT_FOUND.get(rdn, e
+          .getMessageObject());
+      throw new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  // FIXME: ensure that the decoded RDN does not contain multiple AVAs
+  // with the same type.
+  static RDN decode(final String rdnString, final SubstringReader reader,
+      final Schema schema) throws LocalizedIllegalArgumentException,
+      UnknownSchemaElementException
+  {
+    final AVA firstAVA = AVA.decode(reader, schema);
+
+    // Skip over any spaces that might be after the attribute value.
+    reader.skipWhitespaces();
+
+    reader.mark();
+    if (reader.remaining() > 0 && reader.read() == '+')
+    {
+      final List<AVA> avas = new ArrayList<AVA>();
+      avas.add(firstAVA);
+
+      do
+      {
+        avas.add(AVA.decode(reader, schema));
+
+        // Skip over any spaces that might be after the attribute value.
+        reader.skipWhitespaces();
+
+        reader.mark();
+      }
+      while (reader.remaining() > 0 && reader.read() == '+');
+
+      reader.reset();
+      return new RDN(avas.toArray(new AVA[avas.size()]), null);
+    }
+    else
+    {
+      reader.reset();
+      return new RDN(new AVA[] { firstAVA }, null);
+    }
+  }
+
+
+
+  // In original order.
+  private final AVA[] avas;
+
+  // We need to store the original string value if provided in order to
+  // preserve the original whitespace.
+  private String stringValue;
+
+
+
+  /**
+   * Creates a new RDN using the provided attribute type and value.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @param attributeValue
+   *          The attribute value.
+   * @throws NullPointerException
+   *           If {@code attributeType} or {@code attributeValue} was {@code
+   *           null}.
+   */
+  public RDN(final AttributeType attributeType, final ByteString attributeValue)
+      throws NullPointerException
+  {
+    this.avas = new AVA[] { new AVA(attributeType, attributeValue) };
+  }
+
+
+
+  /**
+   * Creates a new RDN using the provided attribute type and value decoded using
+   * the default schema.
+   * <p>
+   * If {@code attributeValue} is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @param attributeValue
+   *          The attribute value.
+   * @throws UnknownSchemaElementException
+   *           If {@code attributeType} was not found in the default schema.
+   * @throws NullPointerException
+   *           If {@code attributeType} or {@code attributeValue} was {@code
+   *           null}.
+   */
+  public RDN(final String attributeType, final Object attributeValue)
+      throws UnknownSchemaElementException, NullPointerException
+  {
+    this.avas = new AVA[] { new AVA(attributeType, attributeValue) };
+  }
+
+
+
+  private RDN(final AVA[] avas, final String stringValue)
+  {
+    this.avas = avas;
+    this.stringValue = stringValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int compareTo(final RDN rdn)
+  {
+    final int sz1 = avas.length;
+    final int sz2 = rdn.avas.length;
+
+    if (sz1 != sz2)
+    {
+      return sz1 - sz2 > 0 ? 1 : -1;
+    }
+
+    if (sz1 == 1)
+    {
+      return avas[0].compareTo(rdn.avas[0]);
+    }
+
+    // Need to sort the AVAs before comparing.
+    final AVA[] a1 = new AVA[sz1];
+    System.arraycopy(avas, 0, a1, 0, sz1);
+    Arrays.sort(a1);
+
+    final AVA[] a2 = new AVA[sz1];
+    System.arraycopy(rdn.avas, 0, a2, 0, sz1);
+    Arrays.sort(a2);
+
+    for (int i = 0; i < sz1; i++)
+    {
+      final int result = a1[i].compareTo(a2[i]);
+      if (result != 0)
+      {
+        return result;
+      }
+    }
+
+    return 0;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    else if (obj instanceof RDN)
+    {
+      return compareTo((RDN) obj) == 0;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Returns the attribute value contained in this RDN which is associated with
+   * the provided attribute type, or {@code null} if this RDN does not include
+   * such an attribute value.
+   *
+   * @param attributeType
+   *          The attribute type.
+   * @return The attribute value.
+   */
+  public ByteString getAttributeValue(final AttributeType attributeType)
+  {
+    for (final AVA ava : avas)
+    {
+      if (ava.getAttributeType().equals(attributeType))
+      {
+        return ava.getAttributeValue();
+      }
+    }
+    return null;
+  }
+
+
+
+  /**
+   * Returns the first AVA contained in this RDN.
+   *
+   * @return The first AVA contained in this RDN.
+   */
+  public AVA getFirstAVA()
+  {
+    return avas[0];
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    // Avoid an algorithm that requires the AVAs to be sorted.
+    int hash = 0;
+    for (final AVA ava : avas)
+    {
+      hash += ava.hashCode();
+    }
+    return hash;
+  }
+
+
+
+  /**
+   * Returns {@code true} if this RDN contains more than one AVA.
+   *
+   * @return {@code true} if this RDN contains more than one AVA, otherwise
+   *         {@code false}.
+   */
+  public boolean isMultiValued()
+  {
+    return avas.length > 1;
+  }
+
+
+
+  /**
+   * Returns an iterator of the AVAs contained in this RDN. The AVAs will be
+   * returned in the user provided order.
+   * <p>
+   * Attempts to remove AVAs using an iterator's {@code remove()} method are not
+   * permitted and will result in an {@code UnsupportedOperationException} being
+   * thrown.
+   *
+   * @return An iterator of the AVAs contained in this RDN.
+   */
+  public Iterator<AVA> iterator()
+  {
+    return Iterators.arrayIterator(avas);
+  }
+
+
+
+  /**
+   * Returns the number of AVAs in this RDN.
+   *
+   * @return The number of AVAs in this RDN.
+   */
+  public int size()
+  {
+    return avas.length;
+  }
+
+
+
+  /**
+   * Returns the RFC 4514 string representation of this RDN.
+   *
+   * @return The RFC 4514 string representation of this RDN.
+   * @see <a href="http://tools.ietf.org/html/rfc4514">RFC 4514 - Lightweight
+   *      Directory Access Protocol (LDAP): String Representation of
+   *      Distinguished Names </a>
+   */
+  @Override
+  public String toString()
+  {
+    // We don't care about potential race conditions here.
+    if (stringValue == null)
+    {
+      final StringBuilder builder = new StringBuilder();
+      avas[0].toString(builder);
+      for (int i = 1; i < avas.length; i++)
+      {
+        builder.append('+');
+        avas[i].toString(builder);
+      }
+      stringValue = builder.toString();
+    }
+    return stringValue;
+  }
+
+
+
+  StringBuilder toString(final StringBuilder builder)
+  {
+    return builder.append(toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ReferralException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ReferralException.java
new file mode 100644
index 0000000..9174eb0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ReferralException.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * could not be processed by the Directory Server because the target entry is
+ * located on another server. More specifically, this exception is used for the
+ * {@link ResultCode#REFERRAL REFERRAL} result code.
+ */
+@SuppressWarnings("serial")
+public class ReferralException extends EntryNotFoundException
+{
+  ReferralException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RequestHandler.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RequestHandler.java
new file mode 100644
index 0000000..3287721
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RequestHandler.java
@@ -0,0 +1,245 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.CompareResult;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * A handler interface for processing client requests.
+ * <p>
+ * Implementations must always return results using the provided
+ * {@link ResultHandler} unless explicitly permitted.
+ * <p>
+ * For example, an {@link LDAPListener} does not require {@code RequestHandler}
+ * implementations to return results, which may be useful when implementing
+ * abandon operation functionality. Conversely, an access logger implemented as
+ * a {@code RequestHandler} wrapper will require wrapped {@code RequestHandler}s
+ * to always return results, even abandoned results, in order for it to log the
+ * result status.
+ *
+ * @param <C>
+ *          The type of request context.
+ * @see ServerConnectionFactory
+ */
+public interface RequestHandler<C>
+{
+
+  /**
+   * Invoked when an add request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The add request.
+   * @param resultHandler
+   *          The handler which should be used to send back the result to the
+   *          client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle add requests.
+   */
+  void handleAdd(C requestContext, AddRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when a bind request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param version
+   *          The protocol version included with the bind request.
+   * @param request
+   *          The bind request.
+   * @param resultHandler
+   *          The handler which should be used to send back the result to the
+   *          client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle bind requests.
+   */
+  void handleBind(C requestContext, int version, BindRequest request,
+      ResultHandler<? super BindResult> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when a compare request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The compare request.
+   * @param resultHandler
+   *          The handler which should be used to send back the result to the
+   *          client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle compare requests.
+   */
+  void handleCompare(C requestContext, CompareRequest request,
+      ResultHandler<? super CompareResult> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when a delete request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The delete request.
+   * @param resultHandler
+   *          The handler which should be used to send back the result to the
+   *          client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle delete requests.
+   */
+  void handleDelete(C requestContext, DeleteRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when an extended request is received from a client.
+   *
+   * @param <R>
+   *          The type of result returned by the extended request.
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The extended request.
+   * @param resultHandler
+   *          The handler which should be used to send back the result to the
+   *          client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle extended requests.
+   */
+  <R extends ExtendedResult> void handleExtendedRequest(C requestContext,
+      ExtendedRequest<R> request, ResultHandler<? super R> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when a modify request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The modify request.
+   * @param resultHandler
+   *          The handler which should be used to send back the result to the
+   *          client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle modify requests.
+   */
+  void handleModify(C requestContext, ModifyRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when a modify DN request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The modify DN request.
+   * @param resultHandler
+   *          The handler which should be used to send back the result to the
+   *          client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle modify DN requests.
+   */
+  void handleModifyDN(C requestContext, ModifyDNRequest request,
+      ResultHandler<? super Result> resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when a search request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The search request.
+   * @param resultHandler
+   *          The handler which should be used to send back the search results
+   *          to the client.
+   * @param intermediateResponseHandler
+   *          The handler which should be used to send back any intermediate
+   *          responses to the client.
+   * @throws UnsupportedOperationException
+   *           If this request handler does not handle search requests.
+   */
+  void handleSearch(C requestContext, SearchRequest request,
+      SearchResultHandler resultHandler,
+      IntermediateResponseHandler intermediateResponseHandler)
+      throws UnsupportedOperationException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultCode.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultCode.java
new file mode 100644
index 0000000..36f2720
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultCode.java
@@ -0,0 +1,747 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * An operation result code as defined in RFC 4511 section 4.1.9 is used to
+ * indicate the final status of an operation. If a server detects multiple
+ * errors for an operation, only one result code is returned. The server should
+ * return the result code that best indicates the nature of the error
+ * encountered. Servers may return substituted result codes to prevent
+ * unauthorized disclosures.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.1.9">RFC 4511 -
+ *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
+ */
+public final class ResultCode
+{
+  private static final ResultCode[] ELEMENTS = new ResultCode[16655];
+
+  private static final List<ResultCode> IMMUTABLE_ELEMENTS = Collections
+      .unmodifiableList(Arrays.asList(ELEMENTS));
+
+  /**
+   * The result code that indicates that the operation completed successfully.
+   */
+  public static final ResultCode SUCCESS = registerSuccessResultCode(0,
+      INFO_RESULT_SUCCESS.get());
+
+  /**
+   * The result code that indicates that an internal error prevented the
+   * operation from being processed properly.
+   */
+  public static final ResultCode OPERATIONS_ERROR = registerErrorResultCode(1,
+      INFO_RESULT_OPERATIONS_ERROR.get());
+
+  /**
+   * The result code that indicates that the client sent a malformed or illegal
+   * request to the server.
+   */
+  public static final ResultCode PROTOCOL_ERROR = registerErrorResultCode(2,
+      INFO_RESULT_PROTOCOL_ERROR.get());
+
+  /**
+   * The result code that indicates that a time limit was exceeded while
+   * attempting to process the request.
+   */
+  public static final ResultCode TIME_LIMIT_EXCEEDED = registerErrorResultCode(
+      3, INFO_RESULT_TIME_LIMIT_EXCEEDED.get());
+
+  /**
+   * The result code that indicates that a size limit was exceeded while
+   * attempting to process the request.
+   */
+  public static final ResultCode SIZE_LIMIT_EXCEEDED = registerErrorResultCode(
+      4, INFO_RESULT_SIZE_LIMIT_EXCEEDED.get());
+
+  /**
+   * The result code that indicates that the attribute value assertion included
+   * in a compare request did not match the targeted entry.
+   */
+  public static final ResultCode COMPARE_FALSE = registerSuccessResultCode(5,
+      INFO_RESULT_COMPARE_FALSE.get());
+
+  /**
+   * The result code that indicates that the attribute value assertion included
+   * in a compare request did match the targeted entry.
+   */
+  public static final ResultCode COMPARE_TRUE = registerSuccessResultCode(6,
+      INFO_RESULT_COMPARE_TRUE.get());
+
+  /**
+   * The result code that indicates that the requested authentication attempt
+   * failed because it referenced an invalid SASL mechanism.
+   */
+  public static final ResultCode AUTH_METHOD_NOT_SUPPORTED = registerErrorResultCode(
+      7, INFO_RESULT_AUTH_METHOD_NOT_SUPPORTED.get());
+
+  /**
+   * The result code that indicates that the requested operation could not be
+   * processed because it requires that the client has completed a strong form
+   * of authentication.
+   */
+  public static final ResultCode STRONG_AUTH_REQUIRED = registerErrorResultCode(
+      8, INFO_RESULT_STRONG_AUTH_REQUIRED.get());
+
+  /**
+   * The result code that indicates that a referral was encountered.
+   * <p>
+   * Strictly speaking this result code should not be exceptional since it is
+   * considered as a "success" response. However, referrals should occur rarely
+   * in practice and, when they do occur, should not be ignored since the
+   * application may believe that a request has succeeded when, in fact, nothing
+   * was done.
+   */
+  public static final ResultCode REFERRAL = registerErrorResultCode(10,
+      INFO_RESULT_REFERRAL.get());
+
+  /**
+   * The result code that indicates that processing on the requested operation
+   * could not continue because an administrative limit was exceeded.
+   */
+  public static final ResultCode ADMIN_LIMIT_EXCEEDED = registerErrorResultCode(
+      11, INFO_RESULT_ADMIN_LIMIT_EXCEEDED.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it included a critical extension that is unsupported or inappropriate for
+   * that request.
+   */
+  public static final ResultCode UNAVAILABLE_CRITICAL_EXTENSION = registerErrorResultCode(
+      12, INFO_RESULT_UNAVAILABLE_CRITICAL_EXTENSION.get());
+
+  /**
+   * The result code that indicates that the requested operation could not be
+   * processed because it requires confidentiality for the communication between
+   * the client and the server.
+   */
+  public static final ResultCode CONFIDENTIALITY_REQUIRED = registerErrorResultCode(
+      13, INFO_RESULT_CONFIDENTIALITY_REQUIRED.get());
+
+  /**
+   * The result code that should be used for intermediate responses in
+   * multi-stage SASL bind operations.
+   */
+  public static final ResultCode SASL_BIND_IN_PROGRESS = registerSuccessResultCode(
+      14, INFO_RESULT_SASL_BIND_IN_PROGRESS.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it targeted an attribute or attribute value that did not exist in the
+   * specified entry.
+   */
+  public static final ResultCode NO_SUCH_ATTRIBUTE = registerErrorResultCode(
+      16, INFO_RESULT_NO_SUCH_ATTRIBUTE.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it referenced an attribute that is not defined in the server schema.
+   */
+  public static final ResultCode UNDEFINED_ATTRIBUTE_TYPE = registerErrorResultCode(
+      17, INFO_RESULT_UNDEFINED_ATTRIBUTE_TYPE.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it attempted to perform an inappropriate type of matching against an
+   * attribute.
+   */
+  public static final ResultCode INAPPROPRIATE_MATCHING = registerErrorResultCode(
+      18, INFO_RESULT_INAPPROPRIATE_MATCHING.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it would have violated some constraint defined in the server.
+   */
+  public static final ResultCode CONSTRAINT_VIOLATION = registerErrorResultCode(
+      19, INFO_RESULT_CONSTRAINT_VIOLATION.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it would have resulted in a conflict with an existing attribute or
+   * attribute value in the target entry.
+   */
+  public static final ResultCode ATTRIBUTE_OR_VALUE_EXISTS = registerErrorResultCode(
+      20, INFO_RESULT_ATTRIBUTE_OR_VALUE_EXISTS.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it violated the syntax for a specified attribute.
+   */
+  public static final ResultCode INVALID_ATTRIBUTE_SYNTAX = registerErrorResultCode(
+      21, INFO_RESULT_INVALID_ATTRIBUTE_SYNTAX.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it referenced an entry that does not exist.
+   */
+  public static final ResultCode NO_SUCH_OBJECT = registerErrorResultCode(32,
+      INFO_RESULT_NO_SUCH_OBJECT.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it attempted to perform an illegal operation on an alias.
+   */
+  public static final ResultCode ALIAS_PROBLEM = registerErrorResultCode(33,
+      INFO_RESULT_ALIAS_PROBLEM.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it would have resulted in an entry with an invalid or malformed DN.
+   */
+  public static final ResultCode INVALID_DN_SYNTAX = registerErrorResultCode(
+      34, INFO_RESULT_INVALID_DN_SYNTAX.get());
+
+  /**
+   * The result code that indicates that a problem was encountered while
+   * attempting to dereference an alias for a search operation.
+   */
+  public static final ResultCode ALIAS_DEREFERENCING_PROBLEM = registerErrorResultCode(
+      36, INFO_RESULT_ALIAS_DEREFERENCING_PROBLEM.get());
+
+  /**
+   * The result code that indicates that an authentication attempt failed
+   * because the requested type of authentication was not appropriate for the
+   * targeted entry.
+   */
+  public static final ResultCode INAPPROPRIATE_AUTHENTICATION = registerErrorResultCode(
+      48, INFO_RESULT_INAPPROPRIATE_AUTHENTICATION.get());
+
+  /**
+   * The result code that indicates that an authentication attempt failed
+   * because the user did not provide a valid set of credentials.
+   */
+  public static final ResultCode INVALID_CREDENTIALS = registerErrorResultCode(
+      49, INFO_RESULT_INVALID_CREDENTIALS.get());
+
+  /**
+   * The result code that indicates that the client does not have sufficient
+   * permission to perform the requested operation.
+   */
+  public static final ResultCode INSUFFICIENT_ACCESS_RIGHTS = registerErrorResultCode(
+      50, INFO_RESULT_INSUFFICIENT_ACCESS_RIGHTS.get());
+
+  /**
+   * The result code that indicates that the server is too busy to process the
+   * requested operation.
+   */
+  public static final ResultCode BUSY = registerErrorResultCode(51,
+      INFO_RESULT_BUSY.get());
+
+  /**
+   * The result code that indicates that either the entire server or one or more
+   * required resources were not available for use in processing the request.
+   */
+  public static final ResultCode UNAVAILABLE = registerErrorResultCode(52,
+      INFO_RESULT_UNAVAILABLE.get());
+
+  /**
+   * The result code that indicates that the server is unwilling to perform the
+   * requested operation.
+   */
+  public static final ResultCode UNWILLING_TO_PERFORM = registerErrorResultCode(
+      53, INFO_RESULT_UNWILLING_TO_PERFORM.get());
+
+  /**
+   * The result code that indicates that a referral or chaining loop was
+   * detected while processing the request.
+   */
+  public static final ResultCode LOOP_DETECT = registerErrorResultCode(54,
+      INFO_RESULT_LOOP_DETECT.get());
+
+  /**
+   * The result code that indicates that a search request included a VLV request
+   * control without a server-side sort control.
+   */
+  public static final ResultCode SORT_CONTROL_MISSING = registerErrorResultCode(
+      60, INFO_RESULT_SORT_CONTROL_MISSING.get());
+
+  /**
+   * The result code that indicates that a search request included a VLV request
+   * control with an invalid offset.
+   */
+  public static final ResultCode OFFSET_RANGE_ERROR = registerErrorResultCode(
+      61, INFO_RESULT_OFFSET_RANGE_ERROR.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it would have violated the server's naming configuration.
+   */
+  public static final ResultCode NAMING_VIOLATION = registerErrorResultCode(64,
+      INFO_RESULT_NAMING_VIOLATION.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it would have resulted in an entry that violated the server schema.
+   */
+  public static final ResultCode OBJECTCLASS_VIOLATION = registerErrorResultCode(
+      65, INFO_RESULT_OBJECTCLASS_VIOLATION.get());
+
+  /**
+   * The result code that indicates that the requested operation is not allowed
+   * for non-leaf entries.
+   */
+  public static final ResultCode NOT_ALLOWED_ON_NONLEAF = registerErrorResultCode(
+      66, INFO_RESULT_NOT_ALLOWED_ON_NONLEAF.get());
+
+  /**
+   * The result code that indicates that the requested operation is not allowed
+   * on an RDN attribute.
+   */
+  public static final ResultCode NOT_ALLOWED_ON_RDN = registerErrorResultCode(
+      67, INFO_RESULT_NOT_ALLOWED_ON_RDN.get());
+
+  /**
+   * The result code that indicates that the requested operation failed because
+   * it would have resulted in an entry that conflicts with an entry that
+   * already exists.
+   */
+  public static final ResultCode ENTRY_ALREADY_EXISTS = registerErrorResultCode(
+      68, INFO_RESULT_ENTRY_ALREADY_EXISTS.get());
+
+  /**
+   * The result code that indicates that the operation could not be processed
+   * because it would have modified the objectclasses associated with an entry
+   * in an illegal manner.
+   */
+  public static final ResultCode OBJECTCLASS_MODS_PROHIBITED = registerErrorResultCode(
+      69, INFO_RESULT_OBJECTCLASS_MODS_PROHIBITED.get());
+
+  /**
+   * The result code that indicates that the operation could not be processed
+   * because it would impact multiple DSAs or other repositories.
+   */
+  public static final ResultCode AFFECTS_MULTIPLE_DSAS = registerErrorResultCode(
+      71, INFO_RESULT_AFFECTS_MULTIPLE_DSAS.get());
+
+  /**
+   * The result code that indicates that the operation could not be processed
+   * because there was an error while processing the virtual list view control.
+   */
+  public static final ResultCode VIRTUAL_LIST_VIEW_ERROR = registerErrorResultCode(
+      76, INFO_RESULT_VIRTUAL_LIST_VIEW_ERROR.get());
+
+  /**
+   * The result code that should be used if no other result code is appropriate.
+   */
+  public static final ResultCode OTHER = registerErrorResultCode(80,
+      INFO_RESULT_OTHER.get());
+
+  /**
+   * The client-side result code that indicates that a previously-established
+   * connection to the server was lost. This is for client-side use only and
+   * should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_SERVER_DOWN = registerErrorResultCode(
+      81, INFO_RESULT_CLIENT_SIDE_SERVER_DOWN.get());
+
+  /**
+   * The client-side result code that indicates that a local error occurred that
+   * had nothing to do with interaction with the server. This is for client-side
+   * use only and should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_LOCAL_ERROR = registerErrorResultCode(
+      82, INFO_RESULT_CLIENT_SIDE_LOCAL_ERROR.get());
+
+  /**
+   * The client-side result code that indicates that an error occurred while
+   * encoding a request to send to the server. This is for client-side use only
+   * and should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_ENCODING_ERROR = registerErrorResultCode(
+      83, INFO_RESULT_CLIENT_SIDE_ENCODING_ERROR.get());
+
+  /**
+   * The client-side result code that indicates that an error occurred while
+   * decoding a response from the server. This is for client-side use only and
+   * should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_DECODING_ERROR = registerErrorResultCode(
+      84, INFO_RESULT_CLIENT_SIDE_DECODING_ERROR.get());
+
+  /**
+   * The client-side result code that indicates that the client did not receive
+   * an expected response in a timely manner. This is for client-side use only
+   * and should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_TIMEOUT = registerErrorResultCode(
+      85, INFO_RESULT_CLIENT_SIDE_TIMEOUT.get());
+
+  /**
+   * The client-side result code that indicates that the user requested an
+   * unknown or unsupported authentication mechanism. This is for client-side
+   * use only and should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_AUTH_UNKNOWN = registerErrorResultCode(
+      86, INFO_RESULT_CLIENT_SIDE_AUTH_UNKNOWN.get());
+
+  /**
+   * The client-side result code that indicates that the filter provided by the
+   * user was malformed and could not be parsed. This is for client-side use
+   * only and should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_FILTER_ERROR = registerErrorResultCode(
+      87, INFO_RESULT_CLIENT_SIDE_FILTER_ERROR.get());
+
+  /**
+   * The client-side result code that indicates that the user cancelled an
+   * operation. This is for client-side use only and should never be transferred
+   * over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_USER_CANCELLED = registerErrorResultCode(
+      88, INFO_RESULT_CLIENT_SIDE_USER_CANCELLED.get());
+
+  /**
+   * The client-side result code that indicates that there was a problem with
+   * one or more of the parameters provided by the user. This is for client-side
+   * use only and should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_PARAM_ERROR = registerErrorResultCode(
+      89, INFO_RESULT_CLIENT_SIDE_PARAM_ERROR.get());
+
+  /**
+   * The client-side result code that indicates that the client application was
+   * not able to allocate enough memory for the requested operation. This is for
+   * client-side use only and should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_NO_MEMORY = registerErrorResultCode(
+      90, INFO_RESULT_CLIENT_SIDE_NO_MEMORY.get());
+
+  /**
+   * The client-side result code that indicates that the client was not able to
+   * establish a connection to the server. This is for client-side use only and
+   * should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_CONNECT_ERROR = registerErrorResultCode(
+      91, INFO_RESULT_CLIENT_SIDE_CONNECT_ERROR.get());
+
+  /**
+   * The client-side result code that indicates that the user requested an
+   * operation that is not supported. This is for client-side use only and
+   * should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_NOT_SUPPORTED = registerErrorResultCode(
+      92, INFO_RESULT_CLIENT_SIDE_NOT_SUPPORTED.get());
+
+  /**
+   * The client-side result code that indicates that the client expected a
+   * control to be present in the response from the server but it was not
+   * included. This is for client-side use only and should never be transferred
+   * over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_CONTROL_NOT_FOUND = registerErrorResultCode(
+      93, INFO_RESULT_CLIENT_SIDE_CONTROL_NOT_FOUND.get());
+
+  /**
+   * The client-side result code that indicates that the requested single entry
+   * search operation or read operation failed because the Directory Server did
+   * not return any matching entries. This is for client-side use only and
+   * should never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_NO_RESULTS_RETURNED = registerErrorResultCode(
+      94, INFO_RESULT_CLIENT_SIDE_NO_RESULTS_RETURNED.get());
+
+  /**
+   * The client-side result code that the requested single entry search
+   * operation or read operation failed because the Directory Server returned
+   * multiple matching entries (or search references) when only a single
+   * matching entry was expected. This is for client-side use only and should
+   * never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED = registerErrorResultCode(
+      95, INFO_RESULT_CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED.get());
+
+  /**
+   * The client-side result code that indicates that the client detected a
+   * referral loop caused by servers referencing each other in a circular
+   * manner. This is for client-side use only and should never be transferred
+   * over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_CLIENT_LOOP = registerErrorResultCode(
+      96, INFO_RESULT_CLIENT_SIDE_CLIENT_LOOP.get());
+
+  /**
+   * The client-side result code that indicates that the client reached the
+   * maximum number of hops allowed when attempting to follow a referral (i.e.,
+   * following one referral resulted in another referral which resulted in
+   * another referral and so on). This is for client-side use only and should
+   * never be transferred over protocol.
+   */
+  public static final ResultCode CLIENT_SIDE_REFERRAL_LIMIT_EXCEEDED = registerErrorResultCode(
+      97, INFO_RESULT_CLIENT_SIDE_REFERRAL_LIMIT_EXCEEDED.get());
+
+  /**
+   * The result code that indicates that a cancel request was successful, or
+   * that the specified operation was canceled.
+   */
+  public static final ResultCode CANCELLED = registerErrorResultCode(118,
+      INFO_RESULT_CANCELED.get());
+
+  /**
+   * The result code that indicates that a cancel request was unsuccessful
+   * because the targeted operation did not exist or had already completed.
+   */
+  public static final ResultCode NO_SUCH_OPERATION = registerErrorResultCode(
+      119, INFO_RESULT_NO_SUCH_OPERATION.get());
+
+  /**
+   * The result code that indicates that a cancel request was unsuccessful
+   * because processing on the targeted operation had already reached a point at
+   * which it could not be canceled.
+   */
+  public static final ResultCode TOO_LATE = registerErrorResultCode(120,
+      INFO_RESULT_TOO_LATE.get());
+
+  /**
+   * The result code that indicates that a cancel request was unsuccessful
+   * because the targeted operation was one that could not be canceled.
+   */
+  public static final ResultCode CANNOT_CANCEL = registerErrorResultCode(121,
+      INFO_RESULT_CANNOT_CANCEL.get());
+
+  /**
+   * The result code that indicates that the filter contained in an assertion
+   * control failed to match the target entry.
+   */
+  public static final ResultCode ASSERTION_FAILED = registerErrorResultCode(
+      122, INFO_RESULT_ASSERTION_FAILED.get());
+
+  /**
+   * The result code that should be used if the server will not allow the client
+   * to use the requested authorization.
+   */
+  public static final ResultCode AUTHORIZATION_DENIED = registerErrorResultCode(
+      123, INFO_RESULT_AUTHORIZATION_DENIED.get());
+
+  /**
+   * The result code that should be used if the server did not actually complete
+   * processing on the associated operation because the request included the
+   * LDAP No-Op control.
+   */
+  public static final ResultCode NO_OPERATION = registerErrorResultCode(16654,
+      INFO_RESULT_NO_OPERATION.get());
+
+
+
+  /**
+   * Returns the result code having the specified integer value as defined in
+   * RFC 4511 section 4.1.9. If there is no result code associated with the
+   * specified integer value then a temporary result code is automatically
+   * created in order to handle cases where unexpected result codes are returned
+   * from the server.
+   *
+   * @param intValue
+   *          The integer value of the result code.
+   * @return The result code.
+   */
+  public static ResultCode valueOf(final int intValue)
+  {
+    ResultCode resultCode = null;
+
+    if (intValue >= 0 || intValue < ELEMENTS.length)
+    {
+      resultCode = ELEMENTS[intValue];
+    }
+
+    if (resultCode == null)
+    {
+      resultCode = new ResultCode(intValue, LocalizableMessage.raw("undefined("
+          + intValue + ")"), true);
+    }
+
+    return resultCode;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the set of available result codes
+   * indexed on their integer value as defined in RFC 4511 section 4.1.9.
+   *
+   * @return An unmodifiable list containing the set of available result codes.
+   */
+  public static List<ResultCode> values()
+  {
+    return IMMUTABLE_ELEMENTS;
+  }
+
+
+
+  /**
+   * Creates and registers a new error result code with the application.
+   *
+   * @param intValue
+   *          The integer value of the error result code as defined in RFC 4511
+   *          section 4.1.9.
+   * @param name
+   *          The name of the error result code.
+   * @return The new error result code.
+   */
+  private static ResultCode registerErrorResultCode(final int intValue,
+      final LocalizableMessage name)
+  {
+    final ResultCode t = new ResultCode(intValue, name, true);
+    ELEMENTS[intValue] = t;
+    return t;
+  }
+
+
+
+  /**
+   * Creates and registers a new success result code with the application.
+   *
+   * @param intValue
+   *          The integer value of the success result code as defined in RFC
+   *          4511 section 4.1.9.
+   * @param name
+   *          The name of the success result code.
+   * @return The new success result code.
+   */
+  private static ResultCode registerSuccessResultCode(final int intValue,
+      final LocalizableMessage name)
+  {
+    final ResultCode t = new ResultCode(intValue, name, false);
+    ELEMENTS[intValue] = t;
+    return t;
+  }
+
+
+
+  private final int intValue;
+
+  private final LocalizableMessage name;
+
+  private final boolean exceptional;
+
+
+
+  // Prevent direct instantiation.
+  private ResultCode(final int intValue, final LocalizableMessage name,
+      final boolean exceptional)
+  {
+    this.intValue = intValue;
+    this.name = name;
+    this.exceptional = exceptional;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    else if (obj instanceof ResultCode)
+    {
+      return this.intValue == ((ResultCode) obj).intValue;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Returns the short human-readable name of this result code.
+   *
+   * @return The short human-readable name of this result code.
+   */
+  public LocalizableMessage getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Returns the integer value of this result code.
+   *
+   * @return The integer value of this result code.
+   */
+  public int intValue()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Indicates whether or not this result code represents an error result. In
+   * order to make it easier for application to detect referrals, the {@code
+   * REFERRAL} result code is treated as an error result (the LDAP RFCs treat
+   * referrals as a success response).
+   *
+   * @return {@code true} if this result code represents an error result,
+   *         otherwise {@code false}.
+   */
+  public boolean isExceptional()
+  {
+    return exceptional;
+  }
+
+
+
+  /**
+   * Returns the string representation of this result code.
+   *
+   * @return The string representation of this result code.
+   */
+  @Override
+  public String toString()
+  {
+    return name.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultHandler.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultHandler.java
new file mode 100644
index 0000000..62f3b89
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ResultHandler.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * A completion handler for consuming the result of an asynchronous operation or
+ * connection attempts.
+ * <p>
+ * A result completion handler may be specified when performing asynchronous
+ * operations using an {@link AsynchronousConnection} object or when connecting
+ * asynchronously to a remote Directory Server using an
+ * {@link ConnectionFactory}. The {@link #handleResult} method is invoked when
+ * the operation or connection attempt completes successfully. The
+ * {@link #handleErrorResult} method is invoked if the operation or connection
+ * attempt fails.
+ * <p>
+ * Implementations of these methods should complete in a timely manner so as to
+ * avoid keeping the invoking thread from dispatching to other completion
+ * handlers.
+ *
+ * @param <S>
+ *          The type of result handled by this result handler.
+ */
+public interface ResultHandler<S>
+{
+  /**
+   * Invoked when the asynchronous operation has failed.
+   *
+   * @param error
+   *          The error result exception indicating why the asynchronous
+   *          operation has failed.
+   */
+  void handleErrorResult(ErrorResultException error);
+
+
+
+  /**
+   * Invoked when the asynchronous operation has completed successfully.
+   *
+   * @param result
+   *          The result of the asynchronous operation.
+   */
+  void handleResult(S result);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RootDSE.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RootDSE.java
new file mode 100644
index 0000000..f06a1da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RootDSE.java
@@ -0,0 +1,510 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.schema.CoreSchema;
+
+import com.sun.opends.sdk.util.*;
+
+
+
+/**
+ * The root DSE is a DSA-specific Entry (DSE) and not part of any naming context
+ * (or any subtree), and which is uniquely identified by the empty DN.
+ * <p>
+ * A Directory Server uses the root DSE to provide information about itself
+ * using the following set of attributes:
+ * <ul>
+ * <li>{@code altServer}: alternative Directory Servers
+ * <li>{@code namingContexts}: naming contexts
+ * <li>{@code supportedControl}: recognized LDAP controls
+ * <li>{@code supportedExtension}: recognized LDAP extended operations
+ * <li>{@code supportedFeatures}: recognized LDAP features
+ * <li>{@code supportedLDAPVersion}: LDAP versions supported
+ * <li>{@code supportedSASLMechanisms}: recognized SASL authentication
+ * mechanisms
+ * <li>{@code supportedAuthPasswordSchemes}: recognized authentication password
+ * schemes
+ * <li>{@code subschemaSubentry}: the name of the subschema subentry holding the
+ * schema controlling the Root DSE
+ * <li>{@code vendorName}: the name of the Directory Server implementer
+ * <li>{@code vendorVersion}: the version of the Directory Server
+ * implementation.
+ * </ul>
+ * The values provided for these attributes may depend on session- specific and
+ * other factors. For example, a server supporting the SASL EXTERNAL mechanism
+ * might only list "EXTERNAL" when the client's identity has been established by
+ * a lower level.
+ * <p>
+ * The root DSE may also include a {@code subschemaSubentry} attribute. If it
+ * does, the attribute refers to the subschema (sub)entry holding the schema
+ * controlling the root DSE. Clients SHOULD NOT assume that this subschema
+ * (sub)entry controls other entries held by the server.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
+ *      Directory Access Protocol (LDAP): Directory Information Models </a>
+ * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 - Storing Vendor
+ *      Information in the LDAP Root DSE </a>
+ * @see <a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
+ *      Authentication Password Schema </a>
+ */
+public final class RootDSE
+{
+  private static final AttributeDescription ATTR_ALT_SERVER =
+    AttributeDescription.create(CoreSchema.getAltServerAttributeType());
+
+  private static final AttributeDescription ATTR_NAMING_CONTEXTS =
+    AttributeDescription.create(CoreSchema.getNamingContextsAttributeType());
+
+  private static final AttributeDescription ATTR_SUBSCHEMA_SUBENTRY =
+    AttributeDescription.create(CoreSchema.getSubschemaSubentryAttributeType());
+
+  private static final AttributeDescription ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES =
+    AttributeDescription.create(
+        CoreSchema.getSupportedAuthPasswordSchemesAttributeType());
+
+  private static final AttributeDescription ATTR_SUPPORTED_CONTROL =
+    AttributeDescription.create(CoreSchema.getSupportedControlAttributeType());
+
+  private static final AttributeDescription ATTR_SUPPORTED_EXTENSION =
+    AttributeDescription.create(
+        CoreSchema.getSupportedExtensionAttributeType());
+
+  private static final AttributeDescription ATTR_SUPPORTED_FEATURE =
+    AttributeDescription.create(CoreSchema.getSupportedFeaturesAttributeType());
+
+  private static final AttributeDescription ATTR_SUPPORTED_LDAP_VERSION =
+    AttributeDescription.create(
+        CoreSchema.getSupportedLDAPVersionAttributeType());
+
+  private static final AttributeDescription ATTR_SUPPORTED_SASL_MECHANISMS =
+    AttributeDescription.create(
+        CoreSchema.getSupportedSASLMechanismsAttributeType());
+
+  private static final AttributeDescription ATTR_VENDOR_NAME =
+    AttributeDescription.create(CoreSchema.getVendorNameAttributeType());
+
+  private static final AttributeDescription ATTR_VENDOR_VERSION =
+    AttributeDescription.create(CoreSchema.getVendorNameAttributeType());
+
+  private static final SearchRequest SEARCH_REQUEST = Requests
+      .newSearchRequest(DN.rootDN(), SearchScope.BASE_OBJECT, Filter
+          .getObjectClassPresentFilter(), ATTR_ALT_SERVER.toString(),
+          ATTR_NAMING_CONTEXTS.toString(), ATTR_SUPPORTED_CONTROL.toString(),
+          ATTR_SUPPORTED_EXTENSION.toString(), ATTR_SUPPORTED_FEATURE
+              .toString(), ATTR_SUPPORTED_LDAP_VERSION.toString(),
+          ATTR_SUPPORTED_SASL_MECHANISMS.toString(), ATTR_VENDOR_NAME
+              .toString(), ATTR_VENDOR_VERSION.toString(),
+          ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES.toString(),
+          ATTR_SUBSCHEMA_SUBENTRY.toString(), "*");
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server using the provided connection.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the request
+   * will fail with an {@link EntryNotFoundException}. More specifically, the
+   * returned future will never return {@code null}.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose Root DSE is to be read.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} was {@code null}.
+   */
+  public static FutureResult<RootDSE> readRootDSE(
+      final AsynchronousConnection connection,
+      final ResultHandler<? super RootDSE> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final FutureResultTransformer<SearchResultEntry, RootDSE> future =
+      new FutureResultTransformer<SearchResultEntry, RootDSE>(handler)
+    {
+
+      @Override
+      protected RootDSE transformResult(final SearchResultEntry result)
+          throws ErrorResultException
+      {
+        return new RootDSE(result);
+      }
+
+    };
+
+    final FutureResult<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(SEARCH_REQUEST, future);
+    future.setFutureResult(innerFuture);
+    return future;
+  }
+
+
+
+  /**
+   * Reads the Root DSE from the Directory Server using the provided connection.
+   * <p>
+   * If the Root DSE is not returned by the Directory Server then the request
+   * will fail with an {@link EntryNotFoundException}. More specifically, this
+   * method will never return {@code null}.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose Root DSE is to be read.
+   * @return The Directory Server's Root DSE.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} was {@code null}.
+   */
+  public static RootDSE readRootDSE(final Connection connection)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final Entry entry = connection.searchSingleEntry(SEARCH_REQUEST);
+    return new RootDSE(entry);
+  }
+
+
+
+  private final Entry entry;
+
+
+
+  /**
+   * Creates a new Root DSE instance backed by the provided entry. Modifications
+   * made to {@code entry} will be reflected in the returned Root DSE. The
+   * returned Root DSE instance is unmodifiable and attempts to use modify any
+   * of the returned collections will result in a {@code
+   * UnsupportedOperationException}.
+   *
+   * @param entry
+   *          The Root DSE entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  public RootDSE(final Entry entry) throws NullPointerException
+  {
+    Validator.ensureNotNull(entry);
+    this.entry = entry;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of URIs referring to alternative Directory
+   * Servers that may be contacted when the Directory Server becomes
+   * unavailable.
+   * <p>
+   * URIs for Directory Servers implementing the LDAP protocol are written
+   * according to RFC 4516. Other kinds of URIs may be provided.
+   * <p>
+   * If the Directory Server does not know of any other Directory Servers that
+   * could be used, the returned list will be empty.
+   *
+   * @return An unmodifiable list of URIs referring to alternative Directory
+   *         Servers, which may be empty.
+   * @see <a href="http://tools.ietf.org/html/rfc4516">RFC 4516 - Lightweight
+   *      Directory Access Protocol (LDAP): Uniform Resource Locator </a>
+   */
+  public Collection<String> getAlternativeServers()
+  {
+    return getMultiValuedAttribute(ATTR_ALT_SERVER, Functions.valueToString());
+  }
+
+
+
+  /**
+   * Returns the entry which backs this Root DSE instance. Modifications made to
+   * the returned entry will be reflected in this Root DSE.
+   *
+   * @return The underlying Root DSE entry.
+   */
+  public Entry getEntry()
+  {
+    return entry;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of DNs identifying the context prefixes of the
+   * naming contexts that the Directory Server masters or shadows (in part or in
+   * whole).
+   * <p>
+   * If the Directory Server does not master or shadow any naming contexts, the
+   * returned list will be empty.
+   *
+   * @return An unmodifiable list of DNs identifying the context prefixes of the
+   *         naming contexts, which may be empty.
+   */
+  public Collection<DN> getNamingContexts()
+  {
+    return getMultiValuedAttribute(ATTR_NAMING_CONTEXTS, Functions.valueToDN());
+  }
+
+
+
+  /**
+   * Returns a string which represents the DN of the subschema subentry holding
+   * the schema controlling the Root DSE.
+   * <p>
+   * Clients SHOULD NOT assume that this subschema (sub)entry controls other
+   * entries held by the Directory Server.
+   *
+   * @return The DN of the subschema subentry holding the schema controlling the
+   *         Root DSE, or {@code null} if the DN is not provided.
+   */
+  public DN getSubschemaSubentry()
+  {
+    return getSingleValuedAttribute(ATTR_SUBSCHEMA_SUBENTRY, Functions
+        .valueToDN());
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of supported authentication password schemes
+   * which the Directory Server supports.
+   * <p>
+   * If the Directory Server does not support any authentication password
+   * schemes, the returned list will be empty.
+   *
+   * @return An unmodifiable list of supported authentication password schemes,
+   *         which may be empty.
+   * @see <a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
+   *      Authentication Password Schema </a>
+   */
+  public Collection<String> getSupportedAuthenticationPasswordSchemes()
+  {
+    return getMultiValuedAttribute(ATTR_SUPPORTED_AUTH_PASSWORD_SCHEMES,
+        Functions.valueToString());
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of object identifiers identifying the request
+   * controls that the Directory Server supports.
+   * <p>
+   * If the Directory Server does not support any request controls, the returned
+   * list will be empty. Object identifiers identifying response controls may
+   * not be listed.
+   *
+   * @return An unmodifiable list of object identifiers identifying the request
+   *         controls, which may be empty.
+   */
+  public Collection<String> getSupportedControls()
+  {
+    return getMultiValuedAttribute(ATTR_SUPPORTED_CONTROL, Functions
+        .valueToString());
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of object identifiers identifying the extended
+   * operations that the Directory Server supports.
+   * <p>
+   * If the Directory Server does not support any extended operations, the
+   * returned list will be empty.
+   * <p>
+   * An extended operation generally consists of an extended request and an
+   * extended response but may also include other protocol data units (such as
+   * intermediate responses). The object identifier assigned to the extended
+   * request is used to identify the extended operation. Other object
+   * identifiers used in the extended operation may not be listed as values of
+   * this attribute.
+   *
+   * @return An unmodifiable list of object identifiers identifying the extended
+   *         operations, which may be empty.
+   */
+  public Collection<String> getSupportedExtendedOperations()
+  {
+    return getMultiValuedAttribute(ATTR_SUPPORTED_EXTENSION, Functions
+        .valueToString());
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of object identifiers identifying elective
+   * features that the Directory Server supports.
+   * <p>
+   * If the server does not support any discoverable elective features, the
+   * returned list will be empty.
+   *
+   * @return An unmodifiable list of object identifiers identifying the elective
+   *         features, which may be empty.
+   */
+  public Collection<String> getSupportedFeatures()
+  {
+    return getMultiValuedAttribute(ATTR_SUPPORTED_FEATURE, Functions
+        .valueToString());
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of the versions of LDAP that the Directory
+   * Server supports.
+   *
+   * @return An unmodifiable list of the versions.
+   */
+  public Collection<Integer> getSupportedLDAPVersions()
+  {
+    return getMultiValuedAttribute(ATTR_SUPPORTED_LDAP_VERSION, Functions
+        .valueToInteger());
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of the SASL mechanisms that the Directory
+   * Server recognizes and/or supports.
+   * <p>
+   * The contents of the returned list may depend on the current session state
+   * and may be empty if the Directory Server does not support any SASL
+   * mechanisms.
+   *
+   * @return An unmodifiable list of the SASL mechanisms, which may be empty.
+   * @see <a href="http://tools.ietf.org/html/rfc4513">RFC 4513 - Lightweight
+   *      Directory Access Protocol (LDAP): Authentication Methods and Security
+   *      Mechanisms </a>
+   * @see <a href="http://tools.ietf.org/html/rfc4422">RFC 4422 - Simple
+   *      Authentication and Security Layer (SASL) </a>
+   */
+  public Collection<String> getSupportedSASLMechanisms()
+  {
+    return getMultiValuedAttribute(ATTR_SUPPORTED_SASL_MECHANISMS, Functions
+        .valueToString());
+  }
+
+
+
+  /**
+   * Returns a string which represents the name of the Directory Server
+   * implementer.
+   *
+   * @return The name of the Directory Server implementer, or {@code null} if
+   *         the vendor name is not provided.
+   * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 - Storing Vendor
+   *      Information in the LDAP Root DSE </a>
+   */
+  public String getVendorName()
+  {
+    return getSingleValuedAttribute(ATTR_VENDOR_NAME, Functions.valueToString());
+  }
+
+
+
+  /**
+   * Returns a string which represents the version of the Directory Server
+   * implementation.
+   * <p>
+   * Note that this value is typically a release value comprised of a string
+   * and/or a string of numbers used by the developer of the LDAP server
+   * product. The returned string will be unique between two versions of the
+   * Directory Server, but there are no other syntactic restrictions on the
+   * value or the way it is formatted.
+   *
+   * @return The version of the Directory Server implementation, or {@code null}
+   *         if the vendor version is not provided.
+   * @see <a href="http://tools.ietf.org/html/rfc3045">RFC 3045 - Storing Vendor
+   *      Information in the LDAP Root DSE </a>
+   */
+  public String getVendorVersion()
+  {
+    return getSingleValuedAttribute(ATTR_VENDOR_VERSION, Functions
+        .valueToString());
+  }
+
+
+
+  private <N> Collection<N> getMultiValuedAttribute(
+      final AttributeDescription attributeDescription,
+      final Function<ByteString, N, Void> function)
+  {
+    // The returned collection is unmodifiable because we may need to
+    // return an empty collection if the attribute does not exist in the
+    // underlying entry. If a value is then added to the returned empty
+    // collection it would require that an attribute is created in the
+    // underlying entry in order to maintain consistency.
+    final Attribute attr = entry.getAttribute(attributeDescription);
+    if (attr != null)
+    {
+      return Collections.unmodifiableCollection(Collections2.transformedCollection(attr,
+          function, Functions.objectToByteString()));
+    }
+    else
+    {
+      return Collections.emptySet();
+    }
+  }
+
+
+
+  private <N> N getSingleValuedAttribute(
+      final AttributeDescription attributeDescription,
+      final Function<ByteString, N, Void> function)
+  {
+    final Attribute attr = entry.getAttribute(attributeDescription);
+    if (attr == null || attr.isEmpty())
+    {
+      return null;
+    }
+    else
+    {
+      return function.apply(attr.firstValue(), null);
+    }
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RoundRobinLoadBalancingAlgorithm.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RoundRobinLoadBalancingAlgorithm.java
new file mode 100644
index 0000000..24c8559
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/RoundRobinLoadBalancingAlgorithm.java
@@ -0,0 +1,178 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Collection;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+
+/**
+ * A round robin load balancing algorithm distributes connection requests across
+ * a list of connection factories one at a time. When the end of the list is
+ * reached, the algorithm starts again from the beginning.
+ * <p>
+ * This algorithm is typically used for load-balancing <i>within</i> data
+ * centers, where load must be distributed equally across multiple data sources.
+ * This algorithm contrasts with the {@link FailoverLoadBalancingAlgorithm}
+ * which is used for load-balancing <i>between</i> data centers.
+ * <p>
+ * If a problem occurs that temporarily prevents connections from being obtained
+ * for one of the connection factories, then this algorithm automatically
+ * "fails over" to the next operational connection factory in the list. If none
+ * of the connection factories are operational then a
+ * {@code ConnectionException} is returned to the client.
+ * <p>
+ * The implementation periodically attempts to connect to failed connection
+ * factories in order to determine if they have become available again.
+ *
+ * @see FailoverLoadBalancingAlgorithm
+ * @see Connections#newLoadBalancer(LoadBalancingAlgorithm)
+ */
+public final class RoundRobinLoadBalancingAlgorithm extends
+    AbstractLoadBalancingAlgorithm
+{
+  private final int maxIndex;
+
+  private final AtomicInteger nextIndex = new AtomicInteger(-1);
+
+
+
+  /**
+   * Creates a new round robin load balancing algorithm which will monitor
+   * offline connection factories every 1 second using the default scheduler.
+   *
+   * @param factories
+   *          The ordered collection of connection factories.
+   */
+  public RoundRobinLoadBalancingAlgorithm(
+      final Collection<ConnectionFactory> factories)
+  {
+    super(factories);
+    this.maxIndex = factories.size();
+  }
+
+
+
+  /**
+   * Creates a new round robin load balancing algorithm which will monitor
+   * offline connection factories using the specified frequency using the
+   * default scheduler.
+   *
+   * @param factories
+   *          The connection factories.
+   * @param interval
+   *          The interval between attempts to poll offline factories.
+   * @param unit
+   *          The time unit for the interval between attempts to poll offline
+   *          factories.
+   */
+  public RoundRobinLoadBalancingAlgorithm(
+      final Collection<ConnectionFactory> factories, final long interval,
+      final TimeUnit unit)
+  {
+    super(factories, interval, unit);
+    this.maxIndex = factories.size();
+  }
+
+
+
+  /**
+   * Creates a new round robin load balancing algorithm which will monitor
+   * offline connection factories using the specified frequency and scheduler.
+   *
+   * @param factories
+   *          The connection factories.
+   * @param interval
+   *          The interval between attempts to poll offline factories.
+   * @param unit
+   *          The time unit for the interval between attempts to poll offline
+   *          factories.
+   * @param scheduler
+   *          The scheduler which should for periodically monitoring dead
+   *          connection factories to see if they are usable again.
+   */
+  public RoundRobinLoadBalancingAlgorithm(
+      final Collection<ConnectionFactory> factories, final long interval,
+      final TimeUnit unit, final ScheduledExecutorService scheduler)
+  {
+    super(factories, interval, unit, scheduler);
+    this.maxIndex = factories.size();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  String getAlgorithmName()
+  {
+    return "RoundRobin";
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  int getInitialConnectionFactoryIndex()
+  {
+    // A round robin pool of one connection factories is unlikely in practice
+    // and requires special treatment.
+    if (maxIndex == 1)
+    {
+      return 0;
+    }
+
+    // Determine the next factory to use: avoid blocking algorithm.
+    int oldNextIndex;
+    int newNextIndex;
+    do
+    {
+      oldNextIndex = nextIndex.get();
+      newNextIndex = oldNextIndex + 1;
+      if (newNextIndex == maxIndex)
+      {
+        newNextIndex = 0;
+      }
+    }
+    while (!nextIndex.compareAndSet(oldNextIndex, newNextIndex));
+
+    // There's a potential, but benign, race condition here: other threads could
+    // jump in and rotate through the list before we return the connection
+    // factory.
+    return newNextIndex;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SSLContextBuilder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SSLContextBuilder.java
new file mode 100644
index 0000000..5db8f24
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SSLContextBuilder.java
@@ -0,0 +1,255 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+
+
+
+/**
+ * An SSL context builder provides an interface for incrementally constructing
+ * {@link SSLContext} instances for use when securing connections with SSL or
+ * the StartTLS extended operation. The {@link #getSSLContext()} should be
+ * called in order to obtain the {@code SSLContext}.
+ */
+public final class SSLContextBuilder
+{
+
+  /**
+   * SSL protocol: supports some version of SSL; may support other versions.
+   */
+  public static final String PROTOCOL_SSL = "SSL";
+
+  /**
+   * SSL protocol: supports SSL version 2 or higher; may support other versions.
+   */
+  public static final String PROTOCOL_SSL2 = "SSLv2";
+
+  /**
+   * SSL protocol: supports SSL version 3; may support other versions.
+   */
+  public static final String PROTOCOL_SSL3 = "SSLv3";
+
+  /**
+   * SSL protocol: supports some version of TLS; may support other versions.
+   */
+  public static final String PROTOCOL_TLS = "TLS";
+
+  /**
+   * SSL protocol: supports RFC 2246: TLS version 1.0 ; may support other
+   * versions.
+   */
+  public static final String PROTOCOL_TLS1 = "TLSv1";
+
+  /**
+   * SSL protocol: supports RFC 4346: TLS version 1.1 ; may support other
+   * versions.
+   */
+  public static final String PROTOCOL_TLS1_1 = "TLSv1.1";
+
+  private TrustManager trustManager = null;
+  private KeyManager keyManager = null;
+  private String protocol = PROTOCOL_TLS1;
+  private SecureRandom random = null;
+
+  // These are mutually exclusive.
+  private Provider provider = null;
+  private String providerName = null;
+
+
+
+  /**
+   * Creates a new SSL context builder using default parameters.
+   */
+  public SSLContextBuilder()
+  {
+    // Do nothing.
+  }
+
+
+
+  /**
+   * Creates a {@code SSLContext} using the parameters of this SSL context
+   * builder.
+   *
+   * @return A {@code SSLContext} using the parameters of this SSL context
+   *         builder.
+   * @throws GeneralSecurityException
+   *           If the SSL context could not be created, perhaps due to missing
+   *           algorithms.
+   */
+  public SSLContext getSSLContext() throws GeneralSecurityException
+  {
+    TrustManager[] tm = null;
+    if (trustManager != null)
+    {
+      tm = new TrustManager[] { trustManager };
+    }
+
+    KeyManager[] km = null;
+    if (keyManager != null)
+    {
+      km = new KeyManager[] { keyManager };
+    }
+
+    SSLContext sslContext;
+    if (provider != null)
+    {
+      sslContext = SSLContext.getInstance(protocol, provider);
+    }
+    else if (providerName != null)
+    {
+      sslContext = SSLContext.getInstance(protocol, providerName);
+    }
+    else
+    {
+      sslContext = SSLContext.getInstance(protocol);
+    }
+    sslContext.init(km, tm, random);
+
+    return sslContext;
+  }
+
+
+
+  /**
+   * Sets the key manager which the SSL context should use. By default, no key
+   * manager is specified indicating that no certificates will be used.
+   *
+   * @param keyManager
+   *          The key manager which the SSL context should use, which may be
+   *          {@code null} indicating that no certificates will be used.
+   * @return This SSL context builder.
+   */
+  public SSLContextBuilder setKeyManager(final KeyManager keyManager)
+  {
+    this.keyManager = keyManager;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the protocol which the SSL context should use. By default, TLSv1 will
+   * be used.
+   *
+   * @param protocol
+   *          The protocol which the SSL context should use, which may be
+   *          {@code null} indicating that TLSv1 will be used.
+   * @return This SSL context builder.
+   */
+  public SSLContextBuilder setProtocol(final String protocol)
+  {
+    this.protocol = protocol;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the provider which the SSL context should use. By default, the default
+   * provider associated with this JVM will be used.
+   *
+   * @param provider
+   *          The provider which the SSL context should use, which may be
+   *          {@code null} indicating that the default provider associated with
+   *          this JVM will be used.
+   * @return This SSL context builder.
+   */
+  public SSLContextBuilder setProvider(final Provider provider)
+  {
+    this.provider = provider;
+    this.providerName = null;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the provider which the SSL context should use. By default, the default
+   * provider associated with this JVM will be used.
+   *
+   * @param providerName
+   *          The name of the provider which the SSL context should use, which
+   *          may be {@code null} indicating that the default provider
+   *          associated with this JVM will be used.
+   * @return This SSL context builder.
+   */
+  public SSLContextBuilder setProvider(final String providerName)
+  {
+    this.provider = null;
+    this.providerName = providerName;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the secure random number generator which the SSL context should use.
+   * By default, the default secure random number generator associated with this
+   * JVM will be used.
+   *
+   * @param random
+   *          The secure random number generator which the SSL context should
+   *          use, which may be {@code null} indicating that the default secure
+   *          random number generator associated with this JVM will be used.
+   * @return This SSL context builder.
+   */
+  public SSLContextBuilder setSecureRandom(final SecureRandom random)
+  {
+    this.random = random;
+    return this;
+  }
+
+
+
+  /**
+   * Sets the trust manager which the SSL context should use. By default, no
+   * trust manager is specified indicating that only certificates signed by the
+   * authorities associated with this JVM will be accepted.
+   *
+   * @param trustManager
+   *          The trust manager which the SSL context should use, which may be
+   *          {@code null} indicating that only certificates signed by the
+   *          authorities associated with this JVM will be accepted.
+   * @return This SSL context builder.
+   */
+  public SSLContextBuilder setTrustManager(final TrustManager trustManager)
+  {
+    this.trustManager = trustManager;
+    return this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SchemaResolver.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SchemaResolver.java
new file mode 100644
index 0000000..f7243c4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SchemaResolver.java
@@ -0,0 +1,63 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * Schema resolvers are included with a set of {@code DecodeOptions} in order to
+ * allow application to control how {@code Schema} instances are selected when
+ * decoding requests and responses.
+ * <p>
+ * Implementations must be thread safe. More specifically, any schema caching
+ * performed by the implementation must be capable of handling multiple
+ * concurrent schema requests.
+ *
+ * @see Schema
+ * @see DecodeOptions
+ */
+public interface SchemaResolver
+{
+
+  /**
+   * Finds the appropriate schema for use with the provided distinguished name.
+   * <p>
+   * Schema resolution must always succeed regardless of any errors that occur.
+   *
+   * @param dn
+   *          The string representation of a distinguished name associated with
+   *          an entry whose schema is to be located.
+   * @return The appropriate schema for use with the provided distinguished
+   *         name.
+   */
+  public abstract Schema resolveSchema(String dn);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultHandler.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultHandler.java
new file mode 100644
index 0000000..9f870d5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultHandler.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.opends.sdk.responses.SearchResultReference;
+
+
+
+/**
+ * A completion handler for consuming the results of a Search operation.
+ * <p>
+ * {@link Connection} and {@link AsynchronousConnection} objects allow a search
+ * result completion handler to be specified when sending Search operation
+ * requests to a Directory Server. The {@link #handleEntry} method is invoked
+ * each time a Search Result Entry is returned from the Directory Server. The
+ * {@link #handleReference} method is invoked for each Search Result Reference
+ * returned from the Directory Server.
+ * <p>
+ * Implementations of these methods should complete in a timely manner so as to
+ * avoid keeping the invoking thread from dispatching to other completion
+ * handlers.
+ */
+public interface SearchResultHandler extends ResultHandler<Result>
+{
+  /**
+   * Invoked each time a search result entry is returned from an asynchronous
+   * search operation.
+   *
+   * @param entry
+   *          The search result entry.
+   * @return {@code true} if this handler should continue to be notified of any
+   *         remaining entries and references, or {@code false} if the remaining
+   *         entries and references should be skipped for some reason (e.g. a
+   *         client side size limit has been reached).
+   */
+  boolean handleEntry(SearchResultEntry entry);
+
+
+
+  /**
+   * Invoked each time a search result reference is returned from an
+   * asynchronous search operation.
+   *
+   * @param reference
+   *          The search result reference.
+   * @return {@code true} if this handler should continue to be notified of any
+   *         remaining entries and references, or {@code false} if the remaining
+   *         entries and references should be skipped for some reason (e.g. a
+   *         client side size limit has been reached).
+   */
+  boolean handleReference(SearchResultReference reference);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultReferenceIOException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultReferenceIOException.java
new file mode 100644
index 0000000..ea7ba1a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchResultReferenceIOException.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.responses.SearchResultReference;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Thrown when an iteration over a set of search results using a
+ * {@code ConnectionEntryReader} encounters a {@code SearchResultReference}.
+ */
+@SuppressWarnings("serial")
+public final class SearchResultReferenceIOException extends IOException
+{
+  private final SearchResultReference reference;
+
+
+
+  /**
+   * Creates a new referral result IO exception with the provided
+   * {@code SearchResultReference}.
+   *
+   * @param reference
+   *          The {@code SearchResultReference} which may be later retrieved by
+   *          the {@link #getReference} method.
+   * @throws NullPointerException
+   *           If {@code reference} was {@code null}.
+   */
+  public SearchResultReferenceIOException(final SearchResultReference reference)
+      throws NullPointerException
+  {
+    super(Validator.ensureNotNull(reference).toString());
+    this.reference = reference;
+  }
+
+
+
+  /**
+   * Returns the {@code SearchResultReference} which was encountered while
+   * processing the search results.
+   *
+   * @return The {@code SearchResultReference} which was encountered while
+   *         processing the search results.
+   */
+  public SearchResultReference getReference()
+  {
+    return reference;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchScope.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchScope.java
new file mode 100644
index 0000000..04ec469
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SearchScope.java
@@ -0,0 +1,205 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * A Search operation search scope as defined in RFC 4511 section 4.5.1.2 is
+ * used to specify the scope of a Search operation.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511#section-4.5.1.2">RFC 4511 -
+ *      Lightweight Directory Access Protocol (LDAP): The Protocol </a>
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-sermersheim-ldap-subordinate-scope">
+ *      draft-sermersheim-ldap-subordinate-scope - Subordinate Subtree Search
+ *      Scope for LDAP </a>
+ */
+public final class SearchScope
+{
+  private static final SearchScope[] ELEMENTS = new SearchScope[4];
+
+  private static final List<SearchScope> IMMUTABLE_ELEMENTS = Collections
+      .unmodifiableList(Arrays.asList(ELEMENTS));
+
+  /**
+   * The scope is constrained to the search base entry.
+   */
+  public static final SearchScope BASE_OBJECT = register(0, "base");
+
+  /**
+   * The scope is constrained to the immediate subordinates of the search base
+   * entry.
+   */
+  public static final SearchScope SINGLE_LEVEL = register(1, "one");
+
+  /**
+   * The scope is constrained to the search base entry and to all its
+   * subordinates.
+   */
+  public static final SearchScope WHOLE_SUBTREE = register(2, "sub");
+
+  /**
+   * The scope is constrained to all the subordinates of the search base entry,
+   * but does not include the search base entry itself (as wholeSubtree does).
+   */
+  public static final SearchScope SUBORDINATES = register(3, "subordinates");
+
+
+
+  /**
+   * Returns the search scope having the specified integer value as defined in
+   * RFC 4511 section 4.5.1.2.
+   *
+   * @param intValue
+   *          The integer value of the search scope.
+   * @return The search scope, or {@code null} if there was no search scope
+   *         associated with {@code intValue}.
+   */
+  public static SearchScope valueOf(final int intValue)
+  {
+    if (intValue < 0 || intValue >= ELEMENTS.length)
+    {
+      return null;
+    }
+    return ELEMENTS[intValue];
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the set of available search scopes
+   * indexed on their integer value as defined in RFC 4511 section 4.5.1.2.
+   *
+   * @return An unmodifiable list containing the set of available search scopes.
+   */
+  public static List<SearchScope> values()
+  {
+    return IMMUTABLE_ELEMENTS;
+  }
+
+
+
+  /**
+   * Creates and registers a new search scope with the application.
+   *
+   * @param intValue
+   *          The integer value of the search scope as defined in RFC 4511
+   *          section 4.5.1.2.
+   * @param name
+   *          The name of the search scope as defined in RFC 4516.
+   * @return The new search scope.
+   */
+  private static SearchScope register(final int intValue, final String name)
+  {
+    final SearchScope t = new SearchScope(intValue, name);
+    ELEMENTS[intValue] = t;
+    return t;
+  }
+
+
+
+  private final int intValue;
+
+  private final String name;
+
+
+
+  // Prevent direct instantiation.
+  private SearchScope(final int intValue, final String name)
+  {
+    this.intValue = intValue;
+    this.name = name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object obj)
+  {
+    if (this == obj)
+    {
+      return true;
+    }
+    else if (obj instanceof SearchScope)
+    {
+      return this.intValue == ((SearchScope) obj).intValue;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Returns the integer value of this search scope as defined in RFC 4511
+   * section 4.5.1.2.
+   *
+   * @return The integer value of this search scope.
+   */
+  public int intValue()
+  {
+    return intValue;
+  }
+
+
+
+  /**
+   * Returns the string representation of this search scope as defined in RFC
+   * 4516.
+   *
+   * @return The string representation of this search scope.
+   */
+  @Override
+  public String toString()
+  {
+    return name;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnection.java
new file mode 100644
index 0000000..b0cea92
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnection.java
@@ -0,0 +1,109 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.requests.AbandonRequest;
+import org.opends.sdk.requests.UnbindRequest;
+
+
+
+/**
+ * A handler interface for interacting with client connections. A
+ * {@code ServerConnection} is associated with a client connection when the
+ * {@link ServerConnectionFactory#handleAccept(Object) handleAccept} method is
+ * invoked against a {@code ServerConnectionFactory}.
+ * <p>
+ * Implementations are responsible for handling connection life-cycle as well as
+ * request life-cycle. In particular, a {@code ServerConnection} is responsible
+ * for processing abandon and unbind requests, as well as extended operations
+ * such as {@code StartTLS} and {@code Cancel} operations.
+ *
+ * @param <C>
+ *          The type of request context.
+ * @see ServerConnectionFactory
+ */
+public interface ServerConnection<C> extends RequestHandler<C>
+{
+
+  /**
+   * Invoked when an abandon request is received from a client.
+   *
+   * @param requestContext
+   *          The request context.
+   * @param request
+   *          The abandon request.
+   * @throws UnsupportedOperationException
+   *           If this server connection does not handle abandon requests.
+   */
+  void handleAbandon(C requestContext, AbandonRequest request)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Invoked when the client closes the connection, possibly using an unbind
+   * request.
+   *
+   * @param requestContext
+   *          The request context which should be ignored if there was no
+   *          associated unbind request.
+   * @param request
+   *          The unbind request, which may be {@code null} if one was not sent
+   *          before the connection was closed.
+   */
+  void handleConnectionClosed(C requestContext, UnbindRequest request);
+
+
+
+  /**
+   * Invoked when the server disconnects the client connection, possibly using a
+   * disconnect notification.
+   *
+   * @param resultCode
+   *          The result code which was included with the disconnect
+   *          notification, or {@code null} if no disconnect notification was
+   *          sent.
+   * @param message
+   *          The diagnostic message, which may be empty or {@code null}
+   *          indicating that none was provided.
+   */
+  void handleConnectionDisconnected(ResultCode resultCode, String message);
+
+
+
+  /**
+   * Invoked when an error occurs on the connection and it is no longer usable.
+   *
+   * @param error
+   *          The exception describing the problem that occurred.
+   */
+  void handleConnectionError(Throwable error);
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnectionFactory.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnectionFactory.java
new file mode 100644
index 0000000..4985d08
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ServerConnectionFactory.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+/**
+ * A handler interface for accepting new connections from clients.
+ * <p>
+ * A connection listener implementation, such as {@link LDAPListener} or
+ * {@link Connections#newInternalConnectionFactory newInternalConnectionFactory}
+ * , invoke the method {@link #handleAccept(Object) handleAccept} whenever a new
+ * client connection is accepted.
+ *
+ * @param <C>
+ *          The type of client context.
+ * @param <R>
+ *          The type of request context.
+ * @see LDAPListener
+ * @see Connections#newInternalConnectionFactory(ServerConnectionFactory,
+ *      Object) newInternalConnectionFactory
+ */
+public interface ServerConnectionFactory<C, R>
+{
+  /**
+   * Invoked when a new client connection is accepted by the associated
+   * listener. Implementations should return a {@code ServerConnection} which
+   * will be used to handle requests from the client connection.
+   *
+   * @param clientContext
+   *          The protocol dependent context information associated with the
+   *          client connection. Depending on the protocol this may contain
+   *          information about the client such as their address and level
+   *          connection security. It may also be used to manage the state of
+   *          the client's connection.
+   * @return A {@code ServerConnection} which will be used to handle requests
+   *         from a client connection.
+   * @throws ErrorResultException
+   *           If this server connection factory cannot accept the client
+   *           connection.
+   */
+  ServerConnection<R> handleAccept(C clientContext) throws ErrorResultException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SortKey.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SortKey.java
new file mode 100644
index 0000000..606119a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SortKey.java
@@ -0,0 +1,704 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.*;
+
+import org.opends.sdk.schema.MatchingRule;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A search result sort key as defined in RFC 2891 is used to specify how search
+ * result entries should be ordered. Sort keys are used with the server side
+ * sort request control
+ * {@link org.opends.sdk.controls.ServerSideSortRequestControl}, but could also
+ * be used for performing client side sorting as well.
+ * <p>
+ * The following example illustrates how a single sort key may be used to sort
+ * entries as they are returned from a search operation using the {@code cn}
+ * attribute as the sort key:
+ *
+ * <pre>
+ * Connection connection = ...;
+ * SearchRequest request = ...;
+ *
+ * Comparator&lt;Entry> comparator = SortKey.comparator("cn");
+ * Set&lt;SearchResultEntry>; results = new TreeSet&lt;SearchResultEntry>(comparator);
+ *
+ * connection.search(request, results);
+ * </pre>
+ *
+ * A sort key includes an attribute description and a boolean value that
+ * indicates whether the sort should be ascending or descending. It may also
+ * contain a specific ordering matching rule that should be used for the sorting
+ * process, although if none is provided it will use the default ordering
+ * matching rule for the attribute type.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2891">RFC 2891 - LDAP Control
+ *      Extension for Server Side Sorting of Search Results </a>
+ */
+public final class SortKey
+{
+  private static final class CompositeEntryComparator implements
+      Comparator<Entry>
+  {
+    private final List<Comparator<Entry>> comparators;
+
+
+
+    private CompositeEntryComparator(final List<Comparator<Entry>> comparators)
+    {
+      this.comparators = comparators;
+    }
+
+
+
+    public int compare(final Entry entry1, final Entry entry2)
+    {
+      for (final Comparator<Entry> comparator : comparators)
+      {
+        final int result = comparator.compare(entry1, entry2);
+        if (result != 0)
+        {
+          return result;
+        }
+      }
+      return 0;
+    }
+
+  }
+
+
+
+  /**
+   * A comparator which can be used to compare entries using a sort key.
+   */
+  private static final class EntryComparator implements Comparator<Entry>
+  {
+    private final AttributeDescription attributeDescription;
+    private final MatchingRule matchingRule;
+    private final Comparator<ByteSequence> valueComparator;
+    private final boolean isReverseOrder;
+
+
+
+    private EntryComparator(final AttributeDescription attributeDescription,
+        final MatchingRule matchingRule, final boolean isReverseOrder)
+
+    {
+      this.attributeDescription = attributeDescription;
+      this.matchingRule = matchingRule;
+      this.valueComparator = matchingRule.comparator();
+      this.isReverseOrder = isReverseOrder;
+    }
+
+
+
+    /**
+     * We must use the lowest available value in both entries and missing
+     * attributes sort last.
+     */
+    public int compare(final Entry entry1, final Entry entry2)
+    {
+      // Find an normalize the lowest value attribute in entry1
+      ByteString lowestNormalizedValue1 = null;
+      for (final Attribute attribute : entry1
+          .getAllAttributes(attributeDescription))
+      {
+        for (final ByteString value : attribute)
+        {
+          try
+          {
+            final ByteString tmp = matchingRule.normalizeAttributeValue(value);
+            if (lowestNormalizedValue1 == null)
+            {
+              lowestNormalizedValue1 = tmp;
+            }
+            else if (valueComparator.compare(tmp, lowestNormalizedValue1) < 0)
+            {
+              lowestNormalizedValue1 = tmp;
+            }
+          }
+          catch (final DecodeException ignored)
+          {
+            // Ignore the error - treat the value as missing.
+          }
+        }
+      }
+
+      // Find an normalize the lowest value attribute in entry2
+      ByteString lowestNormalizedValue2 = null;
+      for (final Attribute attribute : entry2
+          .getAllAttributes(attributeDescription))
+      {
+        for (final ByteString value : attribute)
+        {
+          try
+          {
+            final ByteString tmp = matchingRule.normalizeAttributeValue(value);
+            if (lowestNormalizedValue2 == null)
+            {
+              lowestNormalizedValue2 = tmp;
+            }
+            else if (valueComparator.compare(tmp, lowestNormalizedValue2) < 0)
+            {
+              lowestNormalizedValue2 = tmp;
+            }
+          }
+          catch (final DecodeException ignored)
+          {
+            // Ignore the error - treat the value as missing.
+          }
+        }
+      }
+
+      // Entries with missing attributes always sort after (regardless of
+      // order).
+      if (lowestNormalizedValue1 == null)
+      {
+        return lowestNormalizedValue2 != null ? 1 : 0;
+      }
+
+      if (lowestNormalizedValue2 == null)
+      {
+        return -1;
+      }
+
+      if (isReverseOrder)
+      {
+        return valueComparator.compare(lowestNormalizedValue2,
+            lowestNormalizedValue1);
+      }
+      else
+      {
+        return valueComparator.compare(lowestNormalizedValue1,
+            lowestNormalizedValue2);
+      }
+    }
+
+  }
+
+
+
+  /**
+   * Returns a {@code Comparator} which can be used to compare entries using the
+   * provided list of sort keys. The sort keys will be decoded using the default
+   * schema.
+   *
+   * @param keys
+   *          The list of sort keys.
+   * @return The {@code Comparator}.
+   * @throws LocalizedIllegalArgumentException
+   *           If one of the sort keys could not be converted to a comparator.
+   * @throws IllegalArgumentException
+   *           If {@code keys} was empty.
+   * @throws NullPointerException
+   *           If {@code keys} was {@code null}.
+   */
+  public static Comparator<Entry> comparator(final Collection<SortKey> keys)
+      throws LocalizedIllegalArgumentException, IllegalArgumentException,
+      NullPointerException
+  {
+    return comparator(Schema.getDefaultSchema(), keys);
+  }
+
+
+
+  /**
+   * Returns a {@code Comparator} which can be used to compare entries using the
+   * provided list of sort keys. The sort keys will be decoded using the
+   * provided schema.
+   *
+   * @param schema
+   *          The schema which should be used for decoding the sort keys.
+   * @param keys
+   *          The list of sort keys.
+   * @return The {@code Comparator}.
+   * @throws LocalizedIllegalArgumentException
+   *           If one of the sort keys could not be converted to a comparator.
+   * @throws IllegalArgumentException
+   *           If {@code keys} was empty.
+   * @throws NullPointerException
+   *           If {@code schema} or {@code keys} was {@code null}.
+   */
+  public static Comparator<Entry> comparator(final Schema schema,
+      final Collection<SortKey> keys) throws LocalizedIllegalArgumentException,
+      IllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(schema, keys);
+    Validator.ensureTrue(!keys.isEmpty(), "keys must not be empty");
+
+    final List<Comparator<Entry>> comparators = new ArrayList<Comparator<Entry>>(
+        keys.size());
+    for (final SortKey key : keys)
+    {
+      comparators.add(key.comparator(schema));
+    }
+    return new CompositeEntryComparator(comparators);
+  }
+
+
+
+  /**
+   * Returns a {@code Comparator} which can be used to compare entries using the
+   * provided list of sort keys. The sort keys will be decoded using the
+   * provided schema.
+   *
+   * @param schema
+   *          The schema which should be used for decoding the sort keys.
+   * @param firstKey
+   *          The first sort key.
+   * @param remainingKeys
+   *          The remaining sort keys.
+   * @return The {@code Comparator}.
+   * @throws LocalizedIllegalArgumentException
+   *           If one of the sort keys could not be converted to a comparator.
+   * @throws NullPointerException
+   *           If {@code schema} or {@code firstKey} was {@code null}.
+   */
+  public static Comparator<Entry> comparator(final Schema schema,
+      final SortKey firstKey, final SortKey... remainingKeys)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(schema, firstKey, remainingKeys);
+
+    final List<Comparator<Entry>> comparators = new ArrayList<Comparator<Entry>>(
+        1 + remainingKeys.length);
+    comparators.add(firstKey.comparator(schema));
+    for (final SortKey key : remainingKeys)
+    {
+      comparators.add(key.comparator(schema));
+    }
+    return new CompositeEntryComparator(comparators);
+  }
+
+
+
+  /**
+   * Returns a {@code Comparator} which can be used to compare entries using the
+   * provided list of sort keys. The sort keys will be decoded using the default
+   * schema.
+   *
+   * @param firstKey
+   *          The first sort key.
+   * @param remainingKeys
+   *          The remaining sort keys.
+   * @return The {@code Comparator}.
+   * @throws LocalizedIllegalArgumentException
+   *           If one of the sort keys could not be converted to a comparator.
+   * @throws NullPointerException
+   *           If {@code firstKey} was {@code null}.
+   */
+  public static Comparator<Entry> comparator(final SortKey firstKey,
+      final SortKey... remainingKeys) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    return comparator(Schema.getDefaultSchema(), firstKey, remainingKeys);
+  }
+
+
+
+  /**
+   * Returns a {@code Comparator} which can be used to compare entries using the
+   * provided string representation of a list of sort keys. The sort keys will
+   * be decoded using the default schema. The string representation is comprised
+   * of a comma separate list of sort keys as defined in
+   * {@link #valueOf(String)}. There must be at least one sort key present in
+   * the string representation.
+   *
+   * @param sortKeys
+   *          The list of sort keys.
+   * @return The {@code Comparator}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code sortKeys} is not a valid string representation of a
+   *           list of sort keys, or if one of the sort keys could not be
+   *           converted to a comparator.
+   * @throws NullPointerException
+   *           If {@code sortKeys} was {@code null}.
+   */
+  public static Comparator<Entry> comparator(final String sortKeys)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(sortKeys);
+
+    final List<Comparator<Entry>> comparators = new LinkedList<Comparator<Entry>>();
+    final StringTokenizer tokenizer = new StringTokenizer(sortKeys, ",");
+    while (tokenizer.hasMoreTokens())
+    {
+      final String token = tokenizer.nextToken().trim();
+      comparators.add(valueOf(token).comparator());
+    }
+    if (comparators.isEmpty())
+    {
+      final LocalizableMessage message = ERR_SORT_KEY_NO_SORT_KEYS
+          .get(sortKeys);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+    return new CompositeEntryComparator(comparators);
+  }
+
+
+
+  /**
+   * Parses the provided string representation of a sort key as a {@code
+   * SortKey}. The string representation has the following ABNF (see RFC 4512
+   * for definitions of the elements below):
+   *
+   * <pre>
+   *   SortKey = [ PLUS / HYPHEN ]    ; order specifier
+   *             attributedescription ; attribute description
+   *             [ COLON oid ]        ; ordering matching rule OID
+   * </pre>
+   *
+   * Examples:
+   *
+   * <pre>
+   *   cn                           ; case ignore ascending sort on "cn"
+   *   -cn                          ; case ignore descending sort on "cn"
+   *   +cn;lang-fr                  ; case ignore ascending sort on "cn;lang-fr"
+   *   -cn;lang-fr:caseExactMatch   ; case exact ascending sort on "cn;lang-fr"
+   * </pre>
+   *
+   * @param sortKey
+   *          The string representation of a sort key.
+   * @return The parsed {@code SortKey}.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code sortKey} is not a valid string representation of a sort
+   *           key.
+   * @throws NullPointerException
+   *           If {@code sortKey} was {@code null}.
+   */
+  public static final SortKey valueOf(String sortKey)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(sortKey);
+
+    boolean reverseOrder = false;
+    if (sortKey.startsWith("-"))
+    {
+      reverseOrder = true;
+      sortKey = sortKey.substring(1);
+    }
+    else if (sortKey.startsWith("+"))
+    {
+      sortKey = sortKey.substring(1);
+    }
+
+    final int colonPos = sortKey.indexOf(':');
+    if (colonPos < 0)
+    {
+      if (sortKey.length() == 0)
+      {
+        final LocalizableMessage message = ERR_SORT_KEY_NO_ATTR_NAME
+            .get(sortKey);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      return new SortKey(sortKey, reverseOrder, null);
+    }
+    else if (colonPos == 0)
+    {
+      final LocalizableMessage message = ERR_SORT_KEY_NO_ATTR_NAME.get(sortKey);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+    else if (colonPos == (sortKey.length() - 1))
+    {
+      final LocalizableMessage message = ERR_SORT_KEY_NO_MATCHING_RULE
+          .get(sortKey);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+    else
+    {
+      final String attrName = sortKey.substring(0, colonPos);
+      final String ruleID = sortKey.substring(colonPos + 1);
+
+      return new SortKey(attrName, reverseOrder, ruleID);
+    }
+  }
+
+
+
+  private final String attributeDescription;
+
+  private final String orderingMatchingRule;
+
+  private final boolean isReverseOrder;
+
+
+
+  /**
+   * Creates a new sort key using the provided attribute description. The
+   * returned sort key will compare attributes in the order specified using the
+   * named ordering matching rule.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be sorted using this sort key.
+   * @param isReverseOrder
+   *          {@code true} if this sort key should be evaluated in reverse
+   *          (descending) order.
+   * @param orderingMatchingRule
+   *          The name or OID of the ordering matching rule, which should be
+   *          used when comparing attributes using this sort key, or {@code
+   *          null} if the default ordering matching rule associated with the
+   *          attribute should be used.
+   * @throws NullPointerException
+   *           If {@code AttributeDescription} was {@code null}.
+   */
+  public SortKey(final AttributeDescription attributeDescription,
+      final boolean isReverseOrder, final MatchingRule orderingMatchingRule)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription);
+    this.attributeDescription = attributeDescription.toString();
+    this.orderingMatchingRule = orderingMatchingRule != null ? orderingMatchingRule
+        .getNameOrOID()
+        : null;
+    this.isReverseOrder = isReverseOrder;
+  }
+
+
+
+  /**
+   * Creates a new sort key using the provided attribute description. The
+   * returned sort key will compare attributes in ascending order using the
+   * default ordering matching rule associated with the attribute.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be sorted using this sort key.
+   * @throws NullPointerException
+   *           If {@code AttributeDescription} was {@code null}.
+   */
+  public SortKey(final String attributeDescription) throws NullPointerException
+  {
+    this(attributeDescription, false, null);
+  }
+
+
+
+  /**
+   * Creates a new sort key using the provided attribute description. The
+   * returned sort key will compare attributes in the order specified using the
+   * default ordering matching rule associated with the attribute.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be sorted using this sort key.
+   * @param isReverseOrder
+   *          {@code true} if this sort key should be evaluated in reverse
+   *          (descending) order.
+   * @throws NullPointerException
+   *           If {@code AttributeDescription} was {@code null}.
+   */
+  public SortKey(final String attributeDescription, final boolean isReverseOrder)
+      throws NullPointerException
+  {
+    this(attributeDescription, isReverseOrder, null);
+  }
+
+
+
+  /**
+   * Creates a new sort key using the provided attribute description. The
+   * returned sort key will compare attributes in the order specified using the
+   * named ordering matching rule.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be sorted using this sort key.
+   * @param isReverseOrder
+   *          {@code true} if this sort key should be evaluated in reverse
+   *          (descending) order.
+   * @param orderingMatchingRule
+   *          The name or OID of the ordering matching rule, which should be
+   *          used when comparing attributes using this sort key, or {@code
+   *          null} if the default ordering matching rule associated with the
+   *          attribute should be used.
+   * @throws NullPointerException
+   *           If {@code AttributeDescription} was {@code null}.
+   */
+  public SortKey(final String attributeDescription,
+      final boolean isReverseOrder, final String orderingMatchingRule)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription);
+    this.attributeDescription = attributeDescription;
+    this.orderingMatchingRule = orderingMatchingRule;
+    this.isReverseOrder = isReverseOrder;
+  }
+
+
+
+  /**
+   * Returns a {@code Comparator} which can be used to compare entries using
+   * this sort key. The attribute description and matching rule, if present,
+   * will be decoded using the default schema.
+   *
+   * @return The {@code Comparator}.
+   * @throws LocalizedIllegalArgumentException
+   *           If attributeDescription is not a valid LDAP string representation
+   *           of an attribute description, or if no ordering matching rule was
+   *           found.
+   */
+  public Comparator<Entry> comparator()
+      throws LocalizedIllegalArgumentException
+  {
+    return comparator(Schema.getDefaultSchema());
+  }
+
+
+
+  /**
+   * Returns a {@code Comparator} which can be used to compare entries using
+   * this sort key. The attribute description and matching rule, if present,
+   * will be decoded using the provided schema.
+   *
+   * @param schema
+   *          The schema which should be used for decoding the attribute
+   *          description and matching rule.
+   * @return The {@code Comparator}.
+   * @throws LocalizedIllegalArgumentException
+   *           If attributeDescription is not a valid LDAP string representation
+   *           of an attribute description, or if no ordering matching rule was
+   *           found.
+   * @throws NullPointerException
+   *           If {@code schema} was {@code null}.
+   */
+  public Comparator<Entry> comparator(final Schema schema)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(schema);
+
+    final AttributeDescription ad = AttributeDescription.valueOf(
+        attributeDescription, schema);
+
+    MatchingRule mrule;
+    if (orderingMatchingRule != null)
+    {
+      // FIXME: need to check that the matching rule is a matching rule and can
+      // be used with the attribute.
+      mrule = schema.getMatchingRule(orderingMatchingRule);
+
+      if (mrule == null)
+      {
+        // Specified ordering matching rule not found.
+        final LocalizableMessage message = ERR_SORT_KEY_MRULE_NOT_FOUND.get(
+            toString(), orderingMatchingRule);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+    }
+    else
+    {
+      mrule = ad.getAttributeType().getOrderingMatchingRule();
+
+      if (mrule == null)
+      {
+        // No default ordering matching rule found.
+        final LocalizableMessage message = ERR_SORT_KEY_DEFAULT_MRULE_NOT_FOUND
+            .get(toString(), attributeDescription);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+    }
+
+    return new EntryComparator(ad, mrule, isReverseOrder);
+  }
+
+
+
+  /**
+   * Returns the name of the attribute to be sorted using this sort key.
+   *
+   * @return The name of the attribute to be sorted using this sort key.
+   */
+  public String getAttributeDescription()
+  {
+    return attributeDescription;
+  }
+
+
+
+  /**
+   * Returns the name or OID of the ordering matching rule, if specified, which
+   * should be used when comparing attributes using this sort key.
+   *
+   * @return The name or OID of the ordering matching rule, if specified, which
+   *         should be used when comparing attributes using this sort key, or
+   *         {@code null} if the default ordering matching rule associated with
+   *         the attribute should be used.
+   */
+  public String getOrderingMatchingRule()
+  {
+    return orderingMatchingRule;
+  }
+
+
+
+  /**
+   * Returns {@code true} if this sort key should be evaluated in reverse
+   * (descending) order. More specifically, comparisons performed using the
+   * ordering matching rule associated with this sort key will have their
+   * results inverted.
+   *
+   * @return {@code true} if this sort key should be evaluated in reverse
+   *         (descending) order.
+   */
+  public boolean isReverseOrder()
+  {
+    return isReverseOrder;
+  }
+
+
+
+  /**
+   * Returns a string representation of this sort key using the format defined
+   * in {@link #valueOf(String)}.
+   *
+   * @return A string representation of this sort key.
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    if (isReverseOrder)
+    {
+      builder.append('-');
+    }
+    builder.append(attributeDescription);
+    if (orderingMatchingRule != null)
+    {
+      builder.append(':');
+      builder.append(orderingMatchingRule);
+    }
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SynchronousConnection.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SynchronousConnection.java
new file mode 100644
index 0000000..b382b5c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/SynchronousConnection.java
@@ -0,0 +1,388 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.ldif.ConnectionEntryReader;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+import java.util.concurrent.BlockingQueue;
+
+
+
+/**
+ * A {@code SynchronousConnection} adapts an {@code AsynchronousConnection} into
+ * a synchronous {@code Connection}.
+ */
+public class SynchronousConnection extends AbstractConnection
+{
+  private final AsynchronousConnection connection;
+
+
+
+  /**
+   * Creates a new abstract connection which will route all synchronous requests
+   * to the provided asynchronous connection.
+   *
+   * @param connection
+   *          The asynchronous connection to be used.
+   * @throws NullPointerException
+   *           If {@code connection} was {@code null}.
+   */
+  public SynchronousConnection(final AsynchronousConnection connection)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(connection);
+    this.connection = connection;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result add(final AddRequest request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final FutureResult<Result> future = connection.add(request, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void addConnectionEventListener(final ConnectionEventListener listener)
+      throws IllegalStateException, NullPointerException
+  {
+    connection.addConnectionEventListener(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public BindResult bind(final BindRequest request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final FutureResult<BindResult> future = connection.bind(request, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close()
+  {
+    connection.close();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close(final UnbindRequest request, final String reason)
+      throws NullPointerException
+  {
+    connection.close(request, reason);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareResult compare(final CompareRequest request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final FutureResult<CompareResult> future = connection
+        .compare(request, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result delete(final DeleteRequest request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final FutureResult<Result> future = connection.delete(request, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R extends ExtendedResult> R extendedRequest(
+      final ExtendedRequest<R> request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final FutureResult<R> future = connection.extendedRequest(request, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R extends ExtendedResult> R extendedRequest(
+      final ExtendedRequest<R> request,
+      final IntermediateResponseHandler handler) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final FutureResult<R> future = connection.extendedRequest(request, null,
+        handler);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AsynchronousConnection getAsynchronousConnection()
+  {
+    return connection;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isClosed()
+  {
+    return connection.isClosed();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isValid()
+  {
+    return connection.isValid();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result modify(final ModifyRequest request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final FutureResult<Result> future = connection.modify(request, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result modifyDN(final ModifyDNRequest request)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final FutureResult<Result> future = connection.modifyDN(request, null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Schema readSchemaForEntry(final DN name) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException
+  {
+    final FutureResult<Schema> future = connection.readSchemaForEntry(name,
+        null);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void removeConnectionEventListener(
+      final ConnectionEventListener listener) throws NullPointerException
+  {
+    connection.removeConnectionEventListener(listener);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Result search(final SearchRequest request,
+      final SearchResultHandler handler) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    final FutureResult<Result> future = connection.search(request, handler);
+    try
+    {
+      return future.get();
+    }
+    finally
+    {
+      // Cancel the request if it hasn't completed.
+      future.cancel(false);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ConnectionEntryReader search(final SearchRequest request,
+      BlockingQueue<Response> entries) throws UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return new ConnectionEntryReader(getAsynchronousConnection(), request,
+        entries);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String toString()
+  {
+    return connection.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TimeoutResultException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TimeoutResultException.java
new file mode 100644
index 0000000..db3f200
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TimeoutResultException.java
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.opends.sdk.responses.Result;
+
+
+
+/**
+ * Thrown when the result code returned in a Result indicates that the Request
+ * was aborted because it did not complete in the required time out period.
+ */
+@SuppressWarnings("serial")
+public class TimeoutResultException extends ErrorResultException
+{
+  TimeoutResultException(final Result result)
+  {
+    super(result);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TreeMapEntry.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TreeMapEntry.java
new file mode 100644
index 0000000..0cd3550
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TreeMapEntry.java
@@ -0,0 +1,188 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.TreeMap;
+
+import org.opends.sdk.requests.Requests;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An implementation of the {@code Entry} interface which uses a {@code TreeMap}
+ * for storing attributes. Attributes are returned in ascending order of
+ * attribute description, with {@code objectClass} first, then all user
+ * attributes, and finally any operational attributes. All operations are
+ * supported by this implementation.
+ * <p>
+ * A {@code TreeMapEntry} stores references to attributes which have been added
+ * using the {@link #addAttribute} methods. Attributes sharing the same
+ * attribute description are merged by adding the values of the new attribute to
+ * the existing attribute. More specifically, the existing attribute must be
+ * modifiable for the merge to succeed. Similarly, the {@link #removeAttribute}
+ * methods remove the specified values from the existing attribute. The
+ * {@link #replaceAttribute} methods remove the existing attribute (if present)
+ * and store a reference to the new attribute - neither the new or existing
+ * attribute need to be modifiable in this case.
+ */
+public final class TreeMapEntry extends AbstractMapEntry
+{
+  /**
+   * An entry factory which can be used to create new tree map entries.
+   */
+  public static final EntryFactory FACTORY = new EntryFactory()
+  {
+    public Entry newEntry(final DN name) throws NullPointerException
+    {
+      return new TreeMapEntry(name);
+    }
+  };
+
+
+
+  /**
+   * Creates an entry having the same distinguished name, attributes, and object
+   * classes of the provided entry. This constructor performs a deep copy of
+   * {@code entry} and will copy each attribute as a {@link LinkedAttribute}.
+   * <p>
+   * A shallow copy constructor is provided by {@link #TreeMapEntry(Entry)}.
+   *
+   * @param entry
+   *          The entry to be copied.
+   * @return A deep copy of {@code entry}.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   * @see #TreeMapEntry(Entry)
+   */
+  public static TreeMapEntry deepCopyOfEntry(final Entry entry)
+      throws NullPointerException
+  {
+    TreeMapEntry copy = new TreeMapEntry(entry.getName());
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      copy.addAttribute(new LinkedAttribute(attribute));
+    }
+    return copy;
+  }
+
+
+
+  /**
+   * Creates an entry with an empty (root) distinguished name and no attributes.
+   */
+  public TreeMapEntry()
+  {
+    this(DN.rootDN());
+  }
+
+
+
+  /**
+   * Creates an empty entry using the provided distinguished name and no
+   * attributes.
+   *
+   * @param name
+   *          The distinguished name of this entry.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public TreeMapEntry(final DN name) throws NullPointerException
+  {
+    super(Validator.ensureNotNull(name),
+        new TreeMap<AttributeDescription, Attribute>());
+  }
+
+
+
+  /**
+   * Creates an entry having the same distinguished name, attributes, and object
+   * classes of the provided entry. This constructor performs a shallow copy of
+   * {@code entry} and will not copy the attributes contained in {@code entry}.
+   * <p>
+   * A deep copy constructor is provided by {@link #deepCopyOfEntry(Entry)}
+   *
+   * @param entry
+   *          The entry to be copied.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   * @see #deepCopyOfEntry(Entry)
+   */
+  public TreeMapEntry(final Entry entry) throws NullPointerException
+  {
+    this(entry.getName());
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      addAttribute(attribute);
+    }
+  }
+
+
+
+  /**
+   * Creates an empty entry using the provided distinguished name decoded using
+   * the default schema.
+   *
+   * @param name
+   *          The distinguished name of this entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public TreeMapEntry(final String name)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    this(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * Creates a new entry using the provided lines of LDIF decoded using the
+   * default schema.
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing the an LDIF add change record or an LDIF
+   *          entry record.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  public TreeMapEntry(final String... ldifLines)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    this(Requests.newAddRequest(ldifLines));
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TrustManagers.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TrustManagers.java
new file mode 100644
index 0000000..963737b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/TrustManagers.java
@@ -0,0 +1,551 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class contains methods for creating common types of trust manager.
+ */
+public final class TrustManagers
+{
+
+  /**
+   * An X509TrustManager which rejects certificate chains whose subject DN does
+   * not match a specified host name.
+   */
+  private static final class CheckHostName implements X509TrustManager
+  {
+
+    private final X509TrustManager trustManager;
+
+    private final String hostNamePattern;
+
+
+
+    private CheckHostName(final X509TrustManager trustManager,
+        final String hostNamePattern)
+    {
+      this.trustManager = trustManager;
+      this.hostNamePattern = hostNamePattern;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkClientTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+      verifyHostName(chain);
+      trustManager.checkClientTrusted(chain, authType);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkServerTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+      verifyHostName(chain);
+      trustManager.checkServerTrusted(chain, authType);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public X509Certificate[] getAcceptedIssuers()
+    {
+      return trustManager.getAcceptedIssuers();
+    }
+
+
+
+    /**
+     * Checks whether a host name matches the provided pattern. It accepts the
+     * use of wildcards in the pattern, e.g. {@code *.example.com}.
+     *
+     * @param hostName
+     *          The host name.
+     * @param pattern
+     *          The host name pattern, which may contain wild cards.
+     * @return {@code true} if the host name matched the pattern, otherwise
+     *         {@code false}.
+     */
+    private boolean hostNameMatchesPattern(final String hostName,
+        final String pattern)
+    {
+      final String[] nameElements = hostName.split("\\.");
+      final String[] patternElements = pattern.split("\\.");
+
+      boolean hostMatch = nameElements.length == patternElements.length;
+      for (int i = 0; i < nameElements.length && hostMatch; i++)
+      {
+        final String ne = nameElements[i];
+        final String pe = patternElements[i];
+        if (!pe.equals("*"))
+        {
+          hostMatch = ne.equalsIgnoreCase(pe);
+        }
+      }
+      return hostMatch;
+    }
+
+
+
+    private void verifyHostName(final X509Certificate[] chain)
+        throws CertificateException
+    {
+      try
+      {
+        // TODO: NPE if root DN.
+        final DN dn = DN.valueOf(chain[0].getSubjectX500Principal().getName(),
+            Schema.getCoreSchema());
+        final String value = dn.iterator().next().iterator().next()
+            .getAttributeValue().toString();
+        if (!hostNameMatchesPattern(value, hostNamePattern))
+        {
+          throw new CertificateException(
+              "The host name contained in the certificate chain subject DN \'"
+                  + chain[0].getSubjectX500Principal()
+                  + "' does not match the host name \'" + hostNamePattern + "'");
+        }
+      }
+      catch (final Throwable t)
+      {
+        LOG.log(Level.WARNING, "Error parsing subject dn: "
+            + chain[0].getSubjectX500Principal(), t);
+      }
+    }
+  }
+
+
+
+  /**
+   * An X509TrustManager which rejects certificates which have expired or are
+   * not yet valid.
+   */
+  private static final class CheckValidatyDates implements X509TrustManager
+  {
+
+    private final X509TrustManager trustManager;
+
+
+
+    private CheckValidatyDates(final X509TrustManager trustManager)
+    {
+      this.trustManager = trustManager;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkClientTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+      verifyExpiration(chain);
+      trustManager.checkClientTrusted(chain, authType);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkServerTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+      verifyExpiration(chain);
+      trustManager.checkServerTrusted(chain, authType);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public X509Certificate[] getAcceptedIssuers()
+    {
+      return trustManager.getAcceptedIssuers();
+    }
+
+
+
+    private void verifyExpiration(final X509Certificate[] chain)
+        throws CertificateException
+    {
+      final Date currentDate = new Date();
+      for (final X509Certificate c : chain)
+      {
+        try
+        {
+          c.checkValidity(currentDate);
+        }
+        catch (final CertificateExpiredException e)
+        {
+          LOG.log(Level.WARNING, "Refusing to trust security"
+              + " certificate \"" + c.getSubjectDN().getName()
+              + "\" because it" + " expired on "
+              + String.valueOf(c.getNotAfter()));
+
+          throw e;
+        }
+        catch (final CertificateNotYetValidException e)
+        {
+          LOG.log(Level.WARNING, "Refusing to trust security"
+              + " certificate \"" + c.getSubjectDN().getName()
+              + "\" because it" + " is not valid until "
+              + String.valueOf(c.getNotBefore()));
+
+          throw e;
+        }
+      }
+    }
+  }
+
+
+
+  /**
+   * An X509TrustManager which does not trust any certificates.
+   */
+  private static final class DistrustAll implements X509TrustManager
+  {
+    // Single instance.
+    private static final DistrustAll INSTANCE = new DistrustAll();
+
+
+
+    // Prevent instantiation.
+    private DistrustAll()
+    {
+      // Nothing to do.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkClientTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+      throw new CertificateException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkServerTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+      throw new CertificateException();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public X509Certificate[] getAcceptedIssuers()
+    {
+      return new X509Certificate[0];
+    }
+  }
+
+
+
+  /**
+   * An X509TrustManager which trusts all certificates.
+   */
+  private static final class TrustAll implements X509TrustManager
+  {
+
+    // Single instance.
+    private static final TrustAll INSTANCE = new TrustAll();
+
+
+
+    // Prevent instantiation.
+    private TrustAll()
+    {
+      // Nothing to do.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkClientTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkServerTrusted(final X509Certificate[] chain,
+        final String authType) throws CertificateException
+    {
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public X509Certificate[] getAcceptedIssuers()
+    {
+      return new X509Certificate[0];
+    }
+  }
+
+
+
+  private static final Logger LOG = Logger.getLogger(TrustManagers.class
+      .getName());
+
+
+
+  /**
+   * Wraps the provided {@code X509TrustManager} by adding additional validation
+   * which rejects certificate chains whose subject DN does not match the
+   * specified host name pattern. The pattern may contain wild-cards, for
+   * example {@code *.example.com}.
+   *
+   * @param hostNamePattern
+   *          A host name pattern which the RDN value contained in certificate
+   *          subject DNs must match.
+   * @param trustManager
+   *          The trust manager to be wrapped.
+   * @return The wrapped trust manager.
+   * @throws NullPointerException
+   *           If {@code trustManager} or {@code hostNamePattern} was {@code
+   *           null}.
+   */
+  public static X509TrustManager checkHostName(final String hostNamePattern,
+      final X509TrustManager trustManager) throws NullPointerException
+  {
+    Validator.ensureNotNull(trustManager, hostNamePattern);
+    return new CheckHostName(trustManager, hostNamePattern);
+  }
+
+
+
+  /**
+   * Creates a new {@code X509TrustManager} which will use the named trust store
+   * file to determine whether to trust a certificate. It will use the default
+   * trust store format for the JVM (e.g. {@code JKS}) and will not use a
+   * password to open the trust store.
+   *
+   * @param file
+   *          The trust store file name.
+   * @return A new {@code X509TrustManager} which will use the named trust store
+   *         file to determine whether to trust a certificate.
+   * @throws GeneralSecurityException
+   *           If the trust store could not be loaded, perhaps due to incorrect
+   *           format, or missing algorithms.
+   * @throws IOException
+   *           If the trust store file could not be found or could not be read.
+   * @throws NullPointerException
+   *           If {@code file} was {@code null}.
+   */
+  public static X509TrustManager checkUsingTrustStore(final String file)
+      throws GeneralSecurityException, IOException, NullPointerException
+  {
+    return checkUsingTrustStore(file, null, null);
+  }
+
+
+
+  /**
+   * Creates a new {@code X509TrustManager} which will use the named trust store
+   * file to determine whether to trust a certificate. It will use the provided
+   * trust store format and password.
+   *
+   * @param file
+   *          The trust store file name.
+   * @param password
+   *          The trust store password, which may be {@code null}.
+   * @param format
+   *          The trust store format, which may be {@code null} to indicate that
+   *          the default trust store format for the JVM (e.g. {@code JKS})
+   *          should be used.
+   * @return A new {@code X509TrustManager} which will use the named trust store
+   *         file to determine whether to trust a certificate.
+   * @throws GeneralSecurityException
+   *           If the trust store could not be loaded, perhaps due to incorrect
+   *           format, or missing algorithms.
+   * @throws IOException
+   *           If the trust store file could not be found or could not be read.
+   * @throws NullPointerException
+   *           If {@code file} was {@code null}.
+   */
+  public static X509TrustManager checkUsingTrustStore(final String file,
+      final char[] password, final String format)
+      throws GeneralSecurityException, IOException, NullPointerException
+  {
+    Validator.ensureNotNull(file);
+
+    final File trustStoreFile = new File(file);
+    final String trustStoreFormat = format != null ? format : KeyStore
+        .getDefaultType();
+
+    final KeyStore keyStore = KeyStore.getInstance(trustStoreFormat);
+
+    FileInputStream fos = null;
+    try
+    {
+      fos = new FileInputStream(trustStoreFile);
+      keyStore.load(fos, password);
+    }
+    finally
+    {
+      if (fos != null)
+      {
+        try
+        {
+          fos.close();
+        }
+        catch (final IOException ignored)
+        {
+          // Ignore.
+        }
+      }
+    }
+
+    final TrustManagerFactory tmf = TrustManagerFactory
+        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
+    tmf.init(keyStore);
+
+    X509TrustManager x509tm = null;
+    for (final TrustManager tm : tmf.getTrustManagers())
+    {
+      if (tm instanceof X509TrustManager)
+      {
+        x509tm = (X509TrustManager) tm;
+        break;
+      }
+    }
+
+    if (x509tm == null)
+    {
+      throw new NoSuchAlgorithmException();
+    }
+
+    return x509tm;
+  }
+
+
+
+  /**
+   * Wraps the provided {@code X509TrustManager} by adding additional validation
+   * which rejects certificate chains containing certificates which have expired
+   * or are not yet valid.
+   *
+   * @param trustManager
+   *          The trust manager to be wrapped.
+   * @return The wrapped trust manager.
+   * @throws NullPointerException
+   *           If {@code trustManager} was {@code null}.
+   */
+  public static X509TrustManager checkValidityDates(
+      final X509TrustManager trustManager) throws NullPointerException
+  {
+    Validator.ensureNotNull(trustManager);
+    return new CheckValidatyDates(trustManager);
+  }
+
+
+
+  /**
+   * Returns an {@code X509TrustManager} which does not trust any certificates.
+   *
+   * @return An {@code X509TrustManager} which does not trust any certificates.
+   */
+  public static X509TrustManager distrustAll()
+  {
+    return DistrustAll.INSTANCE;
+  }
+
+
+
+  /**
+   * Returns an {@code X509TrustManager} which trusts all certificates.
+   *
+   * @return An {@code X509TrustManager} which trusts all certificates.
+   */
+  public static X509TrustManager trustAll()
+  {
+    return TrustAll.INSTANCE;
+  }
+
+
+
+  // Prevent insantiation.
+  private TrustManagers()
+  {
+    // Nothing to do.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1.java
new file mode 100644
index 0000000..df5c477
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1.java
@@ -0,0 +1,226 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.asn1;
+
+
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteSequenceReader;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+
+import com.sun.opends.sdk.util.ByteSequenceOutputStream;
+
+
+
+/**
+ * This class contains various static factory methods for creating ASN.1 readers
+ * and writers.
+ *
+ * @see ASN1Reader
+ * @see ASN1Writer
+ */
+public final class ASN1
+{
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided byte array and having
+   * an unlimited maximum BER element size.
+   *
+   * @param array
+   *          The byte array to use.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final byte[] array)
+  {
+    return getReader(array, 0);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided byte array and having
+   * a user defined maximum BER element size.
+   *
+   * @param array
+   *          The byte array to use.
+   * @param maxElementSize
+   *          The maximum BER element size, or {@code 0} to indicate that there
+   *          is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final byte[] array,
+      final int maxElementSize)
+  {
+    return getReader(ByteString.wrap(array), maxElementSize);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided byte sequence and
+   * having an unlimited maximum BER element size.
+   *
+   * @param sequence
+   *          The byte sequence to use.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final ByteSequence sequence)
+  {
+    return getReader(sequence, 0);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided byte sequence and
+   * having a user defined maximum BER element size.
+   *
+   * @param sequence
+   *          The byte sequence to use.
+   * @param maxElementSize
+   *          The maximum BER element size, or {@code 0} to indicate that there
+   *          is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final ByteSequence sequence,
+      final int maxElementSize)
+  {
+    return new ASN1ByteSequenceReader(sequence.asReader(), maxElementSize);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided byte sequence reader
+   * and having an unlimited maximum BER element size.
+   *
+   * @param reader
+   *          The byte sequence reader to use.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final ByteSequenceReader reader)
+  {
+    return getReader(reader, 0);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided byte sequence reader
+   * and having a user defined maximum BER element size.
+   *
+   * @param reader
+   *          The byte sequence reader to use.
+   * @param maxElementSize
+   *          The maximum BER element size, or {@code 0} to indicate that there
+   *          is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final ByteSequenceReader reader,
+      final int maxElementSize)
+  {
+    return new ASN1ByteSequenceReader(reader, maxElementSize);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided input stream and
+   * having an unlimited maximum BER element size.
+   *
+   * @param stream
+   *          The input stream to use.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final InputStream stream)
+  {
+    return getReader(stream, 0);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 reader whose source is the provided input stream and
+   * having a user defined maximum BER element size.
+   *
+   * @param stream
+   *          The input stream to use.
+   * @param maxElementSize
+   *          The maximum BER element size, or {@code 0} to indicate that there
+   *          is no limit.
+   * @return The new ASN.1 reader.
+   */
+  public static ASN1Reader getReader(final InputStream stream,
+      final int maxElementSize)
+  {
+    return new ASN1InputStreamReader(stream, maxElementSize);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 writer whose destination is the provided byte string
+   * builder.
+   *
+   * @param builder
+   *          The byte string builder to use.
+   * @return The new ASN.1 writer.
+   */
+  public static ASN1Writer getWriter(final ByteStringBuilder builder)
+  {
+    final ByteSequenceOutputStream outputStream = new ByteSequenceOutputStream(
+        builder);
+    return getWriter(outputStream);
+  }
+
+
+
+  /**
+   * Returns an ASN.1 writer whose destination is the provided output stream.
+   *
+   * @param stream
+   *          The output stream to use.
+   * @return The new ASN.1 writer.
+   */
+  public static ASN1Writer getWriter(final OutputStream stream)
+  {
+    return new ASN1OutputStreamWriter(stream);
+  }
+
+
+
+  // Prevent instantiation.
+  private ASN1()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1ByteSequenceReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1ByteSequenceReader.java
new file mode 100644
index 0000000..612d101
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1ByteSequenceReader.java
@@ -0,0 +1,562 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.asn1;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_TYPE;
+import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.logging.Level;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An ASN.1 reader that reads from a {@link ByteSequenceReader}.
+ */
+final class ASN1ByteSequenceReader extends AbstractASN1Reader implements
+    ASN1Reader
+{
+
+  private int state = ELEMENT_READ_STATE_NEED_TYPE;
+
+  private byte peekType = 0;
+
+  private int peekLength = -1;
+
+  private final int maxElementSize;
+
+  private ByteSequenceReader reader;
+
+  private final LinkedList<ByteSequenceReader> readerStack;
+
+
+
+  /**
+   * Creates a new ASN1 reader whose source is the provided byte sequence reader
+   * and having a user defined maximum BER element size.
+   *
+   * @param reader
+   *          The byte sequence reader to be read.
+   * @param maxElementSize
+   *          The maximum BER element size, or <code>0</code> to indicate that
+   *          there is no limit.
+   */
+  ASN1ByteSequenceReader(final ByteSequenceReader reader,
+      final int maxElementSize)
+  {
+    this.reader = reader;
+    this.readerStack = new LinkedList<ByteSequenceReader>();
+    this.maxElementSize = maxElementSize;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException
+  {
+    readerStack.clear();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean elementAvailable() throws IOException
+  {
+    if ((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(false))
+    {
+      return false;
+    }
+    if ((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
+        && !needFirstLengthByteState(false))
+    {
+      return false;
+    }
+
+    return peekLength <= reader.remaining();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasNextElement() throws IOException
+  {
+    return (state != ELEMENT_READ_STATE_NEED_TYPE) || needTypeState(false);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int peekLength() throws IOException
+  {
+    peekType();
+
+    if (state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
+    {
+      needFirstLengthByteState(true);
+    }
+
+    return peekLength;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte peekType() throws IOException
+  {
+    if (state == ELEMENT_READ_STATE_NEED_TYPE)
+    {
+      // Read just the type.
+      if (reader.remaining() <= 0)
+      {
+        final LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get();
+        throw DecodeException.fatalError(message);
+      }
+      final int type = reader.get();
+
+      peekType = (byte) type;
+      state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+    }
+
+    return peekType;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean readBoolean() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength != 1)
+    {
+      final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    if (reader.remaining() < peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+    final int readByte = reader.get();
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return readByte != 0x00;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSequence() throws IOException, IllegalStateException
+  {
+    if (readerStack.isEmpty())
+    {
+      final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED
+          .get();
+      throw new IllegalStateException(message.toString());
+    }
+
+    if ((reader.remaining() > 0)
+        && StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+    {
+      StaticUtils.DEBUG_LOG.fine("Ignoring " + reader.remaining()
+          + " unused trailing bytes in " + "ASN.1 SEQUENCE");
+    }
+
+    reader = readerStack.removeFirst();
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSet() throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    readEndSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int readEnumerated() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 4))
+    {
+      final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    // From an implementation point of view, an enumerated value is
+    // equivalent to an integer.
+    return (int) readInteger();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public long readInteger() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 8))
+    {
+      final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    if (reader.remaining() < peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+    if (peekLength > 4)
+    {
+      long longValue = 0;
+      for (int i = 0; i < peekLength; i++)
+      {
+        final int readByte = reader.get();
+        if ((i == 0) && (readByte < 0))
+        {
+          longValue = 0xFFFFFFFFFFFFFFFFL;
+        }
+        longValue = (longValue << 8) | (readByte & 0xFF);
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return longValue;
+    }
+    else
+    {
+      int intValue = 0;
+      for (int i = 0; i < peekLength; i++)
+      {
+        final int readByte = reader.get();
+        if ((i == 0) && (readByte < 0))
+        {
+          intValue = 0xFFFFFFFF;
+        }
+        intValue = (intValue << 8) | (readByte & 0xFF);
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return intValue;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readNull() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    // Make sure that the decoded length is exactly zero byte.
+    if (peekLength != 0)
+    {
+      final LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString readOctetString() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (reader.remaining() < peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return reader.getByteString(peekLength);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteStringBuilder readOctetString(final ByteStringBuilder builder)
+      throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    // Copy the value.
+    if (reader.remaining() < peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+    builder.append(reader, peekLength);
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (reader.remaining() < peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return reader.getString(peekLength);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSequence() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (reader.remaining() < peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_SEQUENCE_SET_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    final ByteSequenceReader subByteString = reader.getByteSequence(peekLength)
+        .asReader();
+    readerStack.addFirst(reader);
+    reader = subByteString;
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSet() throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    readStartSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Reader skipElement() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (reader.remaining() < peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_SKIP_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    reader.skip(peekLength);
+    return this;
+  }
+
+
+
+  /**
+   * Internal helper method reading the first length bytes and transition to the
+   * next state if successful.
+   *
+   * @param throwEofException
+   *          <code>true</code> to throw an exception when the end of the
+   *          sequence is encountered.
+   * @return <code>true</code> if the length bytes was successfully read
+   * @throws IOException
+   *           If an error occurs while trying to decode an ASN1 element.
+   */
+  private boolean needFirstLengthByteState(final boolean throwEofException)
+      throws IOException
+  {
+    if (reader.remaining() <= 0)
+    {
+      if (throwEofException)
+      {
+        final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
+        throw DecodeException.fatalError(message);
+      }
+      return false;
+    }
+    int readByte = reader.get();
+    peekLength = (readByte & 0x7F);
+    if (peekLength != readByte)
+    {
+      int lengthBytesNeeded = peekLength;
+      if (lengthBytesNeeded > 4)
+      {
+        final LocalizableMessage message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES
+            .get(lengthBytesNeeded);
+        throw DecodeException.fatalError(message);
+      }
+
+      peekLength = 0x00;
+      if (reader.remaining() < lengthBytesNeeded)
+      {
+        if (throwEofException)
+        {
+          final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
+              .get(lengthBytesNeeded);
+          throw DecodeException.fatalError(message);
+        }
+        return false;
+      }
+
+      while (lengthBytesNeeded > 0)
+      {
+        readByte = reader.get();
+        peekLength = (peekLength << 8) | (readByte & 0xFF);
+        lengthBytesNeeded--;
+      }
+    }
+
+    // Make sure that the element is not larger than the maximum allowed
+    // message size.
+    if ((maxElementSize > 0) && (peekLength > maxElementSize))
+    {
+      final LocalizableMessage message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
+          .get(peekLength, maxElementSize);
+      throw DecodeException.fatalError(message);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+
+
+  /**
+   * Internal helper method reading the ASN.1 type byte and transition to the
+   * next state if successful.
+   *
+   * @param throwEofException
+   *          <code>true</code> to throw an exception when the end of the
+   *          sequence is encountered.
+   * @return <code>true</code> if the type byte was successfully read
+   * @throws IOException
+   *           If an error occurs while trying to decode an ASN1 element.
+   */
+  private boolean needTypeState(final boolean throwEofException)
+      throws IOException
+  {
+    // Read just the type.
+    if (reader.remaining() <= 0)
+    {
+      if (throwEofException)
+      {
+        final LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get();
+        throw DecodeException.fatalError(message);
+      }
+      return false;
+    }
+    final int type = reader.get();
+
+    peekType = (byte) type;
+    state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Constants.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Constants.java
new file mode 100644
index 0000000..c70ace7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Constants.java
@@ -0,0 +1,169 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+/**
+ * This class defines a number of constants that may be used when interacting
+ * with ASN.1 elements.
+ */
+public final class ASN1Constants
+{
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be the BER type for a new element.
+   */
+  static final int ELEMENT_READ_STATE_NEED_TYPE = 0;
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be the first byte for the element length.
+   */
+  static final int ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE = 1;
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be additional bytes of a multi-byte length.
+   */
+  static final int ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES = 2;
+
+  /**
+   * The ASN.1 element decoding state that indicates that the next byte read
+   * should be applied to the value of the element.
+   */
+  static final int ELEMENT_READ_STATE_NEED_VALUE_BYTES = 3;
+
+  /**
+   * The BER type that is assigned to the universal Boolean element.
+   */
+  public static final byte UNIVERSAL_BOOLEAN_TYPE = 0x01;
+
+  /**
+   * The BER type that is assigned to the universal integer type.
+   */
+  public static final byte UNIVERSAL_INTEGER_TYPE = 0x02;
+
+  /**
+   * The BER type that is assigned to the universal octet string type.
+   */
+  public static final byte UNIVERSAL_OCTET_STRING_TYPE = 0x04;
+
+  /**
+   * The BER type that is assigned to the universal null type.
+   */
+  public static final byte UNIVERSAL_NULL_TYPE = 0x05;
+
+  /**
+   * The BER type that is assigned to the universal enumerated type.
+   */
+  public static final byte UNIVERSAL_ENUMERATED_TYPE = 0x0A;
+
+  /**
+   * The BER type that is assigned to the universal sequence type.
+   */
+  public static final byte UNIVERSAL_SEQUENCE_TYPE = 0x30;
+
+  /**
+   * The BER type that is assigned to the universal set type.
+   */
+  public static final byte UNIVERSAL_SET_TYPE = 0x31;
+
+  /**
+   * The byte array that will be used for ASN.1 elements with no value.
+   */
+  static final byte[] NO_VALUE = new byte[0];
+
+  /**
+   * The bitmask that can be ANDed with the BER type to zero out all bits except
+   * those used in the class.
+   */
+  static final byte TYPE_MASK_ALL_BUT_CLASS = (byte) 0xC0;
+
+  /**
+   * The bitmask that can be ANDed with the BER type to determine if the element
+   * is in the universal class.
+   */
+  static final byte TYPE_MASK_UNIVERSAL = 0x00;
+
+  /**
+   * The bitmask that can be ANDed with the BER type to determine if the element
+   * is in the application-specific class.
+   */
+  static final byte TYPE_MASK_APPLICATION = 0x40;
+
+  /**
+   * The bitmask that can be ANDed with the BER type to determine if the element
+   * is in the context-specific class.
+   */
+  static final byte TYPE_MASK_CONTEXT = (byte) 0x80;
+
+  /**
+   * The bitmask that can be ANDed with the BER type to determine if the element
+   * is in the private class.
+   */
+  static final byte TYPE_MASK_PRIVATE = (byte) 0xC0;
+
+  /**
+   * The bitmask that can be ANDed with the BER type to zero out all bits except
+   * the primitive/constructed bit.
+   */
+  static final byte TYPE_MASK_ALL_BUT_PC = (byte) 0x20;
+
+  /**
+   * The bitmask that can be ANDed with the BER type to determine if the element
+   * is a primitive.
+   */
+  static final byte TYPE_MASK_PRIMITIVE = 0x00;
+
+  /**
+   * The bitmask that can be ANDed with the BER type to determine if the element
+   * is constructed.
+   */
+  static final byte TYPE_MASK_CONSTRUCTED = 0x20;
+
+  /**
+   * The byte array containing the pre-encoded ASN.1 encoding for a boolean
+   * value of "false".
+   */
+  public static final byte BOOLEAN_VALUE_FALSE = 0x00;
+
+  /**
+   * The byte array containing the pre-encoded ASN.1 encoding for a boolean
+   * value of "false".
+   */
+  public static final byte BOOLEAN_VALUE_TRUE = (byte) 0xFF;
+
+
+
+  // Prevent instantiation.
+  private ASN1Constants()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1InputStreamReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1InputStreamReader.java
new file mode 100644
index 0000000..919b4ba
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1InputStreamReader.java
@@ -0,0 +1,786 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.asn1;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_TYPE;
+import static org.opends.sdk.asn1.ASN1Constants.ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.logging.Level;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.SizeLimitInputStream;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An ASN1Reader that reads from an input stream.
+ */
+final class ASN1InputStreamReader extends AbstractASN1Reader implements
+    ASN1Reader
+{
+  private int state = ELEMENT_READ_STATE_NEED_TYPE;
+
+  private byte peekType = 0;
+
+  private int peekLength = -1;
+
+  private int lengthBytesNeeded = 0;
+
+  private final int maxElementSize;
+
+  private InputStream in;
+
+  private final LinkedList<InputStream> streamStack;
+
+  private byte[] buffer;
+
+
+
+  /**
+   * Creates a new ASN1 reader whose source is the provided input stream and
+   * having a user defined maximum BER element size.
+   *
+   * @param stream
+   *          The input stream to be read.
+   * @param maxElementSize
+   *          The maximum BER element size, or <code>0</code> to indicate that
+   *          there is no limit.
+   */
+  ASN1InputStreamReader(final InputStream stream, final int maxElementSize)
+  {
+    this.in = stream;
+    this.streamStack = new LinkedList<InputStream>();
+    this.buffer = new byte[512];
+    this.maxElementSize = maxElementSize;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException
+  {
+    // Calling close of SizeLimitInputStream should close the parent
+    // stream.
+    in.close();
+    streamStack.clear();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean elementAvailable() throws IOException
+  {
+    if ((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(false, false))
+    {
+      return false;
+    }
+    if ((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE)
+        && !needFirstLengthByteState(false, false))
+    {
+      return false;
+    }
+    if ((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES)
+        && !needAdditionalLengthBytesState(false, false))
+    {
+      return false;
+    }
+
+    return peekLength <= in.available();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasNextElement() throws IOException
+  {
+    if (!streamStack.isEmpty())
+    {
+      // We are reading a sub sequence. Return true as long as we
+      // haven't exhausted the size limit for the sub sequence sub input
+      // stream.
+      final SizeLimitInputStream subSq = (SizeLimitInputStream) in;
+      return (subSq.getSizeLimit() - subSq.getBytesRead() > 0);
+    }
+
+    return (state != ELEMENT_READ_STATE_NEED_TYPE)
+        || needTypeState(true, false);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int peekLength() throws IOException
+  {
+    peekType();
+
+    switch (state)
+    {
+    case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE:
+      needFirstLengthByteState(true, true);
+      break;
+
+    case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES:
+      needAdditionalLengthBytesState(true, true);
+    }
+
+    return peekLength;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte peekType() throws IOException
+  {
+    if (state == ELEMENT_READ_STATE_NEED_TYPE)
+    {
+      needTypeState(true, true);
+    }
+
+    return peekType;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean readBoolean() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength != 1)
+    {
+      final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    final int readByte = in.read();
+    if (readByte == -1)
+    {
+      final LocalizableMessage message = ERR_ASN1_BOOLEAN_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", peekType,
+          peekLength, String.valueOf(readByte != 0x00)));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return readByte != 0x00;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSequence() throws IOException, IllegalStateException
+  {
+    if (streamStack.isEmpty())
+    {
+      final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED
+          .get();
+      throw new IllegalStateException(message.toString());
+    }
+
+    // Ignore all unused trailing components.
+    final SizeLimitInputStream subSq = (SizeLimitInputStream) in;
+    if (subSq.getSizeLimit() - subSq.getBytesRead() > 0)
+    {
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE))
+      {
+        StaticUtils.DEBUG_LOG.fine(String.format(
+            "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE", subSq
+                .getSizeLimit()
+                - subSq.getBytesRead()));
+      }
+
+      subSq.skip(subSq.getSizeLimit() - subSq.getBytesRead());
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 END SEQUENCE"));
+    }
+
+    in = streamStack.removeFirst();
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readEndSet() throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    readEndSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int readEnumerated() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 4))
+    {
+      final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    // From an implementation point of view, an enumerated value is
+    // equivalent to an integer.
+    return (int) readInteger();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public long readInteger() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if ((peekLength < 1) || (peekLength > 8))
+    {
+      final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    if (peekLength > 4)
+    {
+      long longValue = 0;
+      for (int i = 0; i < peekLength; i++)
+      {
+        final int readByte = in.read();
+        if (readByte == -1)
+        {
+          final LocalizableMessage message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
+              .get(peekLength);
+          throw DecodeException.fatalError(message);
+        }
+        if ((i == 0) && (((byte) readByte) < 0))
+        {
+          longValue = 0xFFFFFFFFFFFFFFFFL;
+        }
+        longValue = (longValue << 8) | (readByte & 0xFF);
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return longValue;
+    }
+    else
+    {
+      int intValue = 0;
+      for (int i = 0; i < peekLength; i++)
+      {
+        final int readByte = in.read();
+        if (readByte == -1)
+        {
+          final LocalizableMessage message = ERR_ASN1_INTEGER_TRUNCATED_VALUE
+              .get(peekLength);
+          throw DecodeException.fatalError(message);
+        }
+        if ((i == 0) && (((byte) readByte) < 0))
+        {
+          intValue = 0xFFFFFFFF;
+        }
+        intValue = (intValue << 8) | (readByte & 0xFF);
+      }
+
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "READ ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", peekType,
+            peekLength, intValue));
+      }
+
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return intValue;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readNull() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    // Make sure that the decoded length is exactly zero byte.
+    if (peekLength != 0)
+    {
+      final LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 NULL(type=0x%x, length=%d)", peekType, peekLength));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString readOctetString() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return ByteString.empty();
+    }
+
+    // Copy the value and construct the element to return.
+    final byte[] value = new byte[peekLength];
+    int bytesNeeded = peekLength;
+    int bytesRead;
+    while (bytesNeeded > 0)
+    {
+      bytesRead = in.read(value, peekLength - bytesNeeded, bytesNeeded);
+      if (bytesRead < 0)
+      {
+        final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
+            .get(peekLength);
+        throw DecodeException.fatalError(message);
+      }
+
+      bytesNeeded -= bytesRead;
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG
+          .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+              peekType, peekLength));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return ByteString.wrap(value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteStringBuilder readOctetString(final ByteStringBuilder builder)
+      throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return builder;
+    }
+
+    // Copy the value and construct the element to return.
+    int bytesNeeded = peekLength;
+    int bytesRead;
+    while (bytesNeeded > 0)
+    {
+      bytesRead = builder.append(in, bytesNeeded);
+      if (bytesRead < 0)
+      {
+        final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
+            .get(peekLength);
+        throw DecodeException.fatalError(message);
+      }
+      bytesNeeded -= bytesRead;
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG
+          .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)",
+              peekType, peekLength));
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    if (peekLength == 0)
+    {
+      state = ELEMENT_READ_STATE_NEED_TYPE;
+      return "";
+    }
+
+    // Resize the temp buffer if needed
+    if (peekLength > buffer.length)
+    {
+      buffer = new byte[peekLength];
+    }
+
+    int bytesNeeded = peekLength;
+    int bytesRead;
+    while (bytesNeeded > 0)
+    {
+      bytesRead = in.read(buffer, peekLength - bytesNeeded, bytesNeeded);
+      if (bytesRead < 0)
+      {
+        final LocalizableMessage message = ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE
+            .get(peekLength);
+        throw DecodeException.fatalError(message);
+      }
+      bytesNeeded -= bytesRead;
+    }
+
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+
+    String str;
+    try
+    {
+      str = new String(buffer, 0, peekLength, "UTF-8");
+    }
+    catch (final Exception e)
+    {
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING))
+      {
+        StaticUtils.DEBUG_LOG.warning("Unable to decode ASN.1 OCTETSTRING "
+            + "bytes as UTF-8 string: " + e.toString());
+      }
+
+      str = new String(buffer, 0, peekLength);
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 OCTETSTRING(type=0x%x, length=%d, value=%s)", peekType,
+          peekLength, str));
+    }
+
+    return str;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSequence() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    final SizeLimitInputStream subStream = new SizeLimitInputStream(in,
+        peekLength);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "READ ASN.1 START SEQUENCE(type=0x%x, length=%d)", peekType,
+          peekLength));
+    }
+
+    streamStack.addFirst(in);
+    in = subStream;
+
+    // Reset the state
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSet() throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    readStartSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Reader skipElement() throws IOException
+  {
+    // Read the header if haven't done so already
+    peekLength();
+
+    final long bytesSkipped = in.skip(peekLength);
+    if (bytesSkipped != peekLength)
+    {
+      final LocalizableMessage message = ERR_ASN1_SKIP_TRUNCATED_VALUE
+          .get(peekLength);
+      throw DecodeException.fatalError(message);
+    }
+    state = ELEMENT_READ_STATE_NEED_TYPE;
+    return this;
+  }
+
+
+
+  /**
+   * Internal helper method reading the additional ASN.1 length bytes and
+   * transition to the next state if successful.
+   *
+   * @param isBlocking
+   *          <code>true</code> to block if the type byte is not available or
+   *          <code>false</code> to check for availability first.
+   * @param throwEofException
+   *          <code>true</code> to throw an exception when an EOF is encountered
+   *          or <code>false</code> to return false.
+   * @return <code>true</code> if the length bytes was successfully read.
+   * @throws IOException
+   *           If an error occurs while reading from the stream.
+   */
+  private boolean needAdditionalLengthBytesState(final boolean isBlocking,
+      final boolean throwEofException) throws IOException
+  {
+    if (!isBlocking && (in.available() < lengthBytesNeeded))
+    {
+      return false;
+    }
+
+    int readByte;
+    while (lengthBytesNeeded > 0)
+    {
+      readByte = in.read();
+      if (readByte == -1)
+      {
+        state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+        if (throwEofException)
+        {
+          final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
+              .get(lengthBytesNeeded);
+          throw DecodeException.fatalError(message);
+        }
+        return false;
+      }
+      peekLength = (peekLength << 8) | (readByte & 0xFF);
+      lengthBytesNeeded--;
+    }
+
+    // Make sure that the element is not larger than the maximum allowed
+    // message size.
+    if ((maxElementSize > 0) && (peekLength > maxElementSize))
+    {
+      final LocalizableMessage message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
+          .get(peekLength, maxElementSize);
+      throw DecodeException.fatalError(message);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+
+
+  /**
+   * Internal helper method reading the first length bytes and transition to the
+   * next state if successful.
+   *
+   * @param isBlocking
+   *          <code>true</code> to block if the type byte is not available or
+   *          <code>false</code> to check for availability first.
+   * @param throwEofException
+   *          <code>true</code> to throw an exception when an EOF is encountered
+   *          or <code>false</code> to return false.
+   * @return <code>true</code> if the length bytes was successfully read
+   * @throws IOException
+   *           If an error occurs while reading from the stream.
+   */
+  private boolean needFirstLengthByteState(final boolean isBlocking,
+      final boolean throwEofException) throws IOException
+  {
+    if (!isBlocking && (in.available() <= 0))
+    {
+      return false;
+    }
+
+    int readByte = in.read();
+    if (readByte == -1)
+    {
+      if (throwEofException)
+      {
+        final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get();
+        throw DecodeException.fatalError(message);
+      }
+      return false;
+    }
+    peekLength = (readByte & 0x7F);
+    if (peekLength != readByte)
+    {
+      lengthBytesNeeded = peekLength;
+      if (lengthBytesNeeded > 4)
+      {
+        final LocalizableMessage message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES
+            .get(lengthBytesNeeded);
+        throw DecodeException.fatalError(message);
+      }
+      peekLength = 0x00;
+
+      if (!isBlocking && (in.available() < lengthBytesNeeded))
+      {
+        state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+        return false;
+      }
+
+      while (lengthBytesNeeded > 0)
+      {
+        readByte = in.read();
+        if (readByte == -1)
+        {
+          state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES;
+          if (throwEofException)
+          {
+            final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTES
+                .get(lengthBytesNeeded);
+            throw DecodeException.fatalError(message);
+          }
+          return false;
+        }
+        peekLength = (peekLength << 8) | (readByte & 0xFF);
+        lengthBytesNeeded--;
+      }
+    }
+
+    // Make sure that the element is not larger than the maximum allowed
+    // message size.
+    if ((maxElementSize > 0) && (peekLength > maxElementSize))
+    {
+      final LocalizableMessage message = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED
+          .get(peekLength, maxElementSize);
+      throw DecodeException.fatalError(message);
+    }
+    state = ELEMENT_READ_STATE_NEED_VALUE_BYTES;
+    return true;
+  }
+
+
+
+  /**
+   * Internal helper method reading the ASN.1 type byte and transition to the
+   * next state if successful.
+   *
+   * @param isBlocking
+   *          <code>true</code> to block if the type byte is not available or
+   *          <code>false</code> to check for availability first.
+   * @param throwEofException
+   *          <code>true</code> to throw an exception when an EOF is encountered
+   *          or <code>false</code> to return false.
+   * @return <code>true</code> if the type byte was successfully read
+   * @throws IOException
+   *           If an error occurs while reading from the stream.
+   */
+  private boolean needTypeState(final boolean isBlocking,
+      final boolean throwEofException) throws IOException
+  {
+    // Read just the type.
+    if (!isBlocking && (in.available() <= 0))
+    {
+      return false;
+    }
+
+    final int type = in.read();
+    if (type == -1)
+    {
+      if (throwEofException)
+      {
+        final LocalizableMessage message = ERR_ASN1_TRUCATED_TYPE_BYTE.get();
+        throw DecodeException.fatalError(message);
+      }
+      return false;
+    }
+
+    peekType = (byte) type;
+    state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE;
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1OutputStreamWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1OutputStreamWriter.java
new file mode 100644
index 0000000..a61e6a1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1OutputStreamWriter.java
@@ -0,0 +1,562 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED;
+import static org.opends.sdk.asn1.ASN1Constants.BOOLEAN_VALUE_FALSE;
+import static org.opends.sdk.asn1.ASN1Constants.BOOLEAN_VALUE_TRUE;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.logging.Level;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.ByteSequenceOutputStream;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An ASN1Writer implementation that outputs to an outputstream.
+ */
+final class ASN1OutputStreamWriter extends AbstractASN1Writer implements
+    ASN1Writer
+{
+  private final OutputStream rootStream;
+  private OutputStream out;
+  private final ArrayList<ByteSequenceOutputStream> streamStack;
+  private int stackDepth;
+
+
+
+  /**
+   * Creates a new ASN.1 output stream reader.
+   *
+   * @param stream
+   *          The underlying output stream.
+   */
+  ASN1OutputStreamWriter(final OutputStream stream)
+  {
+    this.out = stream;
+    this.rootStream = stream;
+    this.streamStack = new ArrayList<ByteSequenceOutputStream>();
+    this.stackDepth = -1;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException
+  {
+    while (stackDepth >= 0)
+    {
+      writeEndSequence();
+    }
+    rootStream.flush();
+
+    streamStack.clear();
+    rootStream.close();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void flush() throws IOException
+  {
+    rootStream.flush();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeBoolean(final byte type, final boolean booleanValue)
+      throws IOException
+  {
+    out.write(type);
+    writeLength(1);
+    out.write(booleanValue ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", type, 1,
+          String.valueOf(booleanValue)));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSequence() throws IOException,
+      IllegalStateException
+  {
+    if (stackDepth < 0)
+    {
+      final LocalizableMessage message = ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED
+          .get();
+      throw new IllegalStateException(message.toString());
+    }
+
+    final ByteSequenceOutputStream childStream = streamStack.get(stackDepth);
+
+    // Decrement the stack depth and get the parent stream
+    --stackDepth;
+
+    final OutputStream parentStream = stackDepth < 0 ? rootStream : streamStack
+        .get(stackDepth);
+
+    // Switch to parent stream and reset the sub-stream
+    out = parentStream;
+
+    // Write the length and contents of the sub-stream
+    writeLength(childStream.length());
+    childStream.writeTo(parentStream);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 END SEQUENCE(length=%d)", childStream.length()));
+    }
+
+    childStream.reset();
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEndSet() throws IOException
+  {
+    return writeEndSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEnumerated(final byte type, final int intValue)
+      throws IOException
+  {
+    return writeInteger(type, intValue);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(final byte type, final int intValue)
+      throws IOException
+  {
+    out.write(type);
+    if (((intValue < 0) && ((intValue & 0xFFFFFF80) == 0xFFFFFF80))
+        || ((intValue & 0x0000007F) == intValue))
+    {
+      writeLength(1);
+      out.write((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1,
+            intValue));
+      }
+    }
+    else if (((intValue < 0) && ((intValue & 0xFFFF8000) == 0xFFFF8000))
+        || ((intValue & 0x00007FFF) == intValue))
+    {
+      writeLength(2);
+      out.write((byte) ((intValue >> 8) & 0xFF));
+      out.write((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2,
+            intValue));
+      }
+    }
+    else if (((intValue < 0) && ((intValue & 0xFF800000) == 0xFF800000))
+        || ((intValue & 0x007FFFFF) == intValue))
+    {
+      writeLength(3);
+      out.write((byte) ((intValue >> 16) & 0xFF));
+      out.write((byte) ((intValue >> 8) & 0xFF));
+      out.write((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3,
+            intValue));
+      }
+    }
+    else
+    {
+      writeLength(4);
+      out.write((byte) ((intValue >> 24) & 0xFF));
+      out.write((byte) ((intValue >> 16) & 0xFF));
+      out.write((byte) ((intValue >> 8) & 0xFF));
+      out.write((byte) (intValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4,
+            intValue));
+      }
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(final byte type, final long longValue)
+      throws IOException
+  {
+    out.write(type);
+    if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L))
+        || ((longValue & 0x000000000000007FL) == longValue))
+    {
+      writeLength(1);
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L))
+        || ((longValue & 0x0000000000007FFFL) == longValue))
+    {
+      writeLength(2);
+      out.write((byte) ((longValue >> 8) & 0xFF));
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L))
+        || ((longValue & 0x00000000007FFFFFL) == longValue))
+    {
+      writeLength(3);
+      out.write((byte) ((longValue >> 16) & 0xFF));
+      out.write((byte) ((longValue >> 8) & 0xFF));
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L))
+        || ((longValue & 0x000000007FFFFFFFL) == longValue))
+    {
+      writeLength(4);
+      out.write((byte) ((longValue >> 24) & 0xFF));
+      out.write((byte) ((longValue >> 16) & 0xFF));
+      out.write((byte) ((longValue >> 8) & 0xFF));
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L))
+        || ((longValue & 0x0000007FFFFFFFFFL) == longValue))
+    {
+      writeLength(5);
+      out.write((byte) ((longValue >> 32) & 0xFF));
+      out.write((byte) ((longValue >> 24) & 0xFF));
+      out.write((byte) ((longValue >> 16) & 0xFF));
+      out.write((byte) ((longValue >> 8) & 0xFF));
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 5,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L))
+        || ((longValue & 0x00007FFFFFFFFFFFL) == longValue))
+    {
+      writeLength(6);
+      out.write((byte) ((longValue >> 40) & 0xFF));
+      out.write((byte) ((longValue >> 32) & 0xFF));
+      out.write((byte) ((longValue >> 24) & 0xFF));
+      out.write((byte) ((longValue >> 16) & 0xFF));
+      out.write((byte) ((longValue >> 8) & 0xFF));
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 6,
+            longValue));
+      }
+    }
+    else if (((longValue < 0) && ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L))
+        || ((longValue & 0x007FFFFFFFFFFFFFL) == longValue))
+    {
+      writeLength(7);
+      out.write((byte) ((longValue >> 48) & 0xFF));
+      out.write((byte) ((longValue >> 40) & 0xFF));
+      out.write((byte) ((longValue >> 32) & 0xFF));
+      out.write((byte) ((longValue >> 24) & 0xFF));
+      out.write((byte) ((longValue >> 16) & 0xFF));
+      out.write((byte) ((longValue >> 8) & 0xFF));
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 7,
+            longValue));
+      }
+    }
+    else
+    {
+      writeLength(8);
+      out.write((byte) ((longValue >> 56) & 0xFF));
+      out.write((byte) ((longValue >> 48) & 0xFF));
+      out.write((byte) ((longValue >> 40) & 0xFF));
+      out.write((byte) ((longValue >> 32) & 0xFF));
+      out.write((byte) ((longValue >> 24) & 0xFF));
+      out.write((byte) ((longValue >> 16) & 0xFF));
+      out.write((byte) ((longValue >> 8) & 0xFF));
+      out.write((byte) (longValue & 0xFF));
+      if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+      {
+        StaticUtils.DEBUG_LOG.finest(String.format(
+            "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 8,
+            longValue));
+      }
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeNull(final byte type) throws IOException
+  {
+    out.write(type);
+    writeLength(0);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 NULL(type=0x%x, length=%d)", type, 0));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final byte type, final byte[] value,
+      final int offset, final int length) throws IOException
+  {
+    out.write(type);
+    writeLength(length);
+    out.write(value, offset, length);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, length));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final byte type, final ByteSequence value)
+      throws IOException
+  {
+    out.write(type);
+    writeLength(value.length());
+    value.copyTo(out);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String
+          .format("WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, value
+              .length()));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final byte type, final String value)
+      throws IOException
+  {
+    out.write(type);
+
+    if (value == null)
+    {
+      writeLength(0);
+      return this;
+    }
+
+    final byte[] bytes = StaticUtils.getBytes(value);
+    writeLength(bytes.length);
+    out.write(bytes);
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d, " + "value=%s)", type,
+          bytes.length, value));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSequence(final byte type) throws IOException
+  {
+    // Write the type in current stream switch to next sub-stream
+    out.write(type);
+
+    // Increment the stack depth and get the sub-stream from the stack
+    ++stackDepth;
+
+    // Make sure we have a cached sub-stream at this depth
+    if (stackDepth >= streamStack.size())
+    {
+      final ByteSequenceOutputStream subStream = new ByteSequenceOutputStream(
+          new ByteStringBuilder());
+      streamStack.add(subStream);
+      out = subStream;
+    }
+    else
+    {
+      out = streamStack.get(stackDepth);
+    }
+
+    if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST))
+    {
+      StaticUtils.DEBUG_LOG.finest(String.format(
+          "WRITE ASN.1 START SEQUENCE(type=0x%x)", type));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSet(final byte type) throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    return writeStartSequence(type);
+  }
+
+
+
+  /**
+   * Writes the provided value for use as the length of an ASN.1 element.
+   *
+   * @param length
+   *          The length to encode for use in an ASN.1 element.
+   * @throws IOException
+   *           if an error occurs while writing.
+   */
+  private void writeLength(final int length) throws IOException
+  {
+    if (length < 128)
+    {
+      out.write((byte) length);
+    }
+    else if ((length & 0x000000FF) == length)
+    {
+      out.write((byte) 0x81);
+      out.write((byte) (length & 0xFF));
+    }
+    else if ((length & 0x0000FFFF) == length)
+    {
+      out.write((byte) 0x82);
+      out.write((byte) ((length >> 8) & 0xFF));
+      out.write((byte) (length & 0xFF));
+    }
+    else if ((length & 0x00FFFFFF) == length)
+    {
+      out.write((byte) 0x83);
+      out.write((byte) ((length >> 16) & 0xFF));
+      out.write((byte) ((length >> 8) & 0xFF));
+      out.write((byte) (length & 0xFF));
+    }
+    else
+    {
+      out.write((byte) 0x84);
+      out.write((byte) ((length >> 24) & 0xFF));
+      out.write((byte) ((length >> 16) & 0xFF));
+      out.write((byte) ((length >> 8) & 0xFF));
+      out.write((byte) (length & 0xFF));
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Reader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Reader.java
new file mode 100644
index 0000000..025270d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Reader.java
@@ -0,0 +1,431 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.asn1;
+
+
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * An interface for decoding ASN.1 elements from a data source.
+ * <p>
+ * Methods for creating {@link ASN1Reader}s are provided in the {@link ASN1}
+ * class.
+ */
+public interface ASN1Reader extends Closeable
+{
+
+  /**
+   * Closes this ASN.1 reader.
+   *
+   * @throws IOException
+   *           If an error occurs while closing.
+   */
+  void close() throws IOException;
+
+
+
+  /**
+   * Indicates whether or not the next element can be read without blocking.
+   *
+   * @return {@code true} if a complete element is available or {@code false}
+   *         otherwise.
+   * @throws DecodeException
+   *           If the available data was not valid ASN.1.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  boolean elementAvailable() throws DecodeException, IOException;
+
+
+
+  /**
+   * Indicates whether or not the current stream, sequence, or set contains
+   * another element. Note that this method may return {@code true} even if a
+   * previous call to {@link #elementAvailable} returned {@code false},
+   * indicating that the current set or sequence contains another element but an
+   * attempt to read that element may block. This method will block if there is
+   * not enough data available to make the determination (typically only the
+   * next element's type is required).
+   *
+   * @return {@code true} if the current stream, sequence, or set contains
+   *         another element, or {@code false} if the end of the stream,
+   *         sequence, or set has been reached.
+   * @throws DecodeException
+   *           If the available data was not valid ASN.1.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  boolean hasNextElement() throws DecodeException, IOException;
+
+
+
+  /**
+   * Returns the data length of the next element without actually reading it.
+   *
+   * @return The data length of the next element, or {@code -1} if the end of
+   *         the stream, sequence, or set has been reached.
+   * @throws DecodeException
+   *           If the available data was not valid ASN.1.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  int peekLength() throws DecodeException, IOException;
+
+
+
+  /**
+   * Returns the type of the next element without actually reading it.
+   *
+   * @return The type of the next element, or {@code -1} if the end of the
+   *         stream, sequence, or set has been reached.
+   * @throws DecodeException
+   *           If the available data was not valid ASN.1.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  byte peekType() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a boolean having the Universal Boolean ASN.1 type
+   * tag.
+   *
+   * @return The decoded boolean value.
+   * @throws DecodeException
+   *           If the element cannot be decoded as a boolean.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  boolean readBoolean() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a boolean having the provided type tag.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @return The decoded boolean value.
+   * @throws DecodeException
+   *           If the element cannot be decoded as a boolean.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  boolean readBoolean(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Finishes reading a sequence and discards any unread elements.
+   *
+   * @throws DecodeException
+   *           If an error occurs while advancing to the end of the sequence.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   * @throws IllegalStateException
+   *           If there is no sequence being read.
+   */
+  void readEndSequence() throws DecodeException, IOException,
+      IllegalStateException;
+
+
+
+  /**
+   * Finishes reading a set and discards any unread elements.
+   *
+   * @throws DecodeException
+   *           If an error occurs while advancing to the end of the set.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   * @throws IllegalStateException
+   *           If there is no set being read.
+   */
+  void readEndSet() throws DecodeException, IOException, IllegalStateException;
+
+
+
+  /**
+   * Reads the next element as an enumerated having the Universal Enumerated
+   * ASN.1 type tag.
+   *
+   * @return The decoded enumerated value.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an enumerated value.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  int readEnumerated() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an enumerated having the provided type tag.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @return The decoded enumerated value.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an enumerated value.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  int readEnumerated(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an integer having the Universal Integer ASN.1
+   * type tag.
+   *
+   * @return The decoded integer value.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an integer.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  long readInteger() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an integer having the provided type tag.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @return The decoded integer value.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an integer.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  long readInteger(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a null element having the Universal Null ASN.1
+   * type tag.
+   *
+   * @throws DecodeException
+   *           If the element cannot be decoded as a null element.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  void readNull() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a null element having the provided type tag.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @throws DecodeException
+   *           If the element cannot be decoded as a null element.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  void readNull(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an octet string having the Universal Octet String
+   * ASN.1 type tag.
+   *
+   * @return The decoded octet string represented using a {@link ByteString}.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an octet string.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  ByteString readOctetString() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an octet string having the provided type tag.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @return The decoded octet string represented using a {@link ByteString}.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an octet string.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  ByteString readOctetString(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an octet string having the provided type tag and
+   * appends it to the provided {@link ByteStringBuilder}.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @param builder
+   *          The {@link ByteStringBuilder} to append the octet string to.
+   * @return A reference to {@code builder}.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an octet string.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  ByteStringBuilder readOctetString(byte type, ByteStringBuilder builder)
+      throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an octet string having the Universal Octet String
+   * ASN.1 type tag and appends it to the provided {@link ByteStringBuilder}.
+   *
+   * @param builder
+   *          The {@link ByteStringBuilder} to append the octet string to.
+   * @return A reference to {@code builder}.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an octet string.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  ByteStringBuilder readOctetString(ByteStringBuilder builder)
+      throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an octet string having the Universal Octet String
+   * ASN.1 type tag and decodes the value as a UTF-8 encoded string.
+   *
+   * @return The decoded octet string as a UTF-8 encoded string.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an octet string.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  String readOctetStringAsString() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as an octet string having the provided type tag and
+   * decodes the value as a UTF-8 encoded string.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @return The decoded octet string as a UTF-8 encoded string.
+   * @throws DecodeException
+   *           If the element cannot be decoded as an octet string.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  String readOctetStringAsString(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a sequence having the Universal Sequence ASN.1
+   * type tag. All further reads will read the elements in the sequence until
+   * {@link #readEndSequence()} is called.
+   *
+   * @throws DecodeException
+   *           If the element cannot be decoded as a sequence.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  void readStartSequence() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a sequence having the provided type tag. All
+   * further reads will read the elements in the sequence until
+   * {@link #readEndSequence()} is called.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @throws DecodeException
+   *           If the element cannot be decoded as a sequence.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  void readStartSequence(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a set having the Universal Set ASN.1 type tag.
+   * All further reads will read the elements in the set until
+   * {@link #readEndSet()} is called.
+   *
+   * @throws DecodeException
+   *           If the element cannot be decoded as a set.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  void readStartSet() throws DecodeException, IOException;
+
+
+
+  /**
+   * Reads the next element as a set having the provided type tag. All further
+   * reads will read the elements in the set until {@link #readEndSet()} is
+   * called.
+   *
+   * @param type
+   *          The expected type tag of the element.
+   * @throws DecodeException
+   *           If the element cannot be decoded as a set.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  void readStartSet(byte type) throws DecodeException, IOException;
+
+
+
+  /**
+   * Skips the next element without decoding it.
+   *
+   * @return A reference to this ASN.1 reader.
+   * @throws DecodeException
+   *           If the next element could not be skipped.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  ASN1Reader skipElement() throws DecodeException, IOException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Writer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Writer.java
new file mode 100644
index 0000000..b992ab6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/ASN1Writer.java
@@ -0,0 +1,391 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+
+import org.opends.sdk.ByteSequence;
+
+
+
+/**
+ * An interface for encoding ASN.1 elements to a data source.
+ * <p>
+ * Methods for creating {@link ASN1Writer}s are provided in the {@link ASN1}
+ * class.
+ */
+public interface ASN1Writer extends Closeable, Flushable
+{
+
+  /**
+   * Closes this ASN.1 writer, flushing it first. Closing a previously closed
+   * ASN.1 writer has no effect. Any unfinished sequences and/or sets will be
+   * ended.
+   *
+   * @throws IOException
+   *           If an error occurs while closing.
+   */
+  void close() throws IOException;
+
+
+
+  /**
+   * Flushes this ASN.1 writer so that any buffered elements are written
+   * immediately to their intended destination. Then, if that destination is
+   * another byte stream, flush it. Thus one {@code flush()} invocation will
+   * flush all the buffers in a chain of streams.
+   * <p>
+   * If the intended destination of this stream is an abstraction provided by
+   * the underlying operating system, for example a file, then flushing the
+   * stream guarantees only that bytes previously written to the stream are
+   * passed to the operating system for writing; it does not guarantee that they
+   * are actually written to a physical device such as a disk drive.
+   *
+   * @throws IOException
+   *           If an error occurs while flushing.
+   */
+  void flush() throws IOException;
+
+
+
+  /**
+   * Writes a boolean element using the Universal Boolean ASN.1 type tag.
+   *
+   * @param value
+   *          The boolean value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeBoolean(boolean value) throws IOException;
+
+
+
+  /**
+   * Writes a boolean element using the provided type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @param value
+   *          The boolean value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeBoolean(byte type, boolean value) throws IOException;
+
+
+
+  /**
+   * Finishes writing a sequence element.
+   *
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   * @throws IllegalStateException
+   *           If there is no sequence being written.
+   */
+  ASN1Writer writeEndSequence() throws IOException, IllegalStateException;
+
+
+
+  /**
+   * Finishes writing a set element.
+   *
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   * @throws IllegalStateException
+   *           If there is no set being written, IllegalStateException.
+   */
+  ASN1Writer writeEndSet() throws IOException, IllegalStateException;
+
+
+
+  /**
+   * Writes an enumerated element using the provided type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @param value
+   *          The enumerated value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeEnumerated(byte type, int value) throws IOException;
+
+
+
+  /**
+   * Writes an enumerated element using the Universal Enumerated ASN.1 type tag.
+   *
+   * @param value
+   *          The enumerated value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeEnumerated(int value) throws IOException;
+
+
+
+  /**
+   * Writes an integer element using the provided type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @param value
+   *          The integer value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeInteger(byte type, int value) throws IOException;
+
+
+
+  /**
+   * Writes an integer element using the provided type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @param value
+   *          The integer value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeInteger(byte type, long value) throws IOException;
+
+
+
+  /**
+   * Writes an integer element using the Universal Integer ASN.1 type tag.
+   *
+   * @param value
+   *          The integer value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeInteger(int value) throws IOException;
+
+
+
+  /**
+   * Writes an integer element using the Universal Integer ASN.1 type tag.
+   *
+   * @param value
+   *          The integer value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeInteger(long value) throws IOException;
+
+
+
+  /**
+   * Writes a null element using the Universal Null ASN.1 type tag.
+   *
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeNull() throws IOException;
+
+
+
+  /**
+   * Writes a null element using the provided type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeNull(byte type) throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the provided type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @param value
+   *          The byte array containing the octet string data.
+   * @param offset
+   *          The offset in the byte array.
+   * @param length
+   *          The number of bytes to write.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeOctetString(byte type, byte[] value, int offset, int length)
+      throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the provided type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @param value
+   *          The octet string value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeOctetString(byte type, ByteSequence value) throws IOException;
+
+
+
+  /**
+   * Writes a string as a UTF-8 encoded octet string element using the provided
+   * type tag.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @param value
+   *          The string to be written as a UTF-8 encoded octet string.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeOctetString(byte type, String value) throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the Universal Octet String ASN.1 type
+   * tag.
+   *
+   * @param value
+   *          The byte array containing the octet string data.
+   * @param offset
+   *          The offset in the byte array.
+   * @param length
+   *          The number of bytes to write.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeOctetString(byte[] value, int offset, int length)
+      throws IOException;
+
+
+
+  /**
+   * Writes an octet string element using the Universal Octet String ASN.1 type
+   * tag.
+   *
+   * @param value
+   *          The octet string value.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeOctetString(ByteSequence value) throws IOException;
+
+
+
+  /**
+   * Writes a string as a UTF-8 encoded octet string element using the Universal
+   * Octet String ASN.1 type tag.
+   *
+   * @param value
+   *          The string to be written as a UTF-8 encoded octet string.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeOctetString(String value) throws IOException;
+
+
+
+  /**
+   * Writes a sequence element using the Universal Sequence ASN.1 type tag. All
+   * further writes will append elements to the sequence until
+   * {@link #writeEndSequence} is called.
+   *
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeStartSequence() throws IOException;
+
+
+
+  /**
+   * Writes a sequence element using the provided type tag. All further writes
+   * will append elements to the sequence until {@link #writeEndSequence} is
+   * called.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeStartSequence(byte type) throws IOException;
+
+
+
+  /**
+   * Writes a set element using the Universal Set ASN.1 type tag. All further
+   * writes will append elements to the set until {@link #writeEndSet} is
+   * called.
+   *
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeStartSet() throws IOException;
+
+
+
+  /**
+   * Writes a set element using the provided type tag. All further writes will
+   * append elements to the set until {@link #writeEndSet} is called.
+   *
+   * @param type
+   *          The type tag of the element.
+   * @return A reference to this ASN.1 writer.
+   * @throws IOException
+   *           If an error occurs while writing the element.
+   */
+  ASN1Writer writeStartSet(byte type) throws IOException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Reader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Reader.java
new file mode 100644
index 0000000..970640d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Reader.java
@@ -0,0 +1,210 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2008 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.asn1;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ASN1_UNEXPECTED_TAG;
+import static org.opends.sdk.asn1.ASN1Constants.*;
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * An abstract {@code ASN1Reader} which can be used as the basis for
+ * implementing new ASN1 reader implementations.
+ */
+public abstract class AbstractASN1Reader implements ASN1Reader
+{
+  /**
+   * Creates a new abstract ASN.1 reader.
+   */
+  protected AbstractASN1Reader()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean readBoolean(byte type) throws IOException
+  {
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_BOOLEAN_TYPE;
+    }
+    checkType(type);
+    return readBoolean();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int readEnumerated(byte type) throws IOException
+  {
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_ENUMERATED_TYPE;
+    }
+    checkType(type);
+    return readEnumerated();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public long readInteger(byte type) throws IOException
+  {
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_INTEGER_TYPE;
+    }
+    checkType(type);
+    return readInteger();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readNull(byte type) throws IOException
+  {
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_NULL_TYPE;
+    }
+    checkType(type);
+    readNull();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString readOctetString(byte type) throws IOException
+  {
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_OCTET_STRING_TYPE;
+    }
+    checkType(type);
+    return readOctetString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteStringBuilder readOctetString(byte type,
+      final ByteStringBuilder builder) throws IOException
+  {
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_OCTET_STRING_TYPE;
+    }
+    checkType(type);
+    readOctetString(builder);
+    return builder;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String readOctetStringAsString(byte type) throws IOException
+  {
+    // We could cache the UTF-8 CharSet if performance proves to be an
+    // issue.
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_OCTET_STRING_TYPE;
+    }
+    checkType(type);
+    return readOctetStringAsString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSequence(byte type) throws IOException
+  {
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_SEQUENCE_TYPE;
+    }
+    checkType(type);
+    readStartSequence();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void readStartSet(byte type) throws IOException
+  {
+    // From an implementation point of view, a set is equivalent to a
+    // sequence.
+    if (type == 0x00)
+    {
+      type = UNIVERSAL_SET_TYPE;
+    }
+    checkType(type);
+    readStartSet();
+  }
+
+
+
+  private void checkType(final byte expectedType) throws IOException
+  {
+    if (peekType() != expectedType)
+    {
+      final LocalizableMessage message = ERR_ASN1_UNEXPECTED_TAG.get(
+          expectedType, peekType());
+      throw DecodeException.fatalError(message);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Writer.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Writer.java
new file mode 100644
index 0000000..892a149
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/AbstractASN1Writer.java
@@ -0,0 +1,156 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+import static org.opends.sdk.asn1.ASN1Constants.*;
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteSequence;
+
+
+
+/**
+ * An abstract {@code ASN1Writer} which can be used as the basis for
+ * implementing new ASN1 writer implementations.
+ */
+public abstract class AbstractASN1Writer implements ASN1Writer
+{
+
+  /**
+   * Creates a new abstract ASN.1 writer.
+   */
+  protected AbstractASN1Writer()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeBoolean(final boolean value) throws IOException
+  {
+    return writeBoolean(UNIVERSAL_BOOLEAN_TYPE, value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeEnumerated(final int value) throws IOException
+  {
+    return writeEnumerated(UNIVERSAL_ENUMERATED_TYPE, value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(final int value) throws IOException
+  {
+    return writeInteger(UNIVERSAL_INTEGER_TYPE, value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeInteger(final long value) throws IOException
+  {
+    return writeInteger(UNIVERSAL_INTEGER_TYPE, value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeNull() throws IOException
+  {
+    return writeNull(UNIVERSAL_NULL_TYPE);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final byte[] value, final int offset,
+      final int length) throws IOException
+  {
+    return writeOctetString(UNIVERSAL_OCTET_STRING_TYPE, value, offset, length);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final ByteSequence value)
+      throws IOException
+  {
+    return writeOctetString(UNIVERSAL_OCTET_STRING_TYPE, value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeOctetString(final String value) throws IOException
+  {
+    return writeOctetString(UNIVERSAL_OCTET_STRING_TYPE, value);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSequence() throws IOException
+  {
+    return writeStartSequence(UNIVERSAL_SEQUENCE_TYPE);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ASN1Writer writeStartSet() throws IOException
+  {
+    return writeStartSet(UNIVERSAL_SET_TYPE);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/package-info.java
new file mode 100755
index 0000000..f8c61ef
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/asn1/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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes and interfaces for encoding and decoding ASN.1 data streams.
+ * <p>
+ * Note that this particular implementation is limited to the subset of elements
+ * that are typically used by LDAP clients. As such, it does not include all
+ * ASN.1 element types, particularly elements like OIDs, bit strings, and
+ * timestamp values.
+ */
+package org.opends.sdk.asn1;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AssertionRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AssertionRequestControl.java
new file mode 100644
index 0000000..2571fda
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AssertionRequestControl.java
@@ -0,0 +1,242 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_LDAPASSERT_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_LDAPASSERT_INVALID_CONTROL_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_LDAPASSERT_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.ldap.LDAPUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The assertion request control as defined in RFC 4528. The Assertion control
+ * allows a client to specify that a directory operation should only be
+ * processed if an assertion applied to the target entry of the operation is
+ * true. It can be used to construct "test and set", "test and clear", and other
+ * conditional operations.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4528">RFC 4528 - Lightweight
+ *      Directory Access Protocol (LDAP) Assertion Control </a>
+ */
+public final class AssertionRequestControl implements Control
+{
+  /**
+   * The IANA-assigned OID for the LDAP assertion request control.
+   */
+  public static final String OID = "1.3.6.1.1.12";
+
+  /**
+   * A decoder which can be used for decoding the LDAP assertion request
+   * control.
+   */
+  public static final ControlDecoder<AssertionRequestControl> DECODER =
+    new ControlDecoder<AssertionRequestControl>()
+  {
+
+    public AssertionRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof AssertionRequestControl)
+      {
+        return (AssertionRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_LDAPASSERT_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_LDAPASSERT_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      Filter filter;
+      try
+      {
+        filter = LDAPUtils.decodeFilter(reader);
+      }
+      catch (final IOException e)
+      {
+        throw DecodeException.error(ERR_LDAPASSERT_INVALID_CONTROL_VALUE
+            .get(getExceptionMessage(e)), e);
+      }
+
+      return new AssertionRequestControl(control.isCritical(), filter);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new assertion using the provided criticality and assertion
+   * filter.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param filter
+   *          The assertion filter.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code filter} was {@code null}.
+   */
+  public static AssertionRequestControl newControl(final boolean isCritical,
+      final Filter filter) throws NullPointerException
+  {
+    return new AssertionRequestControl(isCritical, filter);
+  }
+
+
+
+  // The assertion filter.
+  private final Filter filter;
+
+  private final boolean isCritical;
+
+
+
+  // Prevent direct instantiation.
+  private AssertionRequestControl(final boolean isCritical, final Filter filter)
+  {
+    Validator.ensureNotNull(filter);
+    this.isCritical = isCritical;
+    this.filter = filter;
+  }
+
+
+
+  /**
+   * Returns the assertion filter.
+   *
+   * @return The assertion filter.
+   */
+  public Filter getFilter()
+  {
+    return filter;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      LDAPUtils.encodeFilter(writer, filter);
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AssertionRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", filter=\"");
+    builder.append(filter.toString());
+    builder.append("\")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityRequestControl.java
new file mode 100644
index 0000000..532684d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityRequestControl.java
@@ -0,0 +1,199 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_AUTHZIDREQ_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_AUTHZIDREQ_CONTROL_HAS_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The authorization request control as defined in RFC 3829. The authorization
+ * identity control extends the Lightweight Directory Access Protocol (LDAP)
+ * bind operation with a mechanism for requesting and returning the
+ * authorization identity it establishes.
+ *
+ * @see AuthorizationIdentityResponseControl
+ * @see org.opends.sdk.requests.WhoAmIExtendedRequest
+ * @see <a href="http://tools.ietf.org/html/rfc3829">RFC 3829 - Lightweight
+ *      Directory Access Protocol (LDAP) Authorization Identity Request and
+ *      Response Controls </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4532">RFC 4532 - Lightweight
+ *      Directory Access Protocol (LDAP) "Who am I?" Operation </a>
+ */
+public final class AuthorizationIdentityRequestControl implements Control
+{
+  /**
+   * The OID for the authorization identity request control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.16";
+
+  private final boolean isCritical;
+
+  private static final AuthorizationIdentityRequestControl CRITICAL_INSTANCE =
+    new AuthorizationIdentityRequestControl(true);
+
+  private static final AuthorizationIdentityRequestControl
+    NONCRITICAL_INSTANCE= new AuthorizationIdentityRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the authorization identity request
+   * control.
+   */
+  public static final ControlDecoder<AuthorizationIdentityRequestControl>
+    DECODER = new ControlDecoder<AuthorizationIdentityRequestControl>()
+  {
+
+    public AuthorizationIdentityRequestControl decodeControl(
+        final Control control, final DecodeOptions options)
+        throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof AuthorizationIdentityRequestControl)
+      {
+        return (AuthorizationIdentityRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_AUTHZIDREQ_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_AUTHZIDREQ_CONTROL_HAS_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new authorization identity request control having the provided
+   * criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static AuthorizationIdentityRequestControl newControl(
+      final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  // Prevent direct instantiation.
+  private AuthorizationIdentityRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AuthorizationIdentityRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityResponseControl.java
new file mode 100644
index 0000000..b4de1fa
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/AuthorizationIdentityResponseControl.java
@@ -0,0 +1,226 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_AUTHZIDRESP_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_AUTHZIDRESP_NO_CONTROL_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The authorization response control as defined in RFC 3829. The authorization
+ * identity control extends the Lightweight Directory Access Protocol (LDAP)
+ * bind operation with a mechanism for requesting and returning the
+ * authorization identity it establishes.
+ * <p>
+ * The authorization identity is specified using an authorization ID, or {@code
+ * authzId}, as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see AuthorizationIdentityRequestControl
+ * @see org.opends.sdk.requests.WhoAmIExtendedRequest
+ * @see <a href="http://tools.ietf.org/html/rfc3829">RFC 3829 - Lightweight
+ *      Directory Access Protocol (LDAP) Authorization Identity Request and
+ *      Response Controls </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4532">RFC 4532 - Lightweight
+ *      Directory Access Protocol (LDAP) "Who am I?" Operation </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public final class AuthorizationIdentityResponseControl implements Control
+{
+
+  /**
+   * The OID for the authorization identity response control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.15";
+
+
+
+  /**
+   * Creates a new authorization identity response control using the provided
+   * authorization ID.
+   *
+   * @param authorizationID
+   *          The authorization ID for this control.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code authorizationID} was {@code null}.
+   */
+  public static AuthorizationIdentityResponseControl newControl(
+      final String authorizationID) throws NullPointerException
+  {
+    return new AuthorizationIdentityResponseControl(false, authorizationID);
+  }
+
+
+
+  // The authorization ID for this control.
+  private final String authorizationID;
+
+  private final boolean isCritical;
+
+  /**
+   * A decoder which can be used for decoding the authorization identity
+   * response control.
+   */
+  public static final ControlDecoder<AuthorizationIdentityResponseControl>
+    DECODER = new ControlDecoder<AuthorizationIdentityResponseControl>()
+  {
+
+    public AuthorizationIdentityResponseControl decodeControl(
+        final Control control, final DecodeOptions options)
+        throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof AuthorizationIdentityResponseControl)
+      {
+        return (AuthorizationIdentityResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_AUTHZIDRESP_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_AUTHZIDRESP_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final String authID = control.getValue().toString();
+      return new AuthorizationIdentityResponseControl(control.isCritical(),
+          authID);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  // Prevent direct instantiation.
+  private AuthorizationIdentityResponseControl(final boolean isCritical,
+      final String authorizationID)
+  {
+    Validator.ensureNotNull(authorizationID);
+    this.isCritical = isCritical;
+    this.authorizationID = authorizationID;
+  }
+
+
+
+  /**
+   * Returns the authorization ID of the user. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authorization ID of the user.
+   */
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return ByteString.valueOf(authorizationID);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AuthorizationIdentityResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", authzID=\"");
+    builder.append(authorizationID);
+    builder.append("\")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/Control.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/Control.java
new file mode 100644
index 0000000..880ab89
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/Control.java
@@ -0,0 +1,96 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * Controls provide a mechanism whereby the semantics and arguments of existing
+ * LDAP operations may be extended. One or more controls may be attached to a
+ * single LDAP message. A control only affects the semantics of the message it
+ * is attached to. Controls sent by clients are termed 'request controls', and
+ * those sent by servers are termed 'response controls'.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight
+ *      Directory Access Protocol (LDAP): The Protocol </a>
+ */
+public interface Control
+{
+
+  /**
+   * Returns the numeric OID associated with this control.
+   *
+   * @return The numeric OID associated with this control.
+   */
+  String getOID();
+
+
+
+  /**
+   * Returns the value, if any, associated with this control. Its format is
+   * defined by the specification of this control.
+   *
+   * @return The value associated with this control, or {@code null} if there is
+   *         no value.
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * Returns {@code true} if this control has a value. In some circumstances it
+   * may be useful to determine if a control has a value, without actually
+   * calculating the value and incurring any performance costs.
+   *
+   * @return {@code true} if this control has a value, or {@code false} if there
+   *         is no value.
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * Returns {@code true} if it is unacceptable to perform the operation without
+   * applying the semantics of this control.
+   * <p>
+   * The criticality field only has meaning in controls attached to request
+   * messages (except UnbindRequest). For controls attached to response messages
+   * and the UnbindRequest, the criticality field SHOULD be {@code false}, and
+   * MUST be ignored by the receiving protocol peer. A value of {@code true}
+   * indicates that it is unacceptable to perform the operation without applying
+   * the semantics of the control.
+   *
+   * @return {@code true} if this control must be processed by the Directory
+   *         Server, or {@code false} if it can be ignored.
+   */
+  boolean isCritical();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ControlDecoder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ControlDecoder.java
new file mode 100644
index 0000000..2d6c32e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ControlDecoder.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+
+
+
+/**
+ * A factory interface for decoding a control as a control of specific type.
+ *
+ * @param <C>
+ *          The type of control decoded by this control decoder.
+ */
+public interface ControlDecoder<C extends Control>
+{
+  /**
+   * Decodes the provided control as a {@code Control} of type {@code C}.
+   *
+   * @param control
+   *          The control to be decoded.
+   * @param options
+   *          The set of decode options which should be used when decoding the
+   *          control.
+   * @return The decoded control.
+   * @throws DecodeException
+   *           If the control contained the wrong OID, it did not have a value,
+   *           or if its value could not be decoded.
+   */
+  C decodeControl(Control control, DecodeOptions options)
+      throws DecodeException;
+
+
+
+  /**
+   * Returns the numeric OID associated with this control decoder.
+   *
+   * @return The numeric OID associated with this control decoder.
+   */
+  String getOID();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/EntryChangeNotificationResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/EntryChangeNotificationResponseControl.java
new file mode 100644
index 0000000..6c29336
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/EntryChangeNotificationResponseControl.java
@@ -0,0 +1,399 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+import static org.opends.sdk.asn1.ASN1Constants.UNIVERSAL_INTEGER_TYPE;
+import static org.opends.sdk.asn1.ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The entry change notification response control as defined in
+ * draft-ietf-ldapext-psearch. This control provides additional information
+ * about the change the caused a particular entry to be returned as the result
+ * of a persistent search.
+ *
+ * @see PersistentSearchRequestControl
+ * @see PersistentSearchChangeType
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-ietf-ldapext-psearch">draft-ietf-ldapext-psearch
+ *      - Persistent Search: A Simple LDAP Change Notification Mechanism </a>
+ */
+public final class EntryChangeNotificationResponseControl implements Control
+{
+  /**
+   * The OID for the entry change notification response control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.7";
+
+  /**
+   * A decoder which can be used for decoding the entry change notification
+   * response control.
+   */
+  public static final ControlDecoder<EntryChangeNotificationResponseControl>
+    DECODER = new ControlDecoder<EntryChangeNotificationResponseControl>()
+  {
+
+    public EntryChangeNotificationResponseControl decodeControl(
+        final Control control, final DecodeOptions options)
+        throws DecodeException
+    {
+      Validator.ensureNotNull(control, options);
+
+      if (control instanceof EntryChangeNotificationResponseControl)
+      {
+        return (EntryChangeNotificationResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_ECN_CONTROL_BAD_OID.get(control
+            .getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_ECN_NO_CONTROL_VALUE.get();
+        throw DecodeException.error(message);
+      }
+
+      String previousDNString = null;
+      long changeNumber = -1;
+      PersistentSearchChangeType changeType;
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        reader.readStartSequence();
+
+        final int changeTypeInt = reader.readEnumerated();
+        switch (changeTypeInt)
+        {
+        case 1:
+          changeType = PersistentSearchChangeType.ADD;
+          break;
+        case 2:
+          changeType = PersistentSearchChangeType.DELETE;
+          break;
+        case 4:
+          changeType = PersistentSearchChangeType.MODIFY;
+          break;
+        case 8:
+          changeType = PersistentSearchChangeType.MODIFY_DN;
+          break;
+        default:
+          final LocalizableMessage message = ERR_ECN_BAD_CHANGE_TYPE
+              .get(changeTypeInt);
+          throw DecodeException.error(message);
+        }
+
+        if (reader.hasNextElement()
+            && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE))
+        {
+          if (changeType != PersistentSearchChangeType.MODIFY_DN)
+          {
+            final LocalizableMessage message = ERR_ECN_ILLEGAL_PREVIOUS_DN
+                .get(String.valueOf(changeType));
+            throw DecodeException.error(message);
+          }
+
+          previousDNString = reader.readOctetStringAsString();
+        }
+        if (reader.hasNextElement()
+            && (reader.peekType() == UNIVERSAL_INTEGER_TYPE))
+        {
+          changeNumber = reader.readInteger();
+        }
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.throwing(
+            "EntryChangeNotificationControl.Decoder", "decode", e);
+
+        final LocalizableMessage message = ERR_ECN_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+
+      final Schema schema = options.getSchemaResolver().resolveSchema(
+          previousDNString);
+      DN previousDN = null;
+      if (previousDNString != null)
+      {
+        try
+        {
+          previousDN = DN.valueOf(previousDNString, schema);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          final LocalizableMessage message = ERR_ECN_INVALID_PREVIOUS_DN
+              .get(getExceptionMessage(e));
+          throw DecodeException.error(message, e);
+        }
+      }
+
+      return new EntryChangeNotificationResponseControl(control.isCritical(),
+          changeType, previousDN, changeNumber);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new entry change notification response control with the provided
+   * change type and optional previous distinguished name and change number.
+   *
+   * @param type
+   *          The change type for this change notification control.
+   * @param previousName
+   *          The distinguished name that the entry had prior to a modify DN
+   *          operation, or <CODE>null</CODE> if the operation was not a modify
+   *          DN.
+   * @param changeNumber
+   *          The change number for the associated change, or a negative value
+   *          if no change number is available.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code type} was {@code null}.
+   */
+  public static EntryChangeNotificationResponseControl newControl(
+      final PersistentSearchChangeType type, final DN previousName,
+      final long changeNumber) throws NullPointerException
+  {
+    return new EntryChangeNotificationResponseControl(false, type,
+        previousName, changeNumber);
+  }
+
+
+
+  /**
+   * Creates a new entry change notification response control with the provided
+   * change type and optional previous distinguished name and change number. The
+   * previous distinguished name, if provided, will be decoded using the default
+   * schema.
+   *
+   * @param type
+   *          The change type for this change notification control.
+   * @param previousName
+   *          The distinguished name that the entry had prior to a modify DN
+   *          operation, or <CODE>null</CODE> if the operation was not a modify
+   *          DN.
+   * @param changeNumber
+   *          The change number for the associated change, or a negative value
+   *          if no change number is available.
+   * @return The new control.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code previousName} is not a valid LDAP string representation
+   *           of a DN.
+   * @throws NullPointerException
+   *           If {@code type} was {@code null}.
+   */
+  public static EntryChangeNotificationResponseControl newControl(
+      final PersistentSearchChangeType type, final String previousName,
+      final long changeNumber) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    return new EntryChangeNotificationResponseControl(false, type, DN
+        .valueOf(previousName), changeNumber);
+  }
+
+
+
+  // The previous DN for this change notification control.
+  private final DN previousName;
+
+  // The change number for this change notification control.
+  private final long changeNumber;
+
+  // The change type for this change notification control.
+  private final PersistentSearchChangeType changeType;
+
+  private final boolean isCritical;
+
+
+
+  private EntryChangeNotificationResponseControl(final boolean isCritical,
+      final PersistentSearchChangeType changeType, final DN previousName,
+      final long changeNumber)
+  {
+    Validator.ensureNotNull(changeType);
+    this.isCritical = isCritical;
+    this.changeType = changeType;
+    this.previousName = previousName;
+    this.changeNumber = changeNumber;
+  }
+
+
+
+  /**
+   * Returns the change number for this entry change notification control.
+   *
+   * @return The change number for this entry change notification control, or a
+   *         negative value if no change number is available.
+   */
+  public long getChangeNumber()
+  {
+    return changeNumber;
+  }
+
+
+
+  /**
+   * Returns the change type for this entry change notification control.
+   *
+   * @return The change type for this entry change notification control.
+   */
+  public PersistentSearchChangeType getChangeType()
+  {
+    return changeType;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns the distinguished name that the entry had prior to a modify DN
+   * operation, or <CODE>null</CODE> if the operation was not a modify DN.
+   *
+   * @return The distinguished name that the entry had prior to a modify DN
+   *         operation.
+   */
+  public DN getPreviousName()
+  {
+    return previousName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeInteger(changeType.intValue());
+
+      if (previousName != null)
+      {
+        writer.writeOctetString(previousName.toString());
+      }
+
+      if (changeNumber > 0)
+      {
+        writer.writeInteger(changeNumber);
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("EntryChangeNotificationResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", changeType=");
+    builder.append(changeType.toString());
+    builder.append(", previousDN=\"");
+    builder.append(previousName);
+    builder.append("\"");
+    builder.append(", changeNumber=");
+    builder.append(changeNumber);
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GenericControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GenericControl.java
new file mode 100644
index 0000000..0f681d3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GenericControl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import org.opends.sdk.ByteString;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A generic control which can be used to represent arbitrary raw request and
+ * response controls.
+ */
+public final class GenericControl implements Control
+{
+
+  /**
+   * Creates a new control having the same OID, criticality, and value as the
+   * provided control.
+   *
+   * @param control
+   *          The control to be copied.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code control} was {@code null}.
+   */
+  public static GenericControl newControl(final Control control)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(control);
+
+    if (control instanceof GenericControl)
+    {
+      return (GenericControl) control;
+    }
+
+    return new GenericControl(control.getOID(), control.isCritical(), control
+        .getValue());
+  }
+
+
+
+  /**
+   * Creates a new non-critical control having the provided OID and no value.
+   *
+   * @param oid
+   *          The numeric OID associated with this control.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code oid} was {@code null}.
+   */
+  public static GenericControl newControl(final String oid)
+      throws NullPointerException
+  {
+    return new GenericControl(oid, false, null);
+  }
+
+
+
+  /**
+   * Creates a new control having the provided OID and criticality, but no
+   * value.
+   *
+   * @param oid
+   *          The numeric OID associated with this control.
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code oid} was {@code null}.
+   */
+  public static GenericControl newControl(final String oid,
+      final boolean isCritical) throws NullPointerException
+  {
+    return new GenericControl(oid, isCritical, null);
+  }
+
+
+
+  /**
+   * Creates a new control having the provided OID, criticality, and value.
+   * <p>
+   * If {@code value} is not an instance of {@code ByteString} then it will be
+   * converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param oid
+   *          The numeric OID associated with this control.
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param value
+   *          The value associated with this control, or {@code null} if there
+   *          is no value. Its format is defined by the specification of this
+   *          control.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code oid} was {@code null}.
+   */
+  public static GenericControl newControl(final String oid,
+      final boolean isCritical, final Object value) throws NullPointerException
+  {
+    return new GenericControl(oid, isCritical, (value == null) ? null
+        : ByteString.valueOf(value));
+  }
+
+
+
+  private final String oid;
+
+  private final boolean isCritical;
+
+  private final ByteString value;
+
+
+
+  // Prevent direct instantiation.
+  private GenericControl(final String oid, final boolean isCritical,
+      final ByteString value)
+  {
+    Validator.ensureNotNull(oid);
+    this.oid = oid;
+    this.isCritical = isCritical;
+    this.value = value;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return oid;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return value;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return value != null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("Control(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    if (value != null)
+    {
+      builder.append(", value=");
+      StaticUtils.toHexPlusAscii(value, builder, 4);
+    }
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GetEffectiveRightsRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GetEffectiveRightsRequestControl.java
new file mode 100644
index 0000000..b5d77eb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/GetEffectiveRightsRequestControl.java
@@ -0,0 +1,427 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+import java.util.*;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.schema.AttributeType;
+import org.opends.sdk.schema.Schema;
+import org.opends.sdk.schema.UnknownSchemaElementException;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A partial implementation of the get effective rights request control as
+ * defined in draft-ietf-ldapext-acl-model. The main differences are:
+ * <ul>
+ * <li>The response control is not supported. Instead the OpenDS implementation
+ * creates attributes containing effective rights information with the entry
+ * being returned.
+ * <li>The attribute type names are dynamically created.
+ * <li>The set of attributes for which effective rights information is to be
+ * requested can be included in the control.
+ * </ul>
+ * The get effective rights request control value has the following BER
+ * encoding:
+ *
+ * <pre>
+ *  GetRightsControl ::= SEQUENCE {
+ *    authzId    authzId  -- Only the "dn:DN" form is supported.
+ *    attributes  SEQUENCE OF AttributeType
+ *  }
+ * </pre>
+ *
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-ietf-ldapext-acl-model">draft-ietf-ldapext-acl-model
+ *      - Access Control Model for LDAPv3 </a>
+ **/
+public final class GetEffectiveRightsRequestControl implements Control
+{
+  /**
+   * The OID for the get effective rights request control.
+   */
+  public static final String OID = "1.3.6.1.4.1.42.2.27.9.5.2";
+
+  /**
+   * A decoder which can be used for decoding the get effective rights request
+   * control.
+   */
+  public static final ControlDecoder<GetEffectiveRightsRequestControl> DECODER =
+    new ControlDecoder<GetEffectiveRightsRequestControl>()
+  {
+
+    public GetEffectiveRightsRequestControl decodeControl(
+        final Control control, final DecodeOptions options)
+        throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof GetEffectiveRightsRequestControl)
+      {
+        return (GetEffectiveRightsRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_GETEFFECTIVERIGHTS_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      DN authorizationDN = null;
+      List<AttributeType> attributes = Collections.emptyList();
+
+      if (control.hasValue())
+      {
+        final ASN1Reader reader = ASN1.getReader(control.getValue());
+        try
+        {
+          reader.readStartSequence();
+          final String authzIDString = reader.readOctetStringAsString();
+          final String lowerAuthzIDString = authzIDString.toLowerCase();
+          Schema schema;
+
+          // Make sure authzId starts with "dn:" and is a valid DN.
+          if (lowerAuthzIDString.startsWith("dn:"))
+          {
+            final String authorizationDNString = authzIDString.substring(3);
+            schema = options.getSchemaResolver().resolveSchema(
+                authorizationDNString);
+            try
+            {
+              authorizationDN = DN.valueOf(authorizationDNString, schema);
+            }
+            catch (final LocalizedIllegalArgumentException e)
+            {
+              final LocalizableMessage message = ERR_GETEFFECTIVERIGHTS_INVALID_AUTHZIDDN
+                  .get(getExceptionMessage(e));
+              throw DecodeException.error(message, e);
+            }
+          }
+          else
+          {
+            final LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID
+                .get(lowerAuthzIDString);
+            throw DecodeException.error(message);
+          }
+
+          // There is an sequence containing an attribute list, try to
+          // decode it.
+          if (reader.hasNextElement())
+          {
+            attributes = new LinkedList<AttributeType>();
+            reader.readStartSequence();
+            while (reader.hasNextElement())
+            {
+              // Decode as an attribute type.
+              final String attributeName = reader.readOctetStringAsString();
+              AttributeType attributeType;
+              try
+              {
+                // FIXME: we're using the schema associated with the authzid
+                // which is not really correct. We should really use the schema
+                // associated with the entry.
+                attributeType = schema.getAttributeType(attributeName);
+              }
+              catch (final UnknownSchemaElementException e)
+              {
+                final LocalizableMessage message = ERR_GETEFFECTIVERIGHTS_UNKNOWN_ATTRIBUTE
+                    .get(attributeName);
+                throw DecodeException.error(message, e);
+              }
+              attributes.add(attributeType);
+            }
+            reader.readEndSequence();
+            attributes = Collections.unmodifiableList(attributes);
+          }
+          reader.readEndSequence();
+        }
+        catch (final IOException e)
+        {
+          final LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_DECODE_ERROR
+              .get(e.getMessage());
+          throw DecodeException.error(message);
+        }
+      }
+
+      return new GetEffectiveRightsRequestControl(control.isCritical(),
+          authorizationDN, attributes);
+
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new get effective rights request control with the provided
+   * criticality, optional authorization name and attribute list.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param authorizationName
+   *          The distinguished name of the user for which effective rights are
+   *          to be returned, or {@code null} if the client's authentication ID
+   *          is to be used.
+   * @param attributes
+   *          The list of attributes for which effective rights are to be
+   *          returned, which may be empty indicating that no attribute rights
+   *          are to be returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code attributes} was {@code null}.
+   */
+  public static GetEffectiveRightsRequestControl newControl(
+      final boolean isCritical, final DN authorizationName,
+      final Collection<AttributeType> attributes) throws NullPointerException
+  {
+    Validator.ensureNotNull(attributes);
+
+    final Collection<AttributeType> copyOfAttributes = Collections
+        .unmodifiableList(new ArrayList<AttributeType>(attributes));
+    return new GetEffectiveRightsRequestControl(isCritical, authorizationName,
+        copyOfAttributes);
+  }
+
+
+
+  /**
+   * Creates a new get effective rights request control with the provided
+   * criticality, optional authorization name and attribute list. The
+   * authorization name and attributes, if provided, will be decoded using the
+   * default schema.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param authorizationName
+   *          The distinguished name of the user for which effective rights are
+   *          to be returned, or {@code null} if the client's authentication ID
+   *          is to be used.
+   * @param attributes
+   *          The list of attributes for which effective rights are to be
+   *          returned, which may be empty indicating that no attribute rights
+   *          are to be returned.
+   * @return The new control.
+   * @throws UnknownSchemaElementException
+   *           If the default schema is a strict schema and one or more of the
+   *           requested attribute types were not recognized.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationName} is not a valid LDAP string
+   *           representation of a DN.
+   * @throws NullPointerException
+   *           If {@code attributes} was {@code null}.
+   */
+  public static GetEffectiveRightsRequestControl newControl(
+      final boolean isCritical, final String authorizationName,
+      final String... attributes) throws UnknownSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull((Object) attributes);
+
+    final DN dn = authorizationName == null ? null : DN
+        .valueOf(authorizationName);
+
+    List<AttributeType> copyOfAttributes;
+    if (attributes != null && attributes.length > 0)
+    {
+      copyOfAttributes = new ArrayList<AttributeType>(attributes.length);
+      for (final String attribute : attributes)
+      {
+        copyOfAttributes.add(Schema.getDefaultSchema().getAttributeType(
+            attribute));
+      }
+      copyOfAttributes = Collections.unmodifiableList(copyOfAttributes);
+    }
+    else
+    {
+      copyOfAttributes = Collections.emptyList();
+    }
+
+    return new GetEffectiveRightsRequestControl(isCritical, dn,
+        copyOfAttributes);
+  }
+
+
+
+  // The DN representing the authzId (may be null meaning use the client's DN).
+  private final DN authorizationName;
+
+  // The unmodifiable list of attributes to be queried (may be empty).
+  private final Collection<AttributeType> attributes;
+
+  private final boolean isCritical;
+
+
+
+  private GetEffectiveRightsRequestControl(final boolean isCritical,
+      final DN authorizationName, final Collection<AttributeType> attributes)
+  {
+    this.isCritical = isCritical;
+    this.authorizationName = authorizationName;
+    this.attributes = attributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list of attributes for which effective rights are
+   * to be returned, which may be empty indicating that no attribute rights are
+   * to be returned.
+   *
+   * @return The unmodifiable list of attributes for which effective rights are
+   *         to be returned.
+   */
+  public Collection<AttributeType> getAttributes()
+  {
+    return attributes;
+  }
+
+
+
+  /**
+   * Returns the distinguished name of the user for which effective rights are
+   * to be returned, or {@code null} if the client's authentication ID is to be
+   * used.
+   *
+   * @return The distinguished name of the user for which effective rights are
+   *         to be returned.
+   */
+  public DN getAuthorizationName()
+  {
+    return authorizationName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      if (authorizationName != null)
+      {
+        writer.writeOctetString("dn:" + authorizationName);
+      }
+
+      if (!attributes.isEmpty())
+      {
+        writer.writeStartSequence();
+        for (final AttributeType attribute : attributes)
+        {
+          writer.writeOctetString(attribute.getNameOrOID());
+        }
+        writer.writeEndSequence();
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return authorizationName != null || !attributes.isEmpty();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GetEffectiveRightsRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", authorizationDN=\"");
+    builder.append(authorizationName);
+    builder.append("\"");
+    builder.append(", attributes=(");
+    builder.append(attributes);
+    builder.append("))");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ManageDsaITRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ManageDsaITRequestControl.java
new file mode 100644
index 0000000..55a5db7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ManageDsaITRequestControl.java
@@ -0,0 +1,194 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_MANAGEDSAIT_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_MANAGEDSAIT_INVALID_CONTROL_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The ManageDsaIT request control as defined in RFC 3296. This control allows
+ * manipulation of referral and other special objects as normal objects.
+ * <p>
+ * When this control is present in the request, the server will not generate a
+ * referral or continuation reference based upon information held in referral
+ * objects and instead will treat the referral object as a normal entry. The
+ * server, however, is still free to return referrals for other reasons.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc3296">RFC 3296 - Named
+ *      Subordinate References in Lightweight Directory Access Protocol (LDAP)
+ *      Directories </a>
+ */
+public final class ManageDsaITRequestControl implements Control
+{
+  /**
+   * The OID for the ManageDsaIT request control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.2";
+
+  private static final ManageDsaITRequestControl CRITICAL_INSTANCE = new ManageDsaITRequestControl(
+      true);
+  private static final ManageDsaITRequestControl NONCRITICAL_INSTANCE =
+    new ManageDsaITRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the Manage DsaIT request control.
+   */
+  public static final ControlDecoder<ManageDsaITRequestControl> DECODER =
+    new ControlDecoder<ManageDsaITRequestControl>()
+  {
+
+    public ManageDsaITRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof ManageDsaITRequestControl)
+      {
+        return (ManageDsaITRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_MANAGEDSAIT_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_MANAGEDSAIT_INVALID_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new ManageDsaIT request control having the provided criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static ManageDsaITRequestControl newControl(final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private final boolean isCritical;
+
+
+
+  private ManageDsaITRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ManageDsaITRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/MatchedValuesRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/MatchedValuesRequestControl.java
new file mode 100644
index 0000000..b28d9b1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/MatchedValuesRequestControl.java
@@ -0,0 +1,463 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+import java.util.*;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.ldap.LDAPUtils;
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The matched values request control as defined in RFC 3876. The matched values
+ * control may be included in a search request to indicate that only attribute
+ * values matching one or more filters contained in the matched values control
+ * should be returned to the client.
+ * <p>
+ * The matched values request control supports a subset of the LDAP filter type
+ * defined in RFC 4511, and is defined as follows:
+ *
+ * <pre>
+ * ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem
+ *
+ * SimpleFilterItem ::= CHOICE {
+ *        equalityMatch   [3] AttributeValueAssertion,
+ *        substrings      [4] SubstringFilter,
+ *        greaterOrEqual  [5] AttributeValueAssertion,
+ *        lessOrEqual     [6] AttributeValueAssertion,
+ *        present         [7] AttributeDescription,
+ *        approxMatch     [8] AttributeValueAssertion,
+ *        extensibleMatch [9] SimpleMatchingAssertion }
+ *
+ * SimpleMatchingAssertion ::= SEQUENCE {
+ *        matchingRule    [1] MatchingRuleId OPTIONAL,
+ *        type            [2] AttributeDescription OPTIONAL,
+ * --- at least one of the above must be present
+ *        matchValue      [3] AssertionValue}
+ * </pre>
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc3876">RFC 3876 - Returning
+ *      Matched Values with the Lightweight Directory Access Protocol version 3
+ *      (LDAPv3) </a>
+ */
+public final class MatchedValuesRequestControl implements Control
+{
+  /**
+   * Visitor for validating matched values filters.
+   */
+  private static final class FilterValidator extends
+      AbstractFilterVisitor<LocalizedIllegalArgumentException, Filter>
+  {
+
+    @Override
+    public LocalizedIllegalArgumentException visitAndFilter(final Filter p,
+        final List<Filter> subFilters)
+    {
+      final LocalizableMessage message = ERR_MVFILTER_BAD_FILTER_AND.get(p
+          .toString());
+      return new LocalizedIllegalArgumentException(message);
+    }
+
+
+
+    @Override
+    public LocalizedIllegalArgumentException visitExtensibleMatchFilter(
+        final Filter p, final String matchingRule,
+        final String attributeDescription, final ByteString assertionValue,
+        final boolean dnAttributes)
+    {
+      if (dnAttributes)
+      {
+        final LocalizableMessage message = ERR_MVFILTER_BAD_FILTER_EXT.get(p
+            .toString());
+        return new LocalizedIllegalArgumentException(message);
+      }
+      else
+      {
+        return null;
+      }
+    }
+
+
+
+    @Override
+    public LocalizedIllegalArgumentException visitNotFilter(final Filter p,
+        final Filter subFilter)
+    {
+      final LocalizableMessage message = ERR_MVFILTER_BAD_FILTER_NOT.get(p
+          .toString());
+      return new LocalizedIllegalArgumentException(message);
+    }
+
+
+
+    @Override
+    public LocalizedIllegalArgumentException visitOrFilter(final Filter p,
+        final List<Filter> subFilters)
+    {
+      final LocalizableMessage message = ERR_MVFILTER_BAD_FILTER_OR.get(p
+          .toString());
+      return new LocalizedIllegalArgumentException(message);
+    }
+
+
+
+    @Override
+    public LocalizedIllegalArgumentException visitUnrecognizedFilter(
+        final Filter p, final byte filterTag, final ByteString filterBytes)
+    {
+      final LocalizableMessage message = ERR_MVFILTER_BAD_FILTER_UNRECOGNIZED
+          .get(p.toString(), filterTag);
+      return new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  /**
+   * The OID for the matched values request control used to specify which
+   * particular attribute values should be returned in a search result entry.
+   */
+  public static final String OID = "1.2.826.0.1.3344810.2.3";
+
+  /**
+   * A decoder which can be used for decoding the matched values request
+   * control.
+   */
+  public static final ControlDecoder<MatchedValuesRequestControl> DECODER =
+    new ControlDecoder<MatchedValuesRequestControl>()
+  {
+
+    public MatchedValuesRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof MatchedValuesRequestControl)
+      {
+        return (MatchedValuesRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_MATCHEDVALUES_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_MATCHEDVALUES_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        reader.readStartSequence();
+        if (!reader.hasNextElement())
+        {
+          final LocalizableMessage message = ERR_MATCHEDVALUES_NO_FILTERS.get();
+          throw DecodeException.error(message);
+        }
+
+        final LinkedList<Filter> filters = new LinkedList<Filter>();
+        do
+        {
+          final Filter filter = LDAPUtils.decodeFilter(reader);
+
+          try
+          {
+            validateFilter(filter);
+          }
+          catch (final LocalizedIllegalArgumentException e)
+          {
+            throw DecodeException.error(e.getMessageObject());
+          }
+
+          filters.add(filter);
+        }
+        while (reader.hasNextElement());
+
+        reader.readEndSequence();
+
+        return new MatchedValuesRequestControl(control.isCritical(),
+            Collections.unmodifiableList(filters));
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("MatchedValuesControl.Decoder",
+            "decode", e);
+
+        final LocalizableMessage message = ERR_MATCHEDVALUES_CANNOT_DECODE_VALUE_AS_SEQUENCE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+  private static final FilterValidator FILTER_VALIDATOR = new FilterValidator();
+
+
+
+  /**
+   * Creates a new matched values request control with the provided criticality
+   * and list of filters.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param filters
+   *          The list of filters of which at least one must match an attribute
+   *          value in order for the attribute value to be returned to the
+   *          client. The list must not be empty.
+   * @return The new control.
+   * @throws LocalizedIllegalArgumentException
+   *           If one or more filters failed to conform to the filter
+   *           constraints defined in RFC 3876.
+   * @throws IllegalArgumentException
+   *           If {@code filters} was empty.
+   * @throws NullPointerException
+   *           If {@code filters} was {@code null}.
+   */
+  public static MatchedValuesRequestControl newControl(
+      final boolean isCritical, final Collection<Filter> filters)
+      throws LocalizedIllegalArgumentException, IllegalArgumentException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(filters);
+    Validator.ensureTrue(filters.size() > 0, "filters is empty");
+
+    List<Filter> copyOfFilters;
+    if (filters.size() == 1)
+    {
+      copyOfFilters = Collections.singletonList(validateFilter(filters
+          .iterator().next()));
+    }
+    else
+    {
+      copyOfFilters = new ArrayList<Filter>(filters.size());
+      for (final Filter filter : filters)
+      {
+        copyOfFilters.add(validateFilter(filter));
+      }
+      copyOfFilters = Collections.unmodifiableList(copyOfFilters);
+    }
+
+    return new MatchedValuesRequestControl(isCritical, copyOfFilters);
+  }
+
+
+
+  /**
+   * Creates a new matched values request control with the provided criticality
+   * and list of filters.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param firstFilter
+   *          The first matched values filter.
+   * @param remainingFilters
+   *          The remaining matched values filter, may be {@code null} or empty.
+   * @return The new control.
+   * @throws LocalizedIllegalArgumentException
+   *           If one or more filters could not be parsed, or if one or more
+   *           filters failed to conform to the filter constraints defined in
+   *           RFC 3876.
+   * @throws NullPointerException
+   *           If {@code firstFilter} was {@code null}.
+   */
+  public static MatchedValuesRequestControl newControl(
+      final boolean isCritical, final String firstFilter,
+      final String... remainingFilters)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(firstFilter);
+
+    List<Filter> filters;
+    if (remainingFilters == null || remainingFilters.length == 0)
+    {
+      filters = Collections.singletonList(validateFilter(Filter
+          .valueOf(firstFilter)));
+    }
+    else
+    {
+      filters = new ArrayList<Filter>(1 + remainingFilters.length);
+      filters.add(validateFilter(Filter.valueOf(firstFilter)));
+      for (final String filter : remainingFilters)
+      {
+        filters.add(validateFilter(Filter.valueOf(filter)));
+      }
+      filters = Collections.unmodifiableList(filters);
+    }
+
+    return new MatchedValuesRequestControl(isCritical, filters);
+  }
+
+
+
+  private static Filter validateFilter(final Filter filter)
+      throws LocalizedIllegalArgumentException
+  {
+    final LocalizedIllegalArgumentException e = filter.accept(FILTER_VALIDATOR,
+        filter);
+    if (e != null)
+    {
+      throw e;
+    }
+    return filter;
+  }
+
+
+
+  private final Collection<Filter> filters;
+
+  private final boolean isCritical;
+
+
+
+  private MatchedValuesRequestControl(final boolean isCritical,
+      final Collection<Filter> filters)
+  {
+    this.isCritical = isCritical;
+    this.filters = filters;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing the list of filters
+   * associated with this matched values control.
+   *
+   * @return An unmodifiable collection containing the list of filters
+   *         associated with this matched values control.
+   */
+  public Collection<Filter> getFilters()
+  {
+    return filters;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      for (final Filter f : filters)
+      {
+        LDAPUtils.encodeFilter(writer, f);
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("MatchedValuesRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiredResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiredResponseControl.java
new file mode 100644
index 0000000..81ff574
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiredResponseControl.java
@@ -0,0 +1,194 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_PWEXPIRED_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_PWEXPIRED_CONTROL_INVALID_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The Netscape password expired response control as defined in
+ * draft-vchu-ldap-pwd-policy. This control indicates to a client that their
+ * password has expired and must be changed. This control always has a value
+ * which is the string {@code "0"}.
+ *
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-vchu-ldap-pwd-policy">draft-vchu-ldap-pwd-policy
+ *      - Password Policy for LDAP Directories </a>
+ */
+public final class PasswordExpiredResponseControl implements Control
+{
+  /**
+   * The OID for the Netscape password expired response control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.4";
+
+  private final boolean isCritical;
+
+  private static final PasswordExpiredResponseControl CRITICAL_INSTANCE =
+    new PasswordExpiredResponseControl(true);
+  private static final PasswordExpiredResponseControl NONCRITICAL_INSTANCE =
+    new PasswordExpiredResponseControl(false);
+
+  /**
+   * A decoder which can be used for decoding the password expired response
+   * control.
+   */
+  public static final ControlDecoder<PasswordExpiredResponseControl> DECODER =
+    new ControlDecoder<PasswordExpiredResponseControl>()
+  {
+
+    public PasswordExpiredResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PasswordExpiredResponseControl)
+      {
+        return (PasswordExpiredResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PWEXPIRED_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        try
+        {
+          Integer.parseInt(control.getValue().toString());
+        }
+        catch (final Exception e)
+        {
+          final LocalizableMessage message = ERR_PWEXPIRED_CONTROL_INVALID_VALUE
+              .get();
+          throw DecodeException.error(message);
+        }
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+  private final static ByteString CONTROL_VALUE = ByteString.valueOf("0");
+
+
+
+  /**
+   * Creates a new Netscape password expired response control.
+   *
+   * @return The new control.
+   */
+  public static PasswordExpiredResponseControl newControl()
+  {
+    return NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private PasswordExpiredResponseControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return CONTROL_VALUE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordExpiredResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiringResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiringResponseControl.java
new file mode 100644
index 0000000..c9dcc25
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordExpiringResponseControl.java
@@ -0,0 +1,229 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_PWEXPIRING_CANNOT_DECODE_SECONDS_UNTIL_EXPIRATION;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_PWEXPIRING_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_PWEXPIRING_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The Netscape password expiring response control as defined in
+ * draft-vchu-ldap-pwd-policy. This control serves as a warning to clients that
+ * the user's password is about to expire. The only element contained in the
+ * control value is a string representation of the number of seconds until
+ * expiration.
+ *
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-vchu-ldap-pwd-policy">draft-vchu-ldap-pwd-policy
+ *      - Password Policy for LDAP Directories </a>
+ */
+public final class PasswordExpiringResponseControl implements Control
+{
+  /**
+   * The OID for the Netscape password expiring response control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.5";
+
+  /**
+   * A decoder which can be used for decoding the password expiring response
+   * control.
+   */
+  public static final ControlDecoder<PasswordExpiringResponseControl> DECODER =
+    new ControlDecoder<PasswordExpiringResponseControl>()
+  {
+
+    public PasswordExpiringResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PasswordExpiringResponseControl)
+      {
+        return (PasswordExpiringResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PWEXPIRING_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        final LocalizableMessage message = ERR_PWEXPIRING_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      int secondsUntilExpiration;
+      try
+      {
+        secondsUntilExpiration = Integer
+            .parseInt(control.getValue().toString());
+      }
+      catch (final Exception e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PasswordExpiringControl.Decoder",
+            "decode", e);
+
+        final LocalizableMessage message = ERR_PWEXPIRING_CANNOT_DECODE_SECONDS_UNTIL_EXPIRATION
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message);
+      }
+
+      return new PasswordExpiringResponseControl(control.isCritical(),
+          secondsUntilExpiration);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new Netscape password expiring response control with the provided
+   * amount of time until expiration.
+   *
+   * @param secondsUntilExpiration
+   *          The length of time in seconds until the password actually expires.
+   * @return The new control.
+   */
+  public static PasswordExpiringResponseControl newControl(
+      final int secondsUntilExpiration)
+  {
+    return new PasswordExpiringResponseControl(false, secondsUntilExpiration);
+  }
+
+
+
+  // The length of time in seconds until the password actually expires.
+  private final int secondsUntilExpiration;
+
+  private final boolean isCritical;
+
+
+
+  private PasswordExpiringResponseControl(final boolean isCritical,
+      final int secondsUntilExpiration)
+  {
+    this.isCritical = isCritical;
+    this.secondsUntilExpiration = secondsUntilExpiration;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns the length of time in seconds until the password actually expires.
+   *
+   * @return The length of time in seconds until the password actually expires.
+   */
+  public int getSecondsUntilExpiration()
+  {
+    return secondsUntilExpiration;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return ByteString.valueOf(String.valueOf(secondsUntilExpiration));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordExpiringResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", secondsUntilExpiration=");
+    builder.append(secondsUntilExpiration);
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyErrorType.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyErrorType.java
new file mode 100644
index 0000000..afa8740
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyErrorType.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+/**
+ * A password policy error type as defined in draft-behera-ldap-password-policy
+ * is used to indicate problems concerning a user's account or password.
+ *
+ * @see PasswordPolicyRequestControl
+ * @see PasswordPolicyResponseControl
+ * @see PasswordPolicyWarningType
+ * @see <a href="http://tools.ietf.org/html/draft-behera-ldap-password-policy">
+ *      draft-behera-ldap-password-policy - Password Policy for LDAP Directories
+ *      </a>
+ */
+public enum PasswordPolicyErrorType
+{
+
+  /**
+   * Indicates that the password has expired and must be reset.
+   */
+  PASSWORD_EXPIRED(0, "passwordExpired"),
+
+  /**
+   * Indicates that the user's account has been locked.
+   */
+  ACCOUNT_LOCKED(1, "accountLocked"),
+
+  /**
+   * Indicates that the password must be changed before the user will be allowed
+   * to perform any operation other than bind and modify.
+   */
+  CHANGE_AFTER_RESET(2, "changeAfterReset"),
+
+  /**
+   * Indicates that a user is restricted from changing her password.
+   */
+  PASSWORD_MOD_NOT_ALLOWED(3, "passwordModNotAllowed"),
+
+  /**
+   * Indicates that the old password must be supplied in order to modify the
+   * password.
+   */
+  MUST_SUPPLY_OLD_PASSWORD(4, "mustSupplyOldPassword"),
+
+  /**
+   * Indicates that a password doesn't pass quality checking.
+   */
+  INSUFFICIENT_PASSWORD_QUALITY(5, "insufficientPasswordQuality"),
+
+  /**
+   * Indicates that a password is not long enough.
+   */
+  PASSWORD_TOO_SHORT(6, "passwordTooShort"),
+
+  /**
+   * Indicates that the age of the password to be modified is not yet old
+   * enough.
+   */
+  PASSWORD_TOO_YOUNG(7, "passwordTooYoung"),
+
+  /**
+   * Indicates that a password has already been used and the user must choose a
+   * different one.
+   */
+  PASSWORD_IN_HISTORY(8, "passwordInHistory");
+
+  private final int intValue;
+
+  private final String name;
+
+
+
+  private PasswordPolicyErrorType(final int intValue, final String name)
+  {
+    this.intValue = intValue;
+    this.name = name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * Returns the integer value for this password policy error type.
+   *
+   * @return The integer value for this password policy error type.
+   */
+  int intValue()
+  {
+    return intValue;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyRequestControl.java
new file mode 100644
index 0000000..eb96ab7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyRequestControl.java
@@ -0,0 +1,195 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_PWPOLICYREQ_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_PWPOLICYREQ_CONTROL_HAS_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The password policy request control as defined in
+ * draft-behera-ldap-password-policy.
+ * <p>
+ * This control may be sent with any request in order to convey to the server
+ * that this client is aware of, and can process the password policy response
+ * control. When a server receives this control, it will return the password
+ * policy response control when appropriate and with the proper data.
+ *
+ * @see PasswordPolicyResponseControl
+ * @see <a href="http://tools.ietf.org/html/draft-behera-ldap-password-policy">
+ *         draft-behera-ldap-password-policy - Password Policy for LDAP Directories </a>
+ */
+public final class PasswordPolicyRequestControl implements Control
+{
+  /**
+   * The OID for the password policy control from
+   * draft-behera-ldap-password-policy.
+   */
+  public static final String OID = "1.3.6.1.4.1.42.2.27.8.5.1";
+
+  private final boolean isCritical;
+
+  private static final PasswordPolicyRequestControl CRITICAL_INSTANCE =
+    new PasswordPolicyRequestControl(true);
+  private static final PasswordPolicyRequestControl NONCRITICAL_INSTANCE =
+    new PasswordPolicyRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the password policy request
+   * control.
+   */
+  public static final ControlDecoder<PasswordPolicyRequestControl> DECODER =
+    new ControlDecoder<PasswordPolicyRequestControl>()
+  {
+
+    public PasswordPolicyRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PasswordPolicyRequestControl)
+      {
+        return (PasswordPolicyRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PWPOLICYREQ_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_PWPOLICYREQ_CONTROL_HAS_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new password policy request control having the provided
+   * criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static PasswordPolicyRequestControl newControl(final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private PasswordPolicyRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordPolicyRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyResponseControl.java
new file mode 100644
index 0000000..742ca3c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyResponseControl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.byteToHex;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The password policy response control as defined in
+ * draft-behera-ldap-password-policy.
+ * <p>
+ * If the client has sent a passwordPolicyRequest control, the server (when
+ * solicited by the inclusion of the request control) sends this control with
+ * the following operation responses: bindResponse, modifyResponse, addResponse,
+ * compareResponse and possibly extendedResponse, to inform of various
+ * conditions, and MAY be sent with other operations (in the case of the
+ * changeAfterReset error).
+ *
+ * @see PasswordPolicyRequestControl
+ * @see PasswordPolicyWarningType
+ * @see PasswordPolicyErrorType
+ * @see <a href="http://tools.ietf.org/html/draft-behera-ldap-password-policy">
+ *         draft-behera-ldap-password-policy - Password Policy for LDAP
+ *         Directories </a>
+ */
+public final class PasswordPolicyResponseControl implements Control
+{
+  /**
+   * The OID for the password policy control from
+   * draft-behera-ldap-password-policy.
+   */
+  public static final String OID = PasswordPolicyRequestControl.OID;
+
+  private final int warningValue;
+
+  private final PasswordPolicyErrorType errorType;
+
+  private final PasswordPolicyWarningType warningType;
+
+  /**
+   * A decoder which can be used for decoding the password policy response
+   * control.
+   */
+  public static final ControlDecoder<PasswordPolicyResponseControl> DECODER =
+    new ControlDecoder<PasswordPolicyResponseControl>()
+  {
+
+    public PasswordPolicyResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PasswordPolicyResponseControl)
+      {
+        return (PasswordPolicyResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PWPOLICYRES_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_PWPOLICYRES_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        PasswordPolicyWarningType warningType = null;
+        PasswordPolicyErrorType errorType = null;
+        int warningValue = -1;
+
+        reader.readStartSequence();
+
+        if (reader.hasNextElement()
+            && (reader.peekType() == TYPE_WARNING_ELEMENT))
+        {
+          // Its a CHOICE element. Read as sequence to retrieve
+          // nested element.
+          reader.readStartSequence();
+          final int warningChoiceValue = (0x7F & reader.peekType());
+          if (warningChoiceValue < 0
+              || warningChoiceValue >= PasswordPolicyWarningType.values().length)
+          {
+            final LocalizableMessage message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE
+                .get(byteToHex(reader.peekType()));
+            throw DecodeException.error(message);
+          }
+          else
+          {
+            warningType = PasswordPolicyWarningType.values()[warningChoiceValue];
+          }
+          warningValue = (int) reader.readInteger();
+          reader.readEndSequence();
+        }
+
+        if (reader.hasNextElement()
+            && (reader.peekType() == TYPE_ERROR_ELEMENT))
+        {
+          final int errorValue = reader.readEnumerated();
+          if (errorValue < 0
+              || errorValue >= PasswordPolicyErrorType.values().length)
+          {
+            final LocalizableMessage message = ERR_PWPOLICYRES_INVALID_ERROR_TYPE
+                .get(errorValue);
+            throw DecodeException.error(message);
+          }
+          else
+          {
+            errorType = PasswordPolicyErrorType.values()[errorValue];
+          }
+        }
+
+        reader.readEndSequence();
+
+        return new PasswordPolicyResponseControl(control.isCritical(),
+            warningType, warningValue, errorType);
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PasswordPolicyControl.ResponseDecoder",
+            "decode", e);
+
+        final LocalizableMessage message = ERR_PWPOLICYRES_DECODE_ERROR
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new password policy response control with the provided error.
+   *
+   * @param errorType
+   *          The password policy error type.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code errorType} was {@code null}.
+   */
+  public static PasswordPolicyResponseControl newControl(
+      final PasswordPolicyErrorType errorType) throws NullPointerException
+  {
+    Validator.ensureNotNull(errorType);
+
+    return new PasswordPolicyResponseControl(false, null, -1, errorType);
+  }
+
+
+
+  /**
+   * Creates a new password policy response control with the provided warning.
+   *
+   * @param warningType
+   *          The password policy warning type.
+   * @param warningValue
+   *          The password policy warning value.
+   * @return The new control.
+   * @throws IllegalArgumentException
+   *           If {@code warningValue} was negative.
+   * @throws NullPointerException
+   *           If {@code warningType} was {@code null}.
+   */
+  public static PasswordPolicyResponseControl newControl(
+      final PasswordPolicyWarningType warningType, final int warningValue)
+      throws IllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(warningType);
+    Validator.ensureTrue(warningValue >= 0, "warningValue is negative");
+
+    return new PasswordPolicyResponseControl(false, warningType, warningValue,
+        null);
+  }
+
+
+
+  /**
+   * Creates a new password policy response control with the provided warning
+   * and error.
+   *
+   * @param warningType
+   *          The password policy warning type.
+   * @param warningValue
+   *          The password policy warning value.
+   * @param errorType
+   *          The password policy error type.
+   * @return The new control.
+   * @throws IllegalArgumentException
+   *           If {@code warningValue} was negative.
+   * @throws NullPointerException
+   *           If {@code warningType} or {@code errorType} was {@code null}.
+   */
+  public static PasswordPolicyResponseControl newControl(
+      final PasswordPolicyWarningType warningType, final int warningValue,
+      final PasswordPolicyErrorType errorType) throws IllegalArgumentException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(warningType, errorType);
+    Validator.ensureTrue(warningValue >= 0, "warningValue is negative");
+
+    return new PasswordPolicyResponseControl(false, warningType, warningValue,
+        errorType);
+  }
+
+
+
+  private final boolean isCritical;
+
+  /**
+   * The BER type value for the warning element of the control value.
+   */
+  private static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0;
+
+  /**
+   * The BER type value for the error element of the control value.
+   */
+  private static final byte TYPE_ERROR_ELEMENT = (byte) 0x81;
+
+
+
+  private PasswordPolicyResponseControl(final boolean isCritical,
+      final PasswordPolicyWarningType warningType, final int warningValue,
+      final PasswordPolicyErrorType errorType)
+  {
+    this.isCritical = isCritical;
+    this.warningType = warningType;
+    this.warningValue = warningValue;
+    this.errorType = errorType;
+  }
+
+
+
+  /**
+   * Returns the password policy error type, if available.
+   *
+   * @return The password policy error type, or {@code null} if this control
+   *         does not contain a error.
+   */
+  public PasswordPolicyErrorType getErrorType()
+  {
+    return errorType;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      if (warningType != null)
+      {
+        // Just write the CHOICE element as a single element SEQUENCE.
+        writer.writeStartSequence(TYPE_WARNING_ELEMENT);
+        writer.writeInteger((byte) (0x80 | warningType.intValue()),
+            warningValue);
+        writer.writeEndSequence();
+      }
+
+      if (errorType != null)
+      {
+        writer.writeInteger(TYPE_ERROR_ELEMENT, errorType.intValue());
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * Returns the password policy warning type, if available.
+   *
+   * @return The password policy warning type, or {@code null} if this control
+   *         does not contain a warning.
+   */
+  public PasswordPolicyWarningType getWarningType()
+  {
+    return warningType;
+  }
+
+
+
+  /**
+   * Returns the password policy warning value, if available. The value is
+   * undefined if this control does not contain a warning.
+   *
+   * @return The password policy warning value, or {@code -1} if this control
+   *         does not contain a warning.
+   */
+  public int getWarningValue()
+  {
+    return warningValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordPolicyResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    if (warningType != null)
+    {
+      builder.append(", warningType=");
+      builder.append(warningType);
+      builder.append(", warningValue=");
+      builder.append(warningValue);
+    }
+    if (errorType != null)
+    {
+      builder.append(", errorType=");
+      builder.append(errorType);
+    }
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyWarningType.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyWarningType.java
new file mode 100644
index 0000000..d79a22d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PasswordPolicyWarningType.java
@@ -0,0 +1,92 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+/**
+ * A password policy warning type as defined in
+ * draft-behera-ldap-password-policy is used to indicate the current state of a
+ * user's password. More specifically, the number of seconds before a password
+ * will expire, or the remaining number of times a user will be allowed to
+ * authenticate with an expired password.
+ *
+ * @see PasswordPolicyRequestControl
+ * @see PasswordPolicyResponseControl
+ * @see PasswordPolicyErrorType
+ * @see <a href="http://tools.ietf.org/html/draft-behera-ldap-password-policy">
+ *         draft-behera-ldap-password-policy - Password Policy for LDAP
+ *         Directories </a>
+ */
+public enum PasswordPolicyWarningType
+{
+  /**
+   * Indicates the number of seconds before a password will expire.
+   */
+  TIME_BEFORE_EXPIRATION(0, "timeBeforeExpiration"),
+
+  /**
+   * Indicates the remaining number of times a user will be allowed to
+   * authenticate with an expired password.
+   */
+  GRACE_LOGINS_REMAINING(1, "graceAuthNsRemaining");
+
+  private final int intValue;
+
+  private final String name;
+
+
+
+  private PasswordPolicyWarningType(final int intValue, final String name)
+  {
+    this.intValue = intValue;
+    this.name = name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * Returns the integer value for this password policy warning type.
+   *
+   * @return The integer value for this password policy warning type.
+   */
+  int intValue()
+  {
+    return intValue;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PermissiveModifyRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PermissiveModifyRequestControl.java
new file mode 100644
index 0000000..6a3442e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PermissiveModifyRequestControl.java
@@ -0,0 +1,201 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_PERMISSIVE_MODIFY_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_PERMISSIVE_MODIFY_INVALID_CONTROL_VALUE;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The Microsoft defined permissive modify request control. The OID for this
+ * control is 1.2.840.113556.1.4.1413, and it does not have a value.
+ * <p>
+ * This control can only be used with LDAP modify requests. It changes the
+ * behavior of the modify operation as follows:
+ * <ul>
+ * <li>Attempts to add an attribute value which already exists will be ignored
+ * and will not cause an {@link ResultCode#ATTRIBUTE_OR_VALUE_EXISTS
+ * AttributeValueExists} error result to be returned.
+ * <li>Attempts to delete an attribute value which does not exist will be
+ * ignored and will not cause an {@link ResultCode#NO_SUCH_ATTRIBUTE
+ * NoSuchAttribute} error result to be returned.
+ * </ul>
+ * In other words, a modify request {@code add} modification <i>ensures</i> that
+ * the attribute contains the specified attribute value, and a {@code delete}
+ * modification <i>ensures</i> that the attribute does not contain the specified
+ * attribute value.
+ */
+public final class PermissiveModifyRequestControl implements Control
+{
+  /**
+   * The OID for the permissive modify request control.
+   */
+  public static final String OID = "1.2.840.113556.1.4.1413";
+
+  private static final PermissiveModifyRequestControl CRITICAL_INSTANCE =
+    new PermissiveModifyRequestControl(true);
+
+  private static final PermissiveModifyRequestControl NONCRITICAL_INSTANCE =
+    new PermissiveModifyRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the permissive modify request
+   * control.
+   */
+  public static final ControlDecoder<PermissiveModifyRequestControl> DECODER =
+    new ControlDecoder<PermissiveModifyRequestControl>()
+  {
+
+    public PermissiveModifyRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PermissiveModifyRequestControl)
+      {
+        return (PermissiveModifyRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PERMISSIVE_MODIFY_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_PERMISSIVE_MODIFY_INVALID_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new permissive modify request control having the provided
+   * criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static PermissiveModifyRequestControl newControl(
+      final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private final boolean isCritical;
+
+
+
+  private PermissiveModifyRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PermissiveModifyRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchChangeType.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchChangeType.java
new file mode 100644
index 0000000..d36f1b3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchChangeType.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+/**
+ * A persistent search change type as defined in draft-ietf-ldapext-psearch is
+ * used to indicate the type of update operation that caused an entry change
+ * notification to occur.
+ *
+ * @see PersistentSearchRequestControl
+ * @see EntryChangeNotificationResponseControl
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-ietf-ldapext-psearch">draft-ietf-ldapext-psearch
+ *      - Persistent Search: A Simple LDAP Change Notification Mechanism </a>
+ */
+public enum PersistentSearchChangeType
+{
+  /**
+   * Indicates that an Add operation triggered the entry change notification.
+   */
+  ADD(1, "add"),
+
+  /**
+   * Indicates that an Delete operation triggered the entry change notification.
+   */
+  DELETE(2, "delete"),
+
+  /**
+   * Indicates that an Modify operation triggered the entry change notification.
+   */
+  MODIFY(4, "modify"),
+
+  /**
+   * Indicates that an Modify DN operation triggered the entry change
+   * notification.
+   */
+  MODIFY_DN(8, "modifyDN");
+
+  private final String name;
+
+  private final int intValue;
+
+
+
+  private PersistentSearchChangeType(final int intValue, final String name)
+  {
+    this.name = name;
+    this.intValue = intValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * Returns the integer value for this change type.
+   *
+   * @return The integer value for this change type.
+   */
+  int intValue()
+  {
+    return intValue;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchRequestControl.java
new file mode 100644
index 0000000..d4513c1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PersistentSearchRequestControl.java
@@ -0,0 +1,414 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_PSEARCH_BAD_CHANGE_TYPES;
+import static com.sun.opends.sdk.messages.Messages.ERR_PSEARCH_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_PSEARCH_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_PSEARCH_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+import java.util.*;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The persistent search request control as defined in
+ * draft-ietf-ldapext-psearch. This control allows a client to receive
+ * notification of changes that occur in an LDAP server.
+ *
+ * @see EntryChangeNotificationResponseControl
+ * @see PersistentSearchChangeType
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-ietf-ldapext-psearch">draft-ietf-ldapext-psearch
+ *      - Persistent Search: A Simple LDAP Change Notification Mechanism </a>
+ */
+public final class PersistentSearchRequestControl implements Control
+{
+  /**
+   * The OID for the persistent search request control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.3";
+
+  /**
+   * A decoder which can be used for decoding the persistent search request
+   * control.
+   */
+  public static final ControlDecoder<PersistentSearchRequestControl> DECODER =
+    new ControlDecoder<PersistentSearchRequestControl>()
+  {
+
+    public PersistentSearchRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PersistentSearchRequestControl)
+      {
+        return (PersistentSearchRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PSEARCH_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The control must always have a value.
+        final LocalizableMessage message = ERR_PSEARCH_NO_CONTROL_VALUE.get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      boolean changesOnly;
+      boolean returnECs;
+      int changeTypes;
+
+      try
+      {
+        reader.readStartSequence();
+
+        changeTypes = (int) reader.readInteger();
+        changesOnly = reader.readBoolean();
+        returnECs = reader.readBoolean();
+
+        reader.readEndSequence();
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PersistentSearchControl.Decoder",
+            "decode", e);
+
+        final LocalizableMessage message = ERR_PSEARCH_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+
+      final Set<PersistentSearchChangeType> changeTypeSet = EnumSet
+          .noneOf(PersistentSearchChangeType.class);
+
+      if ((changeTypes & 15) != 0)
+      {
+        final LocalizableMessage message = ERR_PSEARCH_BAD_CHANGE_TYPES
+            .get(changeTypes);
+        throw DecodeException.error(message);
+      }
+
+      if ((changeTypes & 1) != 0)
+      {
+        changeTypeSet.add(PersistentSearchChangeType.ADD);
+      }
+
+      if ((changeTypes & 2) != 0)
+      {
+        changeTypeSet.add(PersistentSearchChangeType.DELETE);
+      }
+
+      if ((changeTypes & 4) != 0)
+      {
+        changeTypeSet.add(PersistentSearchChangeType.MODIFY);
+      }
+
+      if ((changeTypes & 8) != 0)
+      {
+        changeTypeSet.add(PersistentSearchChangeType.MODIFY_DN);
+      }
+
+      return new PersistentSearchRequestControl(control.isCritical(),
+          changesOnly, returnECs, Collections.unmodifiableSet(changeTypeSet));
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new persistent search request control.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored
+   * @param changesOnly
+   *          Indicates whether or not only updated entries should be returned
+   *          (added, modified, deleted, or subject to a modifyDN operation). If
+   *          this parameter is {@code false} then the search will initially
+   *          return all the existing entries which match the filter.
+   * @param returnECs
+   *          Indicates whether or not the entry change notification control
+   *          should be included in updated entries that match the associated
+   *          search criteria.
+   * @param changeTypes
+   *          The types of update operation for which change notifications
+   *          should be returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code changeTypes} was {@code null}.
+   */
+  public static PersistentSearchRequestControl newControl(
+      final boolean isCritical, final boolean changesOnly,
+      final boolean returnECs,
+      final Collection<PersistentSearchChangeType> changeTypes)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(changeTypes);
+
+    final Set<PersistentSearchChangeType> copyOfChangeTypes = EnumSet
+        .noneOf(PersistentSearchChangeType.class);
+    copyOfChangeTypes.addAll(changeTypes);
+    return new PersistentSearchRequestControl(isCritical, changesOnly,
+        returnECs, Collections.unmodifiableSet(copyOfChangeTypes));
+  }
+
+
+
+  /**
+   * Creates a new persistent search request control.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored
+   * @param changesOnly
+   *          Indicates whether or not only updated entries should be returned
+   *          (added, modified, deleted, or subject to a modifyDN operation). If
+   *          this parameter is {@code false} then the search will initially
+   *          return all the existing entries which match the filter.
+   * @param returnECs
+   *          Indicates whether or not the entry change notification control
+   *          should be included in updated entries that match the associated
+   *          search criteria.
+   * @param changeTypes
+   *          The types of update operation for which change notifications
+   *          should be returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code changeTypes} was {@code null}.
+   */
+  public static PersistentSearchRequestControl newControl(
+      final boolean isCritical, final boolean changesOnly,
+      final boolean returnECs, final PersistentSearchChangeType... changeTypes)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull((Object) changeTypes);
+
+    return newControl(isCritical, changesOnly, returnECs, Arrays
+        .asList(changeTypes));
+  }
+
+
+
+  // Indicates whether to only return entries that have been updated
+  // since the beginning of the search.
+  private final boolean changesOnly;
+
+  // Indicates whether entries returned as a result of changes to
+  // directory data should include the entry change notification control.
+  private final boolean returnECs;
+
+  // The logical OR of change types associated with this control.
+  private final Set<PersistentSearchChangeType> changeTypes;
+
+  private final boolean isCritical;
+
+
+
+  private PersistentSearchRequestControl(final boolean isCritical,
+      final boolean changesOnly, final boolean returnECs,
+      final Set<PersistentSearchChangeType> changeTypes)
+  {
+    this.isCritical = isCritical;
+    this.changesOnly = changesOnly;
+    this.returnECs = returnECs;
+    this.changeTypes = changeTypes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the types of update operation for
+   * which change notifications should be returned.
+   *
+   * @return An unmodifiable set containing the types of update operation for
+   *         which change notifications should be returned.
+   */
+  public Set<PersistentSearchChangeType> getChangeTypes()
+  {
+    return changeTypes;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+
+      int changeTypesInt = 0;
+      for (final PersistentSearchChangeType changeType : changeTypes)
+      {
+        changeTypesInt |= changeType.intValue();
+      }
+      writer.writeInteger(changeTypesInt);
+
+      writer.writeBoolean(changesOnly);
+      writer.writeBoolean(returnECs);
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Returns {@code true} if only updated entries should be returned (added,
+   * modified, deleted, or subject to a modifyDN operation), otherwise {@code
+   * false} if the search will initially return all the existing entries which
+   * match the filter.
+   *
+   * @return {@code true} if only updated entries should be returned (added,
+   *         modified, deleted, or subject to a modifyDN operation), otherwise
+   *         {@code false} if the search will initially return all the existing
+   *         entries which match the filter.
+   */
+  public boolean isChangesOnly()
+  {
+    return changesOnly;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * Returns {@code true} if the entry change notification control should be
+   * included in updated entries that match the associated search criteria.
+   *
+   * @return {@code true} if the entry change notification control should be
+   *         included in updated entries that match the associated search
+   *         criteria.
+   */
+  public boolean isReturnECs()
+  {
+    return returnECs;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PersistentSearchRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", changeTypes=[");
+
+    boolean comma = false;
+    for (final PersistentSearchChangeType type : changeTypes)
+    {
+      if (comma)
+      {
+        builder.append(", ");
+      }
+      builder.append(type);
+      comma = true;
+    }
+
+    builder.append("](");
+    builder.append(changeTypes);
+    builder.append("), changesOnly=");
+    builder.append(changesOnly);
+    builder.append(", returnECs=");
+    builder.append(returnECs);
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadRequestControl.java
new file mode 100644
index 0000000..dc4e2c3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadRequestControl.java
@@ -0,0 +1,354 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_POSTREADREQ_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_POSTREADREQ_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_POSTREAD_CONTROL_BAD_OID;
+
+import java.io.IOException;
+import java.util.*;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The post-read request control as defined in RFC 4527. This control allows the
+ * client to read the target entry of an update operation immediately after the
+ * modifications are applied. These reads are done as an atomic part of the
+ * update operation.
+ *
+ * @see PostReadResponseControl
+ * @see <a href="http://tools.ietf.org/html/rfc4527">RFC 4527 - Lightweight
+ *      Directory Access Protocol (LDAP) Read Entry Controls </a>
+ */
+public final class PostReadRequestControl implements Control
+{
+  /**
+   * The IANA-assigned OID for the LDAP post-read request control used for
+   * retrieving an entry in the state it had immediately after an update was
+   * applied.
+   */
+  public static final String OID = "1.3.6.1.1.13.2";
+
+  // The set of raw attributes to return in the entry.
+  private final Set<String> attributes;
+
+  private final boolean isCritical;
+
+  private static final PostReadRequestControl CRITICAL_EMPTY_INSTANCE =
+    new PostReadRequestControl(true, Collections.<String> emptySet());
+
+  private static final PostReadRequestControl NONCRITICAL_EMPTY_INSTANCE =
+    new PostReadRequestControl(false, Collections.<String> emptySet());
+
+  /**
+   * A decoder which can be used for decoding the post-read request control.
+   */
+  public static final ControlDecoder<PostReadRequestControl> DECODER =
+    new ControlDecoder<PostReadRequestControl>()
+  {
+
+    public PostReadRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PostReadRequestControl)
+      {
+        return (PostReadRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_POSTREAD_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The control must always have a value.
+        final LocalizableMessage message = ERR_POSTREADREQ_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      Set<String> attributes;
+      try
+      {
+        reader.readStartSequence();
+        if (reader.hasNextElement())
+        {
+          final String firstAttribute = reader.readOctetStringAsString();
+          if (reader.hasNextElement())
+          {
+            attributes = new LinkedHashSet<String>();
+            attributes.add(firstAttribute);
+            do
+            {
+              attributes.add(reader.readOctetStringAsString());
+            }
+            while (reader.hasNextElement());
+            attributes = Collections.unmodifiableSet(attributes);
+          }
+          else
+          {
+            attributes = Collections.singleton(firstAttribute);
+          }
+        }
+        else
+        {
+          attributes = Collections.emptySet();
+        }
+        reader.readEndSequence();
+      }
+      catch (final Exception ae)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PostReadRequestControl",
+            "decodeControl", ae);
+
+        final LocalizableMessage message = ERR_POSTREADREQ_CANNOT_DECODE_VALUE
+            .get(ae.getMessage());
+        throw DecodeException.error(message, ae);
+      }
+
+      if (attributes.isEmpty())
+      {
+        return control.isCritical() ? CRITICAL_EMPTY_INSTANCE
+            : NONCRITICAL_EMPTY_INSTANCE;
+      }
+      else
+      {
+        return new PostReadRequestControl(control.isCritical(), attributes);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new post-read request control.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored
+   * @param attributes
+   *          The list of attributes to be included with the response control.
+   *          Attributes that are sub-types of listed attributes are implicitly
+   *          included. The list may be empty, indicating that all user
+   *          attributes should be returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code attributes} was {@code null}.
+   */
+  public static PostReadRequestControl newControl(final boolean isCritical,
+      final Collection<String> attributes) throws NullPointerException
+  {
+    Validator.ensureNotNull(attributes);
+
+    if (attributes.isEmpty())
+    {
+      return isCritical ? CRITICAL_EMPTY_INSTANCE : NONCRITICAL_EMPTY_INSTANCE;
+    }
+    else if (attributes.size() == 1)
+    {
+      return new PostReadRequestControl(isCritical, Collections
+          .singleton(attributes.iterator().next()));
+    }
+    else
+    {
+      final Set<String> attributeSet = new LinkedHashSet<String>(attributes);
+      return new PostReadRequestControl(isCritical, Collections
+          .unmodifiableSet(attributeSet));
+    }
+  }
+
+
+
+  /**
+   * Creates a new post-read request control.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored
+   * @param attributes
+   *          The list of attributes to be included with the response control.
+   *          Attributes that are sub-types of listed attributes are implicitly
+   *          included. The list may be empty, indicating that all user
+   *          attributes should be returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code attributes} was {@code null}.
+   */
+  public static PostReadRequestControl newControl(final boolean isCritical,
+      final String... attributes) throws NullPointerException
+  {
+    Validator.ensureNotNull((Object) attributes);
+
+    if (attributes.length == 0)
+    {
+      return isCritical ? CRITICAL_EMPTY_INSTANCE : NONCRITICAL_EMPTY_INSTANCE;
+    }
+    else if (attributes.length == 1)
+    {
+      return new PostReadRequestControl(isCritical, Collections
+          .singleton(attributes[0]));
+    }
+    else
+    {
+      final Set<String> attributeSet = new LinkedHashSet<String>(Arrays
+          .asList(attributes));
+      return new PostReadRequestControl(isCritical, Collections
+          .unmodifiableSet(attributeSet));
+    }
+  }
+
+
+
+  private PostReadRequestControl(final boolean isCritical,
+      final Set<String> attributes)
+  {
+    this.isCritical = isCritical;
+    this.attributes = attributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the names of attributes to be
+   * included with the response control. Attributes that are sub-types of listed
+   * attributes are implicitly included. The returned set may be empty,
+   * indicating that all user attributes should be returned.
+   *
+   * @return An unmodifiable set containing the names of attributes to be
+   *         included with the response control.
+   */
+  public Set<String> getAttributes()
+  {
+    return attributes;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      if (attributes != null)
+      {
+        for (final String attr : attributes)
+        {
+          writer.writeOctetString(attr);
+        }
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PostReadRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", attributes=");
+    builder.append(attributes);
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadResponseControl.java
new file mode 100644
index 0000000..56f7631
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PostReadResponseControl.java
@@ -0,0 +1,259 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_POSTREADRESP_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_POSTREADRESP_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_POSTREAD_CONTROL_BAD_OID;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.SearchResultEntry;
+
+import com.sun.opends.sdk.ldap.LDAPUtils;
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The post-read response control as defined in RFC 4527. This control is
+ * returned by the server in response to a successful update operation which
+ * included a post-read request control. The control contains a Search Result
+ * Entry containing, subject to access controls and other constraints, values of
+ * the requested attributes.
+ *
+ * @see PostReadRequestControl
+ * @see <a href="http://tools.ietf.org/html/rfc4527">RFC 4527 - Lightweight
+ *      Directory Access Protocol (LDAP) Read Entry Controls </a>
+ */
+public final class PostReadResponseControl implements Control
+{
+  /**
+   * The IANA-assigned OID for the LDAP post-read response control used for
+   * retrieving an entry in the state it had immediately after an update was
+   * applied.
+   */
+  public static final String OID = PostReadRequestControl.OID;
+
+  /**
+   * A decoder which can be used for decoding the post-read response control.
+   */
+  public static final ControlDecoder<PostReadResponseControl> DECODER =
+    new ControlDecoder<PostReadResponseControl>()
+  {
+
+    public PostReadResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PostReadResponseControl)
+      {
+        return (PostReadResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_POSTREAD_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The control must always have a value.
+        final LocalizableMessage message = ERR_POSTREADRESP_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      SearchResultEntry searchEntry;
+      try
+      {
+        searchEntry = LDAPUtils.decodeSearchResultEntry(reader, options);
+      }
+      catch (final IOException le)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PostReadResponseControl",
+            "decodeControl", le);
+
+        final LocalizableMessage message = ERR_POSTREADRESP_CANNOT_DECODE_VALUE
+            .get(le.getMessage());
+        throw DecodeException.error(message, le);
+      }
+
+      /**
+       * FIXME: the RFC states that the control contains a SearchResultEntry
+       * rather than an Entry. Can we assume that the response will not contain
+       * a nested set of controls?
+       */
+      return new PostReadResponseControl(control.isCritical(), Entries
+          .unmodifiableEntry(searchEntry));
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new post-read response control.
+   *
+   * @param entry
+   *          The entry whose contents reflect the state of the updated entry
+   *          immediately after the update operation was performed.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public static PostReadResponseControl newControl(final Entry entry)
+      throws NullPointerException
+  {
+    /**
+     * FIXME: all other control implementations are fully immutable. We should
+     * really do a defensive copy here in order to be consistent, rather than
+     * just wrap it. Also, the RFC states that the control contains a
+     * SearchResultEntry rather than an Entry. Can we assume that the response
+     * will not contain a nested set of controls?
+     */
+    return new PostReadResponseControl(false, Entries.unmodifiableEntry(entry));
+  }
+
+
+
+  private final Entry entry;
+
+  private final boolean isCritical;
+
+
+
+  private PostReadResponseControl(final boolean isCritical, final Entry entry)
+  {
+    this.isCritical = isCritical;
+    this.entry = entry;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable entry whose contents reflect the state of the
+   * updated entry immediately after the update operation was performed.
+   *
+   * @return The unmodifiable entry whose contents reflect the state of the
+   *         updated entry immediately after the update operation was performed.
+   */
+  public Entry getEntry()
+  {
+    return entry;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      LDAPUtils.encodeSearchResultEntry(writer, Responses
+          .newSearchResultEntry(entry));
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PostReadResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", entry=");
+    builder.append(entry);
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadRequestControl.java
new file mode 100644
index 0000000..9310876
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadRequestControl.java
@@ -0,0 +1,354 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_PREREADREQ_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_PREREADREQ_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_PREREAD_CONTROL_BAD_OID;
+
+import java.io.IOException;
+import java.util.*;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The pre-read request control as defined in RFC 4527. This control allows the
+ * client to read the target entry of an update operation immediately before the
+ * modifications are applied. These reads are done as an atomic part of the
+ * update operation.
+ *
+ * @see PreReadResponseControl
+ * @see <a href="http://tools.ietf.org/html/rfc4527">RFC 4527 - Lightweight
+ *      Directory Access Protocol (LDAP) Read Entry Controls </a>
+ */
+public final class PreReadRequestControl implements Control
+{
+  /**
+   * The IANA-assigned OID for the LDAP pre-read request control used for
+   * retrieving an entry in the state it had immediately before an update was
+   * applied.
+   */
+  public static final String OID = "1.3.6.1.1.13.1";
+
+  // The set of raw attributes to return in the entry.
+  private final Set<String> attributes;
+
+  private final boolean isCritical;
+
+  private static final PreReadRequestControl CRITICAL_EMPTY_INSTANCE = new PreReadRequestControl(
+      true, Collections.<String> emptySet());
+
+  private static final PreReadRequestControl NONCRITICAL_EMPTY_INSTANCE = new PreReadRequestControl(
+      false, Collections.<String> emptySet());
+
+  /**
+   * A decoder which can be used for decoding the pre-read request control.
+   */
+  public static final ControlDecoder<PreReadRequestControl> DECODER =
+    new ControlDecoder<PreReadRequestControl>()
+  {
+
+    public PreReadRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PreReadRequestControl)
+      {
+        return (PreReadRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PREREAD_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The control must always have a value.
+        final LocalizableMessage message = ERR_PREREADREQ_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      Set<String> attributes;
+      try
+      {
+        reader.readStartSequence();
+        if (reader.hasNextElement())
+        {
+          final String firstAttribute = reader.readOctetStringAsString();
+          if (reader.hasNextElement())
+          {
+            attributes = new LinkedHashSet<String>();
+            attributes.add(firstAttribute);
+            do
+            {
+              attributes.add(reader.readOctetStringAsString());
+            }
+            while (reader.hasNextElement());
+            attributes = Collections.unmodifiableSet(attributes);
+          }
+          else
+          {
+            attributes = Collections.singleton(firstAttribute);
+          }
+        }
+        else
+        {
+          attributes = Collections.emptySet();
+        }
+        reader.readEndSequence();
+      }
+      catch (final Exception ae)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PreReadRequestControl",
+            "decodeControl", ae);
+
+        final LocalizableMessage message = ERR_PREREADREQ_CANNOT_DECODE_VALUE
+            .get(ae.getMessage());
+        throw DecodeException.error(message, ae);
+      }
+
+      if (attributes.isEmpty())
+      {
+        return control.isCritical() ? CRITICAL_EMPTY_INSTANCE
+            : NONCRITICAL_EMPTY_INSTANCE;
+      }
+      else
+      {
+        return new PreReadRequestControl(control.isCritical(), attributes);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new pre-read request control.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored
+   * @param attributes
+   *          The list of attributes to be included with the response control.
+   *          Attributes that are sub-types of listed attributes are implicitly
+   *          included. The list may be empty, indicating that all user
+   *          attributes should be returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code attributes} was {@code null}.
+   */
+  public static PreReadRequestControl newControl(final boolean isCritical,
+      final Collection<String> attributes) throws NullPointerException
+  {
+    Validator.ensureNotNull(attributes);
+
+    if (attributes.isEmpty())
+    {
+      return isCritical ? CRITICAL_EMPTY_INSTANCE : NONCRITICAL_EMPTY_INSTANCE;
+    }
+    else if (attributes.size() == 1)
+    {
+      return new PreReadRequestControl(isCritical, Collections
+          .singleton(attributes.iterator().next()));
+    }
+    else
+    {
+      final Set<String> attributeSet = new LinkedHashSet<String>(attributes);
+      return new PreReadRequestControl(isCritical, Collections
+          .unmodifiableSet(attributeSet));
+    }
+  }
+
+
+
+  /**
+   * Creates a new pre-read request control.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored
+   * @param attributes
+   *          The list of attributes to be included with the response control.
+   *          Attributes that are sub-types of listed attributes are implicitly
+   *          included. The list may be empty, indicating that all user
+   *          attributes should be returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code attributes} was {@code null}.
+   */
+  public static PreReadRequestControl newControl(final boolean isCritical,
+      final String... attributes) throws NullPointerException
+  {
+    Validator.ensureNotNull((Object) attributes);
+
+    if (attributes.length == 0)
+    {
+      return isCritical ? CRITICAL_EMPTY_INSTANCE : NONCRITICAL_EMPTY_INSTANCE;
+    }
+    else if (attributes.length == 1)
+    {
+      return new PreReadRequestControl(isCritical, Collections
+          .singleton(attributes[0]));
+    }
+    else
+    {
+      final Set<String> attributeSet = new LinkedHashSet<String>(Arrays
+          .asList(attributes));
+      return new PreReadRequestControl(isCritical, Collections
+          .unmodifiableSet(attributeSet));
+    }
+  }
+
+
+
+  private PreReadRequestControl(final boolean isCritical,
+      final Set<String> attributes)
+  {
+    this.isCritical = isCritical;
+    this.attributes = attributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the names of attributes to be
+   * included with the response control. Attributes that are sub-types of listed
+   * attributes are implicitly included. The returned set may be empty,
+   * indicating that all user attributes should be returned.
+   *
+   * @return An unmodifiable set containing the names of attributes to be
+   *         included with the response control.
+   */
+  public Set<String> getAttributes()
+  {
+    return attributes;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      if (attributes != null)
+      {
+        for (final String attr : attributes)
+        {
+          writer.writeOctetString(attr);
+        }
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PreReadRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", attributes=");
+    builder.append(attributes);
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadResponseControl.java
new file mode 100644
index 0000000..5f5953b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/PreReadResponseControl.java
@@ -0,0 +1,260 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_PREREADRESP_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_PREREADRESP_NO_CONTROL_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_PREREAD_CONTROL_BAD_OID;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.SearchResultEntry;
+
+import com.sun.opends.sdk.ldap.LDAPUtils;
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The pre-read response control as defined in RFC 4527. This control is
+ * returned by the server in response to a successful update operation which
+ * included a pre-read request control. The control contains a Search Result
+ * Entry containing, subject to access controls and other constraints, values of
+ * the requested attributes.
+ *
+ * @see PreReadRequestControl
+ * @see <a href="http://tools.ietf.org/html/rfc4527">RFC 4527 - Lightweight
+ *      Directory Access Protocol (LDAP) Read Entry Controls </a>
+ */
+public final class PreReadResponseControl implements Control
+{
+  /**
+   * The IANA-assigned OID for the LDAP pre-read response control used for
+   * retrieving an entry in the state it had immediately before an update was
+   * applied.
+   */
+  public static final String OID = PreReadRequestControl.OID;
+
+  /**
+   * A decoder which can be used for decoding the pre-read response control.
+   */
+  public static final ControlDecoder<PreReadResponseControl> DECODER =
+    new ControlDecoder<PreReadResponseControl>()
+  {
+
+    public PreReadResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof PreReadResponseControl)
+      {
+        return (PreReadResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PREREAD_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The control must always have a value.
+        final LocalizableMessage message = ERR_PREREADRESP_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      SearchResultEntry searchEntry;
+      try
+      {
+        searchEntry = LDAPUtils.decodeSearchResultEntry(reader, options);
+      }
+      catch (final IOException le)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PreReadResponseControl",
+            "decodeControl", le);
+
+        final LocalizableMessage message = ERR_PREREADRESP_CANNOT_DECODE_VALUE
+            .get(le.getMessage());
+        throw DecodeException.error(message, le);
+      }
+
+      /**
+       * FIXME: the RFC states that the control contains a SearchResultEntry
+       * rather than an Entry. Can we assume that the response will not contain
+       * a nested set of controls?
+       */
+      return new PreReadResponseControl(control.isCritical(), Entries
+          .unmodifiableEntry(searchEntry));
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new pre-read response control.
+   *
+   * @param entry
+   *          The entry whose contents reflect the state of the updated entry
+   *          immediately before the update operation was performed.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public static PreReadResponseControl newControl(final Entry entry)
+      throws NullPointerException
+  {
+    /**
+     * FIXME: all other control implementations are fully immutable. We should
+     * really do a defensive copy here in order to be consistent, rather than
+     * just wrap it. Also, the RFC states that the control contains a
+     * SearchResultEntry rather than an Entry. Can we assume that the response
+     * will not contain a nested set of controls?
+     */
+    return new PreReadResponseControl(false, Entries.unmodifiableEntry(entry));
+  }
+
+
+
+  private final Entry entry;
+
+  private final boolean isCritical;
+
+
+
+  private PreReadResponseControl(final boolean isCritical, final Entry entry)
+  {
+    this.isCritical = isCritical;
+    this.entry = entry;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable entry whose contents reflect the state of the
+   * updated entry immediately before the update operation was performed.
+   *
+   * @return The unmodifiable entry whose contents reflect the state of the
+   *         updated entry immediately before the update operation was
+   *         performed.
+   */
+  public Entry getEntry()
+  {
+    return entry;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      LDAPUtils.encodeSearchResultEntry(writer, Responses
+          .newSearchResultEntry(entry));
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PreReadResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", entry=");
+    builder.append(entry);
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV1RequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV1RequestControl.java
new file mode 100644
index 0000000..80d9394
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV1RequestControl.java
@@ -0,0 +1,294 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The proxy authorization v1 request control as defined in
+ * draft-weltman-ldapv3-proxy-04. This control allows a user to request that an
+ * operation be performed using the authorization of another user. The target
+ * user is specified as a DN in the control value, which distinguishes it from
+ * later versions of the control (which used a different OID) in which the
+ * target user was specified using an authorization ID.
+ * <p>
+ * This control implementation is based on version 1 of the proxied
+ * authorization control as defined in early versions of
+ * draft-weltman-ldapv3-proxy (this implementation is based on the "-04"
+ * revision) and is intended for use in legacy applications. New applications
+ * should use the v2 version of this control in preference.
+ *
+ * @see <a href="http://tools.ietf.org/html/draft-weltman-ldapv3-proxy-04">
+ *         draft-weltman-ldapv3-proxy-04 - LDAP Proxied Authorization Control </a>
+ */
+public final class ProxiedAuthV1RequestControl implements Control
+{
+  /**
+   * The OID for the proxied authorization v1 control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.12";
+
+  /**
+   * A decoder which can be used for decoding the proxied authorization v1
+   * request control.
+   */
+  public static final ControlDecoder<ProxiedAuthV1RequestControl> DECODER =
+    new ControlDecoder<ProxiedAuthV1RequestControl>()
+  {
+
+    public ProxiedAuthV1RequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof ProxiedAuthV1RequestControl)
+      {
+        return (ProxiedAuthV1RequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PROXYAUTH1_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.isCritical())
+      {
+        final LocalizableMessage message = ERR_PROXYAUTH1_CONTROL_NOT_CRITICAL
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_PROXYAUTH1_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      String authorizationDNString;
+      try
+      {
+        reader.readStartSequence();
+        authorizationDNString = reader.readOctetStringAsString();
+        reader.readEndSequence();
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("ProxiedAuthV1RequestControl",
+            "decodeControl", e);
+
+        final LocalizableMessage message = ERR_PROXYAUTH1_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+
+      final Schema schema = options.getSchemaResolver().resolveSchema(
+          authorizationDNString);
+      DN authorizationDN;
+      try
+      {
+        authorizationDN = DN.valueOf(authorizationDNString, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        final LocalizableMessage message = ERR_PROXYAUTH1_INVALID_AUTHZIDDN
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+
+      return new ProxiedAuthV1RequestControl(authorizationDN);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new proxy authorization v1 request control with the provided
+   * authorization name.
+   *
+   * @param authorizationName
+   *          The distinguished name of the user whose authorization is to be
+   *          used when performing the operation.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code authorizationName} was {@code null}.
+   */
+  public static ProxiedAuthV1RequestControl newControl(
+      final DN authorizationName) throws NullPointerException
+  {
+    Validator.ensureNotNull(authorizationName);
+    return new ProxiedAuthV1RequestControl(authorizationName);
+  }
+
+
+
+  /**
+   * Creates a new proxy authorization v1 request control with the provided
+   * authorization name decoded using the default schema.
+   *
+   * @param authorizationName
+   *          The distinguished name of the user whose authorization is to be
+   *          used when performing the operation.
+   * @return The new control.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationName} is not a valid LDAP string
+   *           representation of a DN.
+   * @throws NullPointerException
+   *           If {@code authorizationName} was {@code null}.
+   */
+  public static ProxiedAuthV1RequestControl newControl(
+      final String authorizationName) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(authorizationName);
+    return new ProxiedAuthV1RequestControl(DN.valueOf(authorizationName));
+  }
+
+
+
+  private final DN authorizationName;
+
+
+
+  private ProxiedAuthV1RequestControl(final DN authorizationName)
+  {
+    this.authorizationName = authorizationName;
+  }
+
+
+
+  /**
+   * Returns the distinguished name of the user whose authorization is to be
+   * used when performing the operation.
+   *
+   * @return The distinguished name of the user whose authorization is to be
+   *         used when performing the operation.
+   */
+  public DN getAuthorizationDNName()
+  {
+    return authorizationName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeOctetString(authorizationName.toString());
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder buffer = new StringBuilder();
+    buffer.append("ProxiedAuthorizationV1Control(oid=");
+    buffer.append(getOID());
+    buffer.append(", criticality=");
+    buffer.append(isCritical());
+    buffer.append(", proxyDN=\"");
+    buffer.append(authorizationName);
+    buffer.append("\")");
+    return buffer.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV2RequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV2RequestControl.java
new file mode 100644
index 0000000..fb90c3a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ProxiedAuthV2RequestControl.java
@@ -0,0 +1,283 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The proxy authorization v2 request control as defined in RFC 4370. This
+ * control allows a user to request that an operation be performed using the
+ * authorization of another user.
+ * <p>
+ * The target user is specified using an authorization ID, or {@code authzId},
+ * as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4370">RFC 4370 - Lightweight
+ *      Directory Access Protocol (LDAP) Proxied Authorization Control </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public final class ProxiedAuthV2RequestControl implements Control
+{
+  /**
+   * The OID for the proxied authorization v2 control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.18";
+
+  private static final ProxiedAuthV2RequestControl ANONYMOUS = new ProxiedAuthV2RequestControl(
+      "");
+
+  /**
+   * A decoder which can be used for decoding the proxied authorization v2
+   * request control.
+   */
+  public static final ControlDecoder<ProxiedAuthV2RequestControl> DECODER =
+    new ControlDecoder<ProxiedAuthV2RequestControl>()
+  {
+
+    public ProxiedAuthV2RequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof ProxiedAuthV2RequestControl)
+      {
+        return (ProxiedAuthV2RequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_PROXYAUTH2_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.isCritical())
+      {
+        final LocalizableMessage message = ERR_PROXYAUTH2_CONTROL_NOT_CRITICAL
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = ERR_PROXYAUTH2_NO_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      String authorizationID;
+      try
+      {
+        if (reader.elementAvailable())
+        {
+          // Try the legacy encoding where the value is wrapped by an
+          // extra octet string
+          authorizationID = reader.readOctetStringAsString();
+        }
+        else
+        {
+          authorizationID = control.getValue().toString();
+        }
+      }
+      catch (final IOException e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("ProxiedAuthV2RequestControl",
+            "decodeControl", e);
+
+        final LocalizableMessage message = ERR_PROXYAUTH2_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+
+      if (authorizationID.length() == 0)
+      {
+        // Anonymous.
+        return ANONYMOUS;
+      }
+
+      final int colonIndex = authorizationID.indexOf(':');
+      if (colonIndex < 0)
+      {
+        final LocalizableMessage message = ERR_PROXYAUTH2_INVALID_AUTHZID_TYPE
+            .get(authorizationID);
+        throw DecodeException.error(message);
+      }
+
+      return new ProxiedAuthV2RequestControl(authorizationID);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new proxy authorization v2 request control with the provided
+   * authorization ID. The authorization ID usually has the form "dn:"
+   * immediately followed by the distinguished name of the user, or "u:"
+   * followed by a user ID string, but other forms are permitted.
+   *
+   * @param authorizationID
+   *          The authorization ID of the user whose authorization is to be used
+   *          when performing the operation.
+   * @return The new control.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   * @throws NullPointerException
+   *           If {@code authorizationName} was {@code null}.
+   */
+  public static final ProxiedAuthV2RequestControl newControl(
+      final String authorizationID) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    if (authorizationID.length() == 0)
+    {
+      // Anonymous.
+      return ANONYMOUS;
+    }
+
+    final int colonIndex = authorizationID.indexOf(':');
+    if (colonIndex < 0)
+    {
+      final LocalizableMessage message = ERR_PROXYAUTH2_INVALID_AUTHZID_TYPE
+          .get(authorizationID);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+
+    return new ProxiedAuthV2RequestControl(authorizationID);
+  }
+
+
+
+  // The authorization ID from the control value.
+  private final String authorizationID;
+
+
+
+  private ProxiedAuthV2RequestControl(final String authorizationID)
+  {
+    this.authorizationID = authorizationID;
+  }
+
+
+
+  /**
+   * Returns the authorization ID of the user whose authorization is to be used
+   * when performing the operation. The authorization ID usually has the form
+   * "dn:" immediately followed by the distinguished name of the user, or "u:"
+   * followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authorization ID of the user whose authorization is to be used
+   *         when performing the operation.
+   */
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return ByteString.valueOf(authorizationID);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ProxiedAuthorizationV2Control(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", authorizationID=\"");
+    builder.append(authorizationID);
+    builder.append("\")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortRequestControl.java
new file mode 100644
index 0000000..d6e3de4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortRequestControl.java
@@ -0,0 +1,393 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+import java.util.*;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The server-side sort request control as defined in RFC 2891. This control may
+ * be included in a search request to indicate that search result entries should
+ * be sorted by the server before being returned. The sort order is specified
+ * using one or more sort keys, the first being the primary key, and so on.
+ * <p>
+ * This controls may be useful when the client has limited functionality or for
+ * some other reason cannot sort the results but still needs them sorted. In
+ * cases where the client can sort the results client-side sorting is
+ * recommended in order to reduce load on the server. See {@link SortKey} for
+ * more an example of client-side sorting.
+ *
+ * @see ServerSideSortResponseControl
+ * @see SortKey
+ * @see <a href="http://tools.ietf.org/html/rfc2891">RFC 2891 - LDAP Control
+ *      Extension for Server Side Sorting of Search Results </a>
+ */
+public final class ServerSideSortRequestControl implements Control
+{
+  /**
+   * The OID for the server-side sort request control.
+   */
+  public static final String OID = "1.2.840.113556.1.4.473";
+
+  /**
+   * The BER type to use when encoding the orderingRule element.
+   */
+  private static final byte TYPE_ORDERING_RULE_ID = (byte) 0x80;
+
+  /**
+   * The BER type to use when encoding the reverseOrder element.
+   */
+  private static final byte TYPE_REVERSE_ORDER = (byte) 0x81;
+
+  /**
+   * A decoder which can be used for decoding the server side sort request
+   * control.
+   */
+  public static final ControlDecoder<ServerSideSortRequestControl> DECODER =
+    new ControlDecoder<ServerSideSortRequestControl>()
+  {
+
+    public ServerSideSortRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof ServerSideSortRequestControl)
+      {
+        return (ServerSideSortRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_SORTREQ_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The request control must always have a value.
+        final LocalizableMessage message = INFO_SORTREQ_CONTROL_NO_VALUE.get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        reader.readStartSequence();
+        if (!reader.hasNextElement())
+        {
+          final LocalizableMessage message = INFO_SORTREQ_CONTROL_NO_SORT_KEYS
+              .get();
+          throw DecodeException.error(message);
+        }
+
+        final List<SortKey> keys = new LinkedList<SortKey>();
+        while (reader.hasNextElement())
+        {
+          reader.readStartSequence();
+          final String attrName = reader.readOctetStringAsString();
+
+          String orderingRule = null;
+          boolean reverseOrder = false;
+          if (reader.hasNextElement()
+              && (reader.peekType() == TYPE_ORDERING_RULE_ID))
+          {
+            orderingRule = reader.readOctetStringAsString();
+          }
+          if (reader.hasNextElement()
+              && (reader.peekType() == TYPE_REVERSE_ORDER))
+          {
+            reverseOrder = reader.readBoolean();
+          }
+          reader.readEndSequence();
+
+          keys.add(new SortKey(attrName, reverseOrder, orderingRule));
+        }
+        reader.readEndSequence();
+
+        return new ServerSideSortRequestControl(control.isCritical(),
+            Collections.unmodifiableList(keys));
+      }
+      catch (final IOException e)
+      {
+        final LocalizableMessage message = INFO_SORTREQ_CONTROL_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new server side sort request control with the provided
+   * criticality and list of sort keys.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param keys
+   *          The list of sort keys.
+   * @return The new control.
+   * @throws IllegalArgumentException
+   *           If {@code keys} was empty.
+   * @throws NullPointerException
+   *           If {@code keys} was {@code null}.
+   */
+  public static ServerSideSortRequestControl newControl(
+      final boolean isCritical, final Collection<SortKey> keys)
+      throws IllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(keys);
+    Validator.ensureTrue(!keys.isEmpty(), "keys must not be empty");
+
+    return new ServerSideSortRequestControl(isCritical, Collections
+        .unmodifiableList(new ArrayList<SortKey>(keys)));
+  }
+
+
+
+  /**
+   * Creates a new server side sort request control with the provided
+   * criticality and list of sort keys.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param firstKey
+   *          The first sort key.
+   * @param remainingKeys
+   *          The remaining sort keys.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code firstKey} was {@code null}.
+   */
+  public static ServerSideSortRequestControl newControl(
+      final boolean isCritical, final SortKey firstKey,
+      final SortKey... remainingKeys) throws NullPointerException
+  {
+    Validator.ensureNotNull(firstKey, remainingKeys);
+
+    final List<SortKey> keys = new ArrayList<SortKey>(1 + remainingKeys.length);
+    keys.add(firstKey);
+    for (final SortKey key : remainingKeys)
+    {
+      keys.add(key);
+    }
+    return new ServerSideSortRequestControl(isCritical, Collections
+        .unmodifiableList(keys));
+  }
+
+
+
+  /**
+   * Creates a new server side sort request control with the provided
+   * criticality and string representation of a list of sort keys. The string
+   * representation is comprised of a comma separate list of sort keys as
+   * defined in {@link SortKey#valueOf(String)}. There must be at least one sort
+   * key present in the string representation.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param sortKeys
+   *          The list of sort keys.
+   * @return The new control.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code sortKeys} is not a valid string representation of a
+   *           list of sort keys.
+   * @throws NullPointerException
+   *           If {@code sortKeys} was {@code null}.
+   */
+  public static ServerSideSortRequestControl newControl(
+      final boolean isCritical, final String sortKeys)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(sortKeys);
+
+    final List<SortKey> keys = new LinkedList<SortKey>();
+    final StringTokenizer tokenizer = new StringTokenizer(sortKeys, ",");
+    while (tokenizer.hasMoreTokens())
+    {
+      final String token = tokenizer.nextToken().trim();
+      keys.add(SortKey.valueOf(token));
+    }
+    if (keys.isEmpty())
+    {
+      final LocalizableMessage message = ERR_SORT_KEY_NO_SORT_KEYS
+          .get(sortKeys);
+      throw new LocalizedIllegalArgumentException(message);
+    }
+    return new ServerSideSortRequestControl(isCritical, Collections
+        .unmodifiableList(keys));
+  }
+
+
+
+  private final List<SortKey> sortKeys;
+
+  private final boolean isCritical;
+
+
+
+  private ServerSideSortRequestControl(final boolean isCritical,
+      final List<SortKey> keys)
+  {
+    this.isCritical = isCritical;
+    this.sortKeys = keys;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the sort keys associated with this
+   * server side sort request control. The list will contain at least one sort
+   * key.
+   *
+   * @return An unmodifiable list containing the sort keys associated with this
+   *         server side sort request control.
+   */
+  public List<SortKey> getSortKeys()
+  {
+    return sortKeys;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      for (final SortKey sortKey : sortKeys)
+      {
+        writer.writeStartSequence();
+        writer.writeOctetString(sortKey.getAttributeDescription());
+
+        if (sortKey.getOrderingMatchingRule() != null)
+        {
+          writer.writeOctetString(TYPE_ORDERING_RULE_ID, sortKey
+              .getOrderingMatchingRule());
+        }
+
+        if (!sortKey.isReverseOrder())
+        {
+          writer.writeBoolean(TYPE_REVERSE_ORDER, true);
+        }
+
+        writer.writeEndSequence();
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder buffer = new StringBuilder();
+    buffer.append("ServerSideSortRequestControl(oid=");
+    buffer.append(getOID());
+    buffer.append(", criticality=");
+    buffer.append(isCritical());
+    buffer.append(", sortKeys=");
+    buffer.append(sortKeys);
+    buffer.append(")");
+    return buffer.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortResponseControl.java
new file mode 100644
index 0000000..5ef551b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/ServerSideSortResponseControl.java
@@ -0,0 +1,376 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_SORTRES_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.INFO_SORTRES_CONTROL_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.INFO_SORTRES_CONTROL_NO_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The server-side sort response control as defined in RFC 2891. This control is
+ * included with a search result in response to a server-side sort request
+ * included with a search request. The client application is assured that the
+ * search results are sorted in the specified key order if and only if the
+ * result code in this control is success. If the server omits this control from
+ * the search result, the client SHOULD assume that the sort control was ignored
+ * by the server.
+ *
+ * @see ServerSideSortRequestControl
+ * @see <a href="http://tools.ietf.org/html/rfc2891">RFC 2891 - LDAP Control
+ *      Extension for Server Side Sorting of Search Results </a>
+ */
+public final class ServerSideSortResponseControl implements Control
+{
+  /**
+   * The OID for the server-side sort response control.
+   */
+  public static final String OID = "1.2.840.113556.1.4.474";
+
+  /**
+   * A decoder which can be used for decoding the server side sort response
+   * control.
+   */
+  public static final ControlDecoder<ServerSideSortResponseControl> DECODER =
+    new ControlDecoder<ServerSideSortResponseControl>()
+  {
+
+    public ServerSideSortResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control, options);
+
+      if (control instanceof ServerSideSortResponseControl)
+      {
+        return (ServerSideSortResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_SORTRES_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The request control must always have a value.
+        final LocalizableMessage message = INFO_SORTRES_CONTROL_NO_VALUE.get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        reader.readStartSequence();
+
+        // FIXME: should really check that result code is one of the expected
+        // values listed in the RFC.
+        final ResultCode result = ResultCode.valueOf(reader.readEnumerated());
+
+        AttributeDescription attributeDescription = null;
+        if (reader.hasNextElement())
+        {
+          // FIXME: which schema should we use?
+          final Schema schema = options.getSchemaResolver().resolveSchema("");
+          final String ads = reader.readOctetStringAsString();
+          attributeDescription = AttributeDescription.valueOf(ads, schema);
+        }
+
+        return new ServerSideSortResponseControl(control.isCritical(), result,
+            attributeDescription);
+      }
+      catch (final IOException e)
+      {
+        final LocalizableMessage message = INFO_SORTRES_CONTROL_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        final LocalizableMessage message = INFO_SORTRES_CONTROL_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+  /**
+   * The BER type to use when encoding the attribute type element.
+   */
+  private static final byte TYPE_ATTRIBUTE_TYPE = (byte) 0x80;
+
+
+
+  /**
+   * Creates a new server-side response control with the provided sort result
+   * and no attribute description.
+   *
+   * @param result
+   *          The result code indicating the outcome of the server-side sort
+   *          request. {@link ResultCode#SUCCESS} if the search results were
+   *          sorted in accordance with the keys specified in the server-side
+   *          sort request control, or an error code indicating why the results
+   *          could not be sorted (such as {@link ResultCode#NO_SUCH_ATTRIBUTE}
+   *          or {@link ResultCode#INAPPROPRIATE_MATCHING}).
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static ServerSideSortResponseControl newControl(final ResultCode result)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(result);
+
+    return new ServerSideSortResponseControl(false, result, null);
+  }
+
+
+
+  /**
+   * Creates a new server-side response control with the provided sort result
+   * and attribute description.
+   *
+   * @param result
+   *          The result code indicating the outcome of the server-side sort
+   *          request. {@link ResultCode#SUCCESS} if the search results were
+   *          sorted in accordance with the keys specified in the server-side
+   *          sort request control, or an error code indicating why the results
+   *          could not be sorted (such as {@link ResultCode#NO_SUCH_ATTRIBUTE}
+   *          or {@link ResultCode#INAPPROPRIATE_MATCHING}).
+   * @param attributeDescription
+   *          The first attribute description specified in the list of sort keys
+   *          that was in error, may be {@code null}.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static ServerSideSortResponseControl newControl(
+      final ResultCode result, final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(result);
+
+    return new ServerSideSortResponseControl(false, result,
+        attributeDescription);
+  }
+
+
+
+  /**
+   * Creates a new server-side response control with the provided sort result
+   * and attribute description. The attribute description will be decoded using
+   * the default schema.
+   *
+   * @param result
+   *          The result code indicating the outcome of the server-side sort
+   *          request. {@link ResultCode#SUCCESS} if the search results were
+   *          sorted in accordance with the keys specified in the server-side
+   *          sort request control, or an error code indicating why the results
+   *          could not be sorted (such as {@link ResultCode#NO_SUCH_ATTRIBUTE}
+   *          or {@link ResultCode#INAPPROPRIATE_MATCHING}).
+   * @param attributeDescription
+   *          The first attribute description specified in the list of sort keys
+   *          that was in error, may be {@code null}.
+   * @return The new control.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be parsed using the
+   *           default schema.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static ServerSideSortResponseControl newControl(
+      final ResultCode result, final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(result);
+
+    if (attributeDescription != null)
+    {
+      return new ServerSideSortResponseControl(false, result,
+          AttributeDescription.valueOf(attributeDescription));
+    }
+    else
+    {
+      return new ServerSideSortResponseControl(false, result, null);
+    }
+  }
+
+
+
+  private final ResultCode result;
+
+  private final AttributeDescription attributeDescription;
+
+  private final boolean isCritical;
+
+
+
+  private ServerSideSortResponseControl(final boolean isCritical,
+      final ResultCode result, final AttributeDescription attributeDescription)
+  {
+    this.isCritical = isCritical;
+    this.result = result;
+    this.attributeDescription = attributeDescription;
+  }
+
+
+
+  /**
+   * Returns the first attribute description specified in the list of sort keys
+   * that was in error, or {@code null} if the attribute description was not
+   * included with this control.
+   *
+   * @return The first attribute description specified in the list of sort keys
+   *         that was in error.
+   */
+  public AttributeDescription getAttributeDescription()
+  {
+    return attributeDescription;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns a result code indicating the outcome of the server-side sort
+   * request. This will be {@link ResultCode#SUCCESS} if the search results were
+   * sorted in accordance with the keys specified in the server-side sort
+   * request control, or an error code indicating why the results could not be
+   * sorted (such as {@link ResultCode#NO_SUCH_ATTRIBUTE} or
+   * {@link ResultCode#INAPPROPRIATE_MATCHING}).
+   *
+   * @return The result code indicating the outcome of the server-side sort
+   *         request.
+   */
+  public ResultCode getResult()
+  {
+    return result;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeEnumerated(result.intValue());
+      if (attributeDescription != null)
+      {
+        writer.writeOctetString(TYPE_ATTRIBUTE_TYPE, attributeDescription
+            .toString());
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ServerSideSortResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", result=");
+    builder.append(result);
+    if (attributeDescription != null)
+    {
+      builder.append(", attributeDescription=");
+      builder.append(attributeDescription);
+    }
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SimplePagedResultsControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SimplePagedResultsControl.java
new file mode 100644
index 0000000..bea06b7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SimplePagedResultsControl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The simple paged results request and response control as defined in RFC 2696.
+ * This control allows a client to control the rate at which an LDAP server
+ * returns the results of an LDAP search operation. This control may be useful
+ * when the LDAP client has limited resources and may not be able to process the
+ * entire result set from a given LDAP query, or when the LDAP client is
+ * connected over a low-bandwidth connection.
+ * <p>
+ * This control is included in the searchRequest and searchResultDone messages
+ * and has the following structure:
+ *
+ * <pre>
+ * realSearchControlValue ::= SEQUENCE {
+ *         size            INTEGER (0..maxInt),
+ *                                 -- requested page size from client
+ *                                 -- result set size estimate from server
+ *         cookie          OCTET STRING
+ * }
+ * </pre>
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2696">RFC 2696 - LDAP Control
+ *      Extension for Simple Paged Results Manipulation </a>
+ */
+public final class SimplePagedResultsControl implements Control
+{
+  /**
+   * The OID for the paged results request/response control defined in RFC 2696.
+   */
+  public static final String OID = "1.2.840.113556.1.4.319";
+
+  /**
+   * A decoder which can be used for decoding the simple paged results control.
+   */
+  public static final ControlDecoder<SimplePagedResultsControl> DECODER =
+    new ControlDecoder<SimplePagedResultsControl>()
+  {
+
+    public SimplePagedResultsControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof SimplePagedResultsControl)
+      {
+        return (SimplePagedResultsControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The control must always have a value.
+        final LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_NULL
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        reader.readStartSequence();
+      }
+      catch (final Exception e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PagedResultsControl.Decoder", "decode",
+            e);
+
+        final LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE
+            .get(String.valueOf(e));
+        throw DecodeException.error(message, e);
+      }
+
+      int size;
+      try
+      {
+        size = (int) reader.readInteger();
+      }
+      catch (final Exception e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PagedResultsControl.Decoder", "decode",
+            e);
+
+        final LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SIZE
+            .get(String.valueOf(e));
+        throw DecodeException.error(message, e);
+      }
+
+      ByteString cookie;
+      try
+      {
+        cookie = reader.readOctetString();
+      }
+      catch (final Exception e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PagedResultsControl.Decoder", "decode",
+            e);
+
+        final LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_COOKIE
+            .get(String.valueOf(e));
+        throw DecodeException.error(message, e);
+      }
+
+      try
+      {
+        reader.readEndSequence();
+      }
+      catch (final Exception e)
+      {
+        StaticUtils.DEBUG_LOG.throwing("PagedResultsControl.Decoder", "decode",
+            e);
+
+        final LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE
+            .get(String.valueOf(e));
+        throw DecodeException.error(message, e);
+      }
+
+      return new SimplePagedResultsControl(control.isCritical(), size, cookie);
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new simple paged results control with the provided criticality,
+   * size, and cookie.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param size
+   *          The requested page size when used in a request control from the
+   *          client, or an estimate of the result set size when used in a
+   *          response control from the server (may be 0, indicating that the
+   *          server does not know).
+   * @param cookie
+   *          An opaque cookie which is used by the server to track its position
+   *          in the set of search results. The cookie must be empty in the
+   *          initial search request sent by the client. For subsequent search
+   *          requests the client must include the cookie returned with the
+   *          previous search result, until the server returns an empty cookie
+   *          indicating that the final page of results has been returned.
+   * @return The new control.
+   * @throws NullPointerException
+   *           If {@code cookie} was {@code null}.
+   */
+  public static SimplePagedResultsControl newControl(final boolean isCritical,
+      final int size, final ByteString cookie) throws NullPointerException
+  {
+    Validator.ensureNotNull(cookie);
+    return new SimplePagedResultsControl(isCritical, size, cookie);
+  }
+
+
+
+  /**
+   * The control value size element, which is either the requested page size
+   * from the client, or the result set size estimate from the server.
+   */
+  private final int size;
+
+  /**
+   * The control value cookie element.
+   */
+  private final ByteString cookie;
+
+  private final boolean isCritical;
+
+
+
+  private SimplePagedResultsControl(final boolean isCritical, final int size,
+      final ByteString cookie)
+  {
+    this.isCritical = isCritical;
+    this.size = size;
+    this.cookie = cookie;
+  }
+
+
+
+  /**
+   * Returns the opaque cookie which is used by the server to track its position
+   * in the set of search results. The cookie must be empty in the initial
+   * search request sent by the client. For subsequent search requests the
+   * client must include the cookie returned with the previous search result,
+   * until the server returns an empty cookie indicating that the final page of
+   * results has been returned.
+   *
+   * @return The opaque cookie which is used by the server to track its position
+   *         in the set of search results.
+   */
+  public ByteString getCookie()
+  {
+    return cookie;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns the requested page size when used in a request control from the
+   * client, or an estimate of the result set size when used in a response
+   * control from the server (may be 0, indicating that the server does not
+   * know).
+   *
+   * @return The requested page size when used in a request control from the
+   *         client, or an estimate of the result set size when used in a
+   *         response control from the server.
+   */
+  public int getSize()
+  {
+    return size;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeInteger(size);
+      writer.writeOctetString(cookie);
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("SimplePagedResultsControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", size=");
+    builder.append(size);
+    builder.append(", cookie=");
+    builder.append(cookie);
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubentriesRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubentriesRequestControl.java
new file mode 100644
index 0000000..a9eae9e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubentriesRequestControl.java
@@ -0,0 +1,195 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_SUBENTRIES_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_SUBENTRIES_INVALID_CONTROL_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The sub-entries request control as defined in draft-ietf-ldup-subentry. This
+ * control may be included in a search request to indicate that sub-entries
+ * should be included in the search results.
+ * <p>
+ * In the absence of the sub-entries request control, sub-entries are not
+ * visible to search operations unless the target/base of the operation is a
+ * sub-entry. In the presence of the sub-entry request control, only sub-entries
+ * are visible.
+ *
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-ietf-ldup-subentry">draft-ietf-ldup-subentry
+ *      - LDAP Subentry Schema </a>
+ */
+public final class SubentriesRequestControl implements Control
+{
+  /**
+   * The OID for the sub-entries request control.
+   */
+  public static final String OID = "1.3.6.1.4.1.7628.5.101.1";
+
+  private static final SubentriesRequestControl CRITICAL_INSTANCE = new SubentriesRequestControl(
+      true);
+  private static final SubentriesRequestControl NONCRITICAL_INSTANCE = new SubentriesRequestControl(
+      false);
+
+  /**
+   * A decoder which can be used for decoding the sub-entries request control.
+   */
+  public static final ControlDecoder<SubentriesRequestControl> DECODER =
+    new ControlDecoder<SubentriesRequestControl>()
+  {
+
+    public SubentriesRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof SubentriesRequestControl)
+      {
+        return (SubentriesRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_SUBENTRIES_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_SUBENTRIES_INVALID_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new sub-entries request control having the provided criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static SubentriesRequestControl newControl(final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private final boolean isCritical;
+
+
+
+  private SubentriesRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("SubentriesRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubtreeDeleteRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubtreeDeleteRequestControl.java
new file mode 100644
index 0000000..f37646c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/SubtreeDeleteRequestControl.java
@@ -0,0 +1,192 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_SUBTREE_DELETE_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.ERR_SUBTREE_DELETE_INVALID_CONTROL_VALUE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The tree delete request control as defined in draft-armijo-ldap-treedelete.
+ * This control allows a client to delete an entire subtree of a container entry
+ * in a single delete operation.
+ *
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-armijo-ldap-treedelete">draft-armijo-ldap-treedelete
+ *      - Tree Delete Control </a>
+ */
+public final class SubtreeDeleteRequestControl implements Control
+{
+  /**
+   * The OID for the subtree delete request control.
+   */
+  public static final String OID = "1.2.840.113556.1.4.805";
+
+  private static final SubtreeDeleteRequestControl CRITICAL_INSTANCE =
+    new SubtreeDeleteRequestControl(true);
+
+  private static final SubtreeDeleteRequestControl NONCRITICAL_INSTANCE =
+    new SubtreeDeleteRequestControl(false);
+
+  /**
+   * A decoder which can be used for decoding the sub-tree delete request
+   * control.
+   */
+  public static final ControlDecoder<SubtreeDeleteRequestControl> DECODER =
+    new ControlDecoder<SubtreeDeleteRequestControl>()
+  {
+
+    public SubtreeDeleteRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof SubtreeDeleteRequestControl)
+      {
+        return (SubtreeDeleteRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_SUBTREE_DELETE_CONTROL_BAD_OID
+            .get(control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (control.hasValue())
+      {
+        final LocalizableMessage message = ERR_SUBTREE_DELETE_INVALID_CONTROL_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new tree delete request control having the provided criticality.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @return The new control.
+   */
+  public static SubtreeDeleteRequestControl newControl(final boolean isCritical)
+  {
+    return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
+  }
+
+
+
+  private final boolean isCritical;
+
+
+
+  private SubtreeDeleteRequestControl(final boolean isCritical)
+  {
+    this.isCritical = isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("SubtreeDeleteRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewRequestControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewRequestControl.java
new file mode 100644
index 0000000..6481220
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewRequestControl.java
@@ -0,0 +1,525 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_VLVREQ_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE;
+import static com.sun.opends.sdk.messages.Messages.INFO_VLVREQ_CONTROL_NO_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.byteToHex;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The virtual list view request control as defined in
+ * draft-ietf-ldapext-ldapv3-vlv. This control allows a client to specify that
+ * the server return, for a given search request with associated sort keys, a
+ * contiguous subset of the search result set. This subset is specified in terms
+ * of offsets into the ordered list, or in terms of a greater than or equal
+ * assertion value.
+ * <p>
+ * This control must be used in conjunction with the server-side sort request
+ * control in order to ensure that results are returned in a consistent order.
+ * <p>
+ * This control is similar to the simple paged results request control, except
+ * that it allows the client to move backwards and forwards in the result set.
+ *
+ * @see VirtualListViewResponseControl
+ * @see ServerSideSortRequestControl
+ * @see <a href="http://tools.ietf.org/html/draft-ietf-ldapext-ldapv3-vlv">
+ *         draft-ietf-ldapext-ldapv3-vlv - LDAP Extensions for Scrolling View
+ *         Browsing of Search Results </a>
+ */
+public final class VirtualListViewRequestControl implements Control
+{
+  /**
+   * The OID for the virtual list view request control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.9";
+
+  /**
+   * A decoder which can be used for decoding the virtual list view request
+   * control.
+   */
+  public static final ControlDecoder<VirtualListViewRequestControl> DECODER =
+    new ControlDecoder<VirtualListViewRequestControl>()
+  {
+
+    public VirtualListViewRequestControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof VirtualListViewRequestControl)
+      {
+        return (VirtualListViewRequestControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_VLVREQ_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The request control must always have a value.
+        final LocalizableMessage message = INFO_VLVREQ_CONTROL_NO_VALUE.get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        reader.readStartSequence();
+
+        final int beforeCount = (int) reader.readInteger();
+        final int afterCount = (int) reader.readInteger();
+
+        int offset = -1;
+        int contentCount = -1;
+        ByteString assertionValue = null;
+        final byte targetType = reader.peekType();
+        switch (targetType)
+        {
+        case TYPE_TARGET_BYOFFSET:
+          reader.readStartSequence();
+          offset = (int) reader.readInteger();
+          contentCount = (int) reader.readInteger();
+          reader.readEndSequence();
+          break;
+        case TYPE_TARGET_GREATERTHANOREQUAL:
+          assertionValue = reader.readOctetString();
+          break;
+        default:
+          final LocalizableMessage message = INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE
+              .get(byteToHex(targetType));
+          throw DecodeException.error(message);
+        }
+
+        ByteString contextID = null;
+        if (reader.hasNextElement())
+        {
+          contextID = reader.readOctetString();
+        }
+
+        return new VirtualListViewRequestControl(control.isCritical(),
+            beforeCount, afterCount, contentCount, offset, assertionValue,
+            contextID);
+      }
+      catch (final IOException e)
+      {
+        final LocalizableMessage message = INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+  /**
+   * The BER type to use when encoding the byOffset target element.
+   */
+  private static final byte TYPE_TARGET_BYOFFSET = (byte) 0xA0;
+
+  /**
+   * The BER type to use when encoding the greaterThanOrEqual target element.
+   */
+  private static final byte TYPE_TARGET_GREATERTHANOREQUAL = (byte) 0x81;
+
+
+
+  /**
+   * Creates a new virtual list view request control that will identify the
+   * target entry by an assertion value. The assertion value is encoded
+   * according to the ORDERING matching rule for the attribute description in
+   * the sort control. The assertion value is used to determine the target entry
+   * by comparison with the values of the attribute specified as the primary
+   * sort key. The first list entry who's value is no less than (less than or
+   * equal to when the sort order is reversed) the supplied value is the target
+   * entry.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param assertionValue
+   *          The assertion value that will be used to locate the target entry.
+   * @param beforeCount
+   *          The number of entries before the target entry to be included in
+   *          the search results.
+   * @param afterCount
+   *          The number of entries after the target entry to be included in the
+   *          search results.
+   * @param contextID
+   *          The context ID provided by the server in the last virtual list
+   *          view response for the same set of criteria, or {@code null} if
+   *          there was no previous virtual list view response or the server did
+   *          not include a context ID in the last response.
+   * @return The new control.
+   * @throws IllegalArgumentException
+   *           If {@code beforeCount} or {@code afterCount} were less than
+   *           {@code 0}.
+   * @throws NullPointerException
+   *           If {@code assertionValue} was {@code null}.
+   */
+  public static VirtualListViewRequestControl newAssertionControl(
+      final boolean isCritical, final ByteString assertionValue,
+      final int beforeCount, final int afterCount, final ByteString contextID)
+      throws IllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(assertionValue);
+    Validator.ensureTrue(beforeCount >= 0, "beforeCount is less than 0");
+    Validator.ensureTrue(afterCount >= 0, "afterCount is less than 0");
+
+    return new VirtualListViewRequestControl(isCritical, beforeCount,
+        afterCount, -1, -1, assertionValue, contextID);
+  }
+
+
+
+  /**
+   * Creates a new virtual list view request control that will identify the
+   * target entry by a positional offset within the complete result set.
+   *
+   * @param isCritical
+   *          {@code true} if it is unacceptable to perform the operation
+   *          without applying the semantics of this control, or {@code false}
+   *          if it can be ignored.
+   * @param offset
+   *          The positional offset of the target entry in the result set, where
+   *          {@code 1} is the first entry.
+   * @param contentCount
+   *          The content count returned by the server in the last virtual list
+   *          view response, or {@code 0} if this is the first virtual list view
+   *          request.
+   * @param beforeCount
+   *          The number of entries before the target entry to be included in
+   *          the search results.
+   * @param afterCount
+   *          The number of entries after the target entry to be included in the
+   *          search results.
+   * @param contextID
+   *          The context ID provided by the server in the last virtual list
+   *          view response for the same set of criteria, or {@code null} if
+   *          there was no previous virtual list view response or the server did
+   *          not include a context ID in the last response.
+   * @return The new control.
+   * @throws IllegalArgumentException
+   *           If {@code beforeCount}, {@code afterCount}, or {@code
+   *           contentCount} were less than {@code 0}, or if {@code offset} was
+   *           less than {@code 1}.
+   */
+  public static VirtualListViewRequestControl newOffsetControl(
+      final boolean isCritical, final int offset, final int contentCount,
+      final int beforeCount, final int afterCount, final ByteString contextID)
+      throws IllegalArgumentException
+  {
+    Validator.ensureTrue(beforeCount >= 0, "beforeCount is less than 0");
+    Validator.ensureTrue(afterCount >= 0, "afterCount is less than 0");
+    Validator.ensureTrue(offset > 0, "beforeCount is less than 1");
+    Validator.ensureTrue(contentCount >= 0, "afterCount is less than 0");
+
+    return new VirtualListViewRequestControl(isCritical, beforeCount,
+        afterCount, offset, contentCount, null, contextID);
+  }
+
+
+
+  private final int beforeCount;
+
+  private final int afterCount;
+
+  private final ByteString contextID;
+
+  private final boolean isCritical;
+
+  private final int contentCount;
+
+  private final int offset;
+
+  private final ByteString assertionValue;
+
+
+
+  private VirtualListViewRequestControl(final boolean isCritical,
+      final int beforeCount, final int afterCount, final int contentCount,
+      final int offset, final ByteString assertionValue,
+      final ByteString contextID)
+  {
+    this.isCritical = isCritical;
+    this.beforeCount = beforeCount;
+    this.afterCount = afterCount;
+    this.contentCount = contentCount;
+    this.offset = offset;
+    this.assertionValue = assertionValue;
+    this.contextID = contextID;
+  }
+
+
+
+  /**
+   * Returns the number of entries after the target entry to be included in the
+   * search results.
+   *
+   * @return The number of entries after the target entry to be included in the
+   *         search results.
+   */
+  public int getAfterCount()
+  {
+    return afterCount;
+  }
+
+
+
+  /**
+   * Returns the assertion value that will be used to locate the target entry,
+   * if applicable.
+   *
+   * @return The assertion value that will be used to locate the target entry,
+   *         or {@code null} if this control is using a target offset.
+   */
+  public ByteString getAssertionValue()
+  {
+    return assertionValue;
+  }
+
+
+
+  /**
+   * Returns the assertion value that will be used to locate the target entry,
+   * if applicable, decoded as a UTF-8 string.
+   *
+   * @return The assertion value that will be used to locate the target entry
+   *         decoded as a UTF-8 string, or {@code null} if this control is using
+   *         a target offset.
+   */
+  public String getAssertionValueAsString()
+  {
+    return assertionValue != null ? assertionValue.toString() : null;
+  }
+
+
+
+  /**
+   * Returns the number of entries before the target entry to be included in the
+   * search results.
+   *
+   * @return The number of entries before the target entry to be included in the
+   *         search results.
+   */
+  public int getBeforeCount()
+  {
+    return beforeCount;
+  }
+
+
+
+  /**
+   * Returns the content count returned by the server in the last virtual list
+   * view response, if applicable.
+   *
+   * @return The content count returned by the server in the last virtual list
+   *         view response, which may be {@code 0} if this is the first virtual
+   *         list view request, or {@code -1} if this control is using a target
+   *         assertion.
+   */
+  public int getContentCount()
+  {
+    return contentCount;
+  }
+
+
+
+  /**
+   * Returns the context ID provided by the server in the last virtual list view
+   * response for the same set of criteria, or {@code null} if there was no
+   * previous virtual list view response or the server did not include a context
+   * ID in the last response.
+   *
+   * @return The context ID provided by the server in the last virtual list view
+   *         response, or {@code null} if unavailable.
+   */
+  public ByteString getContextID()
+  {
+    return contextID;
+  }
+
+
+
+  /**
+   * Returns the positional offset of the target entry in the result set, if
+   * applicable, where {@code 1} is the first entry.
+   *
+   * @return The positional offset of the target entry in the result set, or
+   *         {@code -1} if this control is using a target assertion.
+   */
+  public int getOffset()
+  {
+    return offset;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeInteger(beforeCount);
+      writer.writeInteger(afterCount);
+      if (hasTargetOffset())
+      {
+        writer.writeStartSequence(TYPE_TARGET_BYOFFSET);
+        writer.writeInteger(offset);
+        writer.writeInteger(contentCount);
+        writer.writeEndSequence();
+      }
+      else
+      {
+        writer.writeOctetString(TYPE_TARGET_GREATERTHANOREQUAL, assertionValue);
+      }
+      if (contextID != null)
+      {
+        writer.writeOctetString(contextID);
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * Returns {@code true} if this control is using a target offset, or {@code
+   * false} if this control is using a target assertion.
+   *
+   * @return {@code true} if this control is using a target offset, or {@code
+   *         false} if this control is using a target assertion.
+   */
+  public boolean hasTargetOffset()
+  {
+    return assertionValue != null ? false : true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("VirtualListViewRequestControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", beforeCount=");
+    builder.append(beforeCount);
+    builder.append(", afterCount=");
+    builder.append(afterCount);
+    if (hasTargetOffset())
+    {
+      builder.append(", offset=");
+      builder.append(offset);
+      builder.append(", contentCount=");
+      builder.append(contentCount);
+    }
+    else
+    {
+      builder.append(", greaterThanOrEqual=");
+      builder.append(assertionValue);
+    }
+    if (contextID != null)
+    {
+      builder.append(", contextID=");
+      builder.append(contextID);
+    }
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewResponseControl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewResponseControl.java
new file mode 100644
index 0000000..6ede03a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/VirtualListViewResponseControl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.controls;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_VLVRES_CONTROL_BAD_OID;
+import static com.sun.opends.sdk.messages.Messages.INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE;
+import static com.sun.opends.sdk.messages.Messages.INFO_VLVRES_CONTROL_NO_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * The virtual list view response control as defined in
+ * draft-ietf-ldapext-ldapv3-vlv. This control is included with a search result
+ * in response to a virtual list view request included with a search request.
+ * <p>
+ * If the result code included with this control indicates that the virtual list
+ * view request succeeded then the content count and target position give
+ * sufficient information for the client to update a list box slider position to
+ * match the newly retrieved entries and identify the target entry.
+ * <p>
+ * The content count and context ID should be used in a subsequent virtual list
+ * view requests.
+ *
+ * @see VirtualListViewRequestControl
+ * @see <a href="http://tools.ietf.org/html/draft-ietf-ldapext-ldapv3-vlv">
+ *         draft-ietf-ldapext-ldapv3-vlv - LDAP Extensions for Scrolling View
+ *         Browsing of Search Results </a>
+ */
+public final class VirtualListViewResponseControl implements Control
+{
+  /**
+   * The OID for the virtual list view request control.
+   */
+  public static final String OID = "2.16.840.1.113730.3.4.10";
+
+  /**
+   * A decoder which can be used for decoding the virtual list view response
+   * control.
+   */
+  public static final ControlDecoder<VirtualListViewResponseControl> DECODER =
+    new ControlDecoder<VirtualListViewResponseControl>()
+  {
+
+    public VirtualListViewResponseControl decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      Validator.ensureNotNull(control);
+
+      if (control instanceof VirtualListViewResponseControl)
+      {
+        return (VirtualListViewResponseControl) control;
+      }
+
+      if (!control.getOID().equals(OID))
+      {
+        final LocalizableMessage message = ERR_VLVRES_CONTROL_BAD_OID.get(
+            control.getOID(), OID);
+        throw DecodeException.error(message);
+      }
+
+      if (!control.hasValue())
+      {
+        // The response control must always have a value.
+        final LocalizableMessage message = INFO_VLVRES_CONTROL_NO_VALUE.get();
+        throw DecodeException.error(message);
+      }
+
+      final ASN1Reader reader = ASN1.getReader(control.getValue());
+      try
+      {
+        reader.readStartSequence();
+
+        final int targetPosition = (int) reader.readInteger();
+        final int contentCount = (int) reader.readInteger();
+        final ResultCode result = ResultCode.valueOf(reader.readEnumerated());
+        ByteString contextID = null;
+        if (reader.hasNextElement())
+        {
+          contextID = reader.readOctetString();
+        }
+
+        return new VirtualListViewResponseControl(control.isCritical(),
+            targetPosition, contentCount, result, contextID);
+      }
+      catch (final IOException e)
+      {
+        final LocalizableMessage message = INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+    }
+
+
+
+    public String getOID()
+    {
+      return OID;
+    }
+  };
+
+
+
+  /**
+   * Creates a new virtual list view response control.
+   *
+   * @param targetPosition
+   *          The position of the target entry in the result set.
+   * @param contentCount
+   *          An estimate of the total number of entries in the result set.
+   * @param result
+   *          The result code indicating the outcome of the virtual list view
+   *          request.
+   * @param contextID
+   *          A server-defined octet string. If present, the contextID should be
+   *          sent back to the server by the client in a subsequent virtual list
+   *          request.
+   * @return The new control.
+   * @throws IllegalArgumentException
+   *           If {@code targetPosition} or {@code contentCount} were less than
+   *           {@code 0}.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static VirtualListViewResponseControl newControl(
+      final int targetPosition, final int contentCount,
+      final ResultCode result, final ByteString contextID)
+      throws IllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(result);
+    Validator.ensureTrue(targetPosition >= 0, "targetPosition is less than 0");
+    Validator.ensureTrue(contentCount >= 0, "contentCount is less than 0");
+
+    return new VirtualListViewResponseControl(false, targetPosition,
+        contentCount, result, contextID);
+  }
+
+
+
+  private final int targetPosition;
+
+  private final int contentCount;
+
+  private final ResultCode result;
+
+  private final ByteString contextID;
+
+  private final boolean isCritical;
+
+
+
+  private VirtualListViewResponseControl(final boolean isCritical,
+      final int targetPosition, final int contentCount,
+      final ResultCode result, final ByteString contextID)
+  {
+    this.isCritical = isCritical;
+    this.targetPosition = targetPosition;
+    this.contentCount = contentCount;
+    this.result = result;
+    this.contextID = contextID;
+  }
+
+
+
+  /**
+   * Returns the estimated total number of entries in the result set.
+   *
+   * @return The estimated total number of entries in the result set.
+   */
+  public int getContentCount()
+  {
+    return contentCount;
+  }
+
+
+
+  /**
+   * Returns a server-defined octet string which, if present, should be sent
+   * back to the server by the client in a subsequent virtual list request.
+   *
+   * @return A server-defined octet string which, if present, should be sent
+   *         back to the server by the client in a subsequent virtual list
+   *         request, or {@code null} if there is no context ID.
+   */
+  public ByteString getContextID()
+  {
+    return contextID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * Returns result code indicating the outcome of the virtual list view
+   * request.
+   *
+   * @return The result code indicating the outcome of the virtual list view
+   *         request.
+   */
+  public ResultCode getResult()
+  {
+    return result;
+  }
+
+
+
+  /**
+   * Returns the position of the target entry in the result set.
+   *
+   * @return The position of the target entry in the result set.
+   */
+  public int getTargetPosition()
+  {
+    return targetPosition;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeInteger(targetPosition);
+      writer.writeInteger(contentCount);
+      writer.writeEnumerated(result.intValue());
+      if (contextID != null)
+      {
+        writer.writeOctetString(contextID);
+      }
+      writer.writeEndSequence();
+      return buffer.toByteString();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isCritical()
+  {
+    return isCritical;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("VirtualListViewResponseControl(oid=");
+    builder.append(getOID());
+    builder.append(", criticality=");
+    builder.append(isCritical());
+    builder.append(", targetPosition=");
+    builder.append(targetPosition);
+    builder.append(", contentCount=");
+    builder.append(contentCount);
+    builder.append(", result=");
+    builder.append(result);
+    if (contextID != null)
+    {
+      builder.append(", contextID=");
+      builder.append(contextID);
+    }
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/package-info.java
new file mode 100755
index 0000000..da216de
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/controls/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes and interfaces for common LDAP controls.
+ */
+package org.opends.sdk.controls;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFReader.java
new file mode 100644
index 0000000..418b08a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFReader.java
@@ -0,0 +1,891 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.Base64;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Common LDIF reader functionality.
+ */
+abstract class AbstractLDIFReader extends AbstractLDIFStream
+{
+  static final class KeyValuePair
+  {
+    String key;
+
+    String value;
+  }
+
+
+
+  /**
+   * LDIF reader implementation interface.
+   */
+  interface LDIFReaderImpl
+  {
+
+    /**
+     * Closes any resources associated with this LDIF reader implementation.
+     *
+     * @throws IOException
+     *           If an error occurs while closing.
+     */
+    void close() throws IOException;
+
+
+
+    /**
+     * Reads the next line of LDIF from the underlying LDIF source.
+     * Implementations must remove trailing line delimiters.
+     *
+     * @return The next line of LDIF, or {@code null} if the end of the LDIF
+     *         source has been reached.
+     * @throws IOException
+     *           If an error occurs while reading from the LDIF source.
+     */
+    String readLine() throws IOException;
+  }
+
+
+
+  static final class LDIFRecord
+  {
+    final Iterator<String> iterator;
+
+    final LinkedList<String> ldifLines;
+
+    final long lineNumber;
+
+
+
+    private LDIFRecord(final long lineNumber, final LinkedList<String> ldifLines)
+    {
+      this.lineNumber = lineNumber;
+      this.ldifLines = ldifLines;
+      this.iterator = ldifLines.iterator();
+    }
+  }
+
+
+
+  /**
+   * LDIF output stream writer implementation.
+   */
+  private static final class LDIFReaderInputStreamImpl implements
+      LDIFReaderImpl
+  {
+
+    private BufferedReader reader;
+
+
+
+    /**
+     * Creates a new LDIF input stream reader implementation.
+     *
+     * @param in
+     *          The input stream to use.
+     */
+    LDIFReaderInputStreamImpl(final InputStream in)
+    {
+      this.reader = new BufferedReader(new InputStreamReader(in));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException
+    {
+      if (reader != null)
+      {
+        reader.close();
+        reader = null;
+      }
+    }
+
+
+
+    /**
+     *{@inheritDoc}
+     */
+    public String readLine() throws IOException
+    {
+      String line = null;
+      if (reader != null)
+      {
+        line = reader.readLine();
+        if (line == null)
+        {
+          // Automatically close.
+          close();
+        }
+      }
+      return line;
+    }
+  }
+
+
+
+  /**
+   * LDIF output stream writer implementation.
+   */
+  private static final class LDIFReaderListImpl implements LDIFReaderImpl
+  {
+
+    private final Iterator<String> iterator;
+
+
+
+    /**
+     * Creates a new LDIF list reader.
+     *
+     * @param ldifLines
+     *          The string list.
+     */
+    LDIFReaderListImpl(final List<String> ldifLines)
+    {
+      this.iterator = ldifLines.iterator();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException
+    {
+      // Nothing to do.
+    }
+
+
+
+    /**
+     *{@inheritDoc}
+     */
+    public String readLine() throws IOException
+    {
+      if (iterator.hasNext())
+      {
+        return iterator.next();
+      }
+      else
+      {
+        return null;
+      }
+    }
+  }
+
+
+
+  boolean validateSchema = true;
+
+  private final LDIFReaderImpl impl;
+
+  private long lineNumber = 0;
+
+
+
+  /**
+   * Creates a new LDIF entry reader whose source is the provided input stream.
+   *
+   * @param in
+   *          The input stream to use.
+   */
+  AbstractLDIFReader(final InputStream in)
+  {
+    Validator.ensureNotNull(in);
+    this.impl = new LDIFReaderInputStreamImpl(in);
+  }
+
+
+
+  /**
+   * Creates a new LDIF entry reader which will read lines of LDIF from the
+   * provided list.
+   *
+   * @param ldifLines
+   *          The list from which lines of LDIF should be read.
+   */
+  AbstractLDIFReader(final List<String> ldifLines)
+  {
+    Validator.ensureNotNull(ldifLines);
+    this.impl = new LDIFReaderListImpl(ldifLines);
+  }
+
+
+
+  final void close0() throws IOException
+  {
+    impl.close();
+  }
+
+
+
+  final int parseColonPosition(final LDIFRecord record, final String ldifLine)
+      throws DecodeException
+  {
+    final int colonPos = ldifLine.indexOf(":");
+    if (colonPos <= 0)
+    {
+      final LocalizableMessage message = ERR_LDIF_NO_ATTR_NAME.get(
+          record.lineNumber, ldifLine);
+      throw DecodeException.error(message);
+    }
+    return colonPos;
+  }
+
+
+
+  final ByteString parseSingleValue(final LDIFRecord record,
+      final String ldifLine, final DN entryDN, final int colonPos,
+      final String attrName) throws DecodeException
+  {
+
+    // Look at the character immediately after the colon. If there is
+    // none, then assume an attribute with an empty value. If it is
+    // another colon, then the value must be base64-encoded. If it is a
+    // less-than sign, then assume that it is a URL. Otherwise, it is a
+    // regular value.
+    final int length = ldifLine.length();
+    ByteString value;
+    if (colonPos == length - 1)
+    {
+      value = ByteString.empty();
+    }
+    else
+    {
+      final char c = ldifLine.charAt(colonPos + 1);
+      if (c == ':')
+      {
+        // The value is base64-encoded. Find the first non-blank
+        // character, take the rest of the line, and base64-decode it.
+        int pos = colonPos + 2;
+        while (pos < length && ldifLine.charAt(pos) == ' ')
+        {
+          pos++;
+        }
+
+        try
+        {
+          value = Base64.decode(ldifLine.substring(pos));
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          // The value did not have a valid base64-encoding.
+          final LocalizableMessage message = ERR_LDIF_COULD_NOT_BASE64_DECODE_ATTR
+              .get(entryDN.toString(), record.lineNumber, ldifLine, e
+                  .getMessageObject());
+          throw DecodeException.error(message);
+        }
+      }
+      else if (c == '<')
+      {
+        // Find the first non-blank character, decode the rest of the
+        // line as a URL, and read its contents.
+        int pos = colonPos + 2;
+        while (pos < length && ldifLine.charAt(pos) == ' ')
+        {
+          pos++;
+        }
+
+        URL contentURL;
+        try
+        {
+          contentURL = new URL(ldifLine.substring(pos));
+        }
+        catch (final Exception e)
+        {
+          // The URL was malformed or had an invalid protocol.
+          final LocalizableMessage message = ERR_LDIF_INVALID_URL.get(entryDN
+              .toString(), record.lineNumber, attrName, String.valueOf(e));
+          throw DecodeException.error(message);
+        }
+
+        InputStream inputStream = null;
+        ByteStringBuilder builder = null;
+        try
+        {
+          builder = new ByteStringBuilder();
+          inputStream = contentURL.openConnection().getInputStream();
+
+          int bytesRead;
+          final byte[] buffer = new byte[4096];
+          while ((bytesRead = inputStream.read(buffer)) > 0)
+          {
+            builder.append(buffer, 0, bytesRead);
+          }
+
+          value = builder.toByteString();
+        }
+        catch (final Exception e)
+        {
+          // We were unable to read the contents of that URL for some
+          // reason.
+          final LocalizableMessage message = ERR_LDIF_URL_IO_ERROR.get(entryDN
+              .toString(), record.lineNumber, attrName, String
+              .valueOf(contentURL), String.valueOf(e));
+          throw DecodeException.error(message);
+        }
+        finally
+        {
+          if (inputStream != null)
+          {
+            try
+            {
+              inputStream.close();
+            }
+            catch (final Exception e)
+            {
+              // Ignore.
+            }
+          }
+        }
+      }
+      else
+      {
+        // The rest of the line should be the value. Skip over any
+        // spaces and take the rest of the line as the value.
+        int pos = colonPos + 1;
+        while (pos < length && ldifLine.charAt(pos) == ' ')
+        {
+          pos++;
+        }
+
+        value = ByteString.valueOf(ldifLine.substring(pos));
+      }
+    }
+    return value;
+  }
+
+
+
+  final LDIFRecord readLDIFRecord() throws IOException
+  {
+    // Read the entry lines into a buffer.
+    final StringBuilder lastLineBuilder = new StringBuilder();
+    final LinkedList<String> ldifLines = new LinkedList<String>();
+    long recordLineNumber = 0;
+
+    final int stateStart = 0;
+    final int stateStartCommentLine = 1;
+    final int stateGotLDIFLine = 2;
+    final int stateGotCommentLine = 3;
+    final int appendingLDIFLine = 4;
+
+    int state = stateStart;
+
+    while (true)
+    {
+      final String line = readLine();
+
+      switch (state)
+      {
+      case stateStart:
+        if (line == null)
+        {
+          // We have reached the end of the LDIF source.
+          return null;
+        }
+        else if (line.length() == 0)
+        {
+          // Skip leading blank lines.
+        }
+        else if (line.charAt(0) == '#')
+        {
+          // This is a comment at the start of the LDIF record.
+          state = stateStartCommentLine;
+        }
+        else if (isContinuationLine(line))
+        {
+          // Fatal: got a continuation line at the start of the record.
+          final LocalizableMessage message = ERR_LDIF_INVALID_LEADING_SPACE
+              .get(lineNumber, line);
+          throw DecodeException.fatalError(message);
+        }
+        else
+        {
+          // Got the first line of LDIF.
+          ldifLines.add(line);
+          recordLineNumber = lineNumber;
+          state = stateGotLDIFLine;
+        }
+        break;
+      case stateStartCommentLine:
+        if (line == null)
+        {
+          // We have reached the end of the LDIF source.
+          return null;
+        }
+        else if (line.length() == 0)
+        {
+          // Skip leading blank lines and comments.
+          state = stateStart;
+        }
+        else if (line.charAt(0) == '#')
+        {
+          // This is another comment at the start of the LDIF record.
+        }
+        else if (isContinuationLine(line))
+        {
+          // Skip comment continuation lines.
+        }
+        else
+        {
+          // Got the first line of LDIF.
+          ldifLines.add(line);
+          recordLineNumber = lineNumber;
+          state = stateGotLDIFLine;
+        }
+        break;
+      case stateGotLDIFLine:
+        if (line == null)
+        {
+          // We have reached the end of the LDIF source.
+          return new LDIFRecord(recordLineNumber, ldifLines);
+        }
+        else if (line.length() == 0)
+        {
+          // We have reached the end of the LDIF record.
+          return new LDIFRecord(recordLineNumber, ldifLines);
+        }
+        else if (line.charAt(0) == '#')
+        {
+          // This is a comment.
+          state = stateGotCommentLine;
+        }
+        else if (isContinuationLine(line))
+        {
+          // Got a continuation line for the previous line.
+          lastLineBuilder.setLength(0);
+          lastLineBuilder.append(ldifLines.removeLast());
+          lastLineBuilder.append(line.substring(1));
+          state = appendingLDIFLine;
+        }
+        else
+        {
+          // Got the next line of LDIF.
+          ldifLines.add(line);
+          state = stateGotLDIFLine;
+        }
+        break;
+      case stateGotCommentLine:
+        if (line == null)
+        {
+          // We have reached the end of the LDIF source.
+          return new LDIFRecord(recordLineNumber, ldifLines);
+        }
+        else if (line.length() == 0)
+        {
+          // We have reached the end of the LDIF record.
+          return new LDIFRecord(recordLineNumber, ldifLines);
+        }
+        else if (line.charAt(0) == '#')
+        {
+          // This is another comment.
+          state = stateGotCommentLine;
+        }
+        else if (isContinuationLine(line))
+        {
+          // Skip comment continuation lines.
+        }
+        else
+        {
+          // Got the next line of LDIF.
+          ldifLines.add(line);
+          state = stateGotLDIFLine;
+        }
+        break;
+      case appendingLDIFLine:
+        if (line == null)
+        {
+          // We have reached the end of the LDIF source.
+          ldifLines.add(lastLineBuilder.toString());
+          return new LDIFRecord(recordLineNumber, ldifLines);
+        }
+        else if (line.length() == 0)
+        {
+          // We have reached the end of the LDIF record.
+          ldifLines.add(lastLineBuilder.toString());
+          return new LDIFRecord(recordLineNumber, ldifLines);
+        }
+        else if (line.charAt(0) == '#')
+        {
+          // This is a comment.
+          ldifLines.add(lastLineBuilder.toString());
+          state = stateGotCommentLine;
+        }
+        else if (isContinuationLine(line))
+        {
+          // Got another continuation line for the previous line.
+          lastLineBuilder.append(line.substring(1));
+        }
+        else
+        {
+          // Got the next line of LDIF.
+          ldifLines.add(lastLineBuilder.toString());
+          ldifLines.add(line);
+          state = stateGotLDIFLine;
+        }
+        break;
+      }
+    }
+  }
+
+
+
+  final void readLDIFRecordAttributeValue(final LDIFRecord record,
+      final String ldifLine, final Entry entry) throws DecodeException
+  {
+    // Parse the attribute description.
+    final int colonPos = parseColonPosition(record, ldifLine);
+    final String attrDescr = ldifLine.substring(0, colonPos);
+
+    AttributeDescription attributeDescription;
+    try
+    {
+      attributeDescription = AttributeDescription.valueOf(attrDescr, schema);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      throw DecodeException.error(e.getMessageObject());
+    }
+
+    // Now parse the attribute value.
+    final ByteString value = parseSingleValue(record, ldifLine,
+        entry.getName(), colonPos, attrDescr);
+
+    // Skip the attribute if requested before performing any schema
+    // checking: the attribute may have been excluded because it is
+    // known to violate the schema.
+    if (isAttributeExcluded(attributeDescription))
+    {
+      return;
+    }
+
+    // Ensure that the binary option is present if required.
+    if (!attributeDescription.getAttributeType().getSyntax()
+        .isBEREncodingRequired())
+    {
+      if (validateSchema && attributeDescription.containsOption("binary"))
+      {
+        final LocalizableMessage message = ERR_LDIF_INVALID_ATTR_OPTION.get(
+            entry.getName().toString(), record.lineNumber, attrDescr);
+        throw DecodeException.error(message);
+      }
+    }
+    else
+    {
+      attributeDescription = AttributeDescription.create(attributeDescription,
+          "binary");
+    }
+
+    Attribute attribute = entry.getAttribute(attributeDescription);
+    if (attribute == null)
+    {
+      if (validateSchema)
+      {
+        final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
+        if (!attributeDescription.getAttributeType().getSyntax()
+            .valueIsAcceptable(value, invalidReason))
+        {
+          final LocalizableMessage message = WARN_LDIF_VALUE_VIOLATES_SYNTAX
+              .get(entry.getName().toString(), record.lineNumber, value
+                  .toString(), attrDescr, invalidReason);
+          throw DecodeException.error(message);
+        }
+      }
+
+      attribute = new LinkedAttribute(attributeDescription, value);
+      entry.addAttribute(attribute);
+    }
+    else
+    {
+      if (validateSchema)
+      {
+        final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
+        if (!attributeDescription.getAttributeType().getSyntax()
+            .valueIsAcceptable(value, invalidReason))
+        {
+          final LocalizableMessage message = WARN_LDIF_VALUE_VIOLATES_SYNTAX
+              .get(entry.getName().toString(), record.lineNumber, value
+                  .toString(), attrDescr, invalidReason);
+          throw DecodeException.error(message);
+        }
+
+        if (!attribute.add(value))
+        {
+          final LocalizableMessage message = WARN_LDIF_DUPLICATE_ATTR.get(entry
+              .getName().toString(), record.lineNumber, attrDescr, value
+              .toString());
+          throw DecodeException.error(message);
+        }
+
+        if (attributeDescription.getAttributeType().isSingleValue())
+        {
+          final LocalizableMessage message = ERR_LDIF_MULTIPLE_VALUES_FOR_SINGLE_VALUED_ATTR
+              .get(entry.getName().toString(), record.lineNumber, attrDescr);
+          throw DecodeException.error(message);
+        }
+      }
+      else
+      {
+        attribute.add(value);
+      }
+    }
+  }
+
+
+
+  final DN readLDIFRecordDN(final LDIFRecord record) throws DecodeException
+  {
+    String ldifLine = record.iterator.next();
+    int colonPos = ldifLine.indexOf(":");
+    if (colonPos <= 0)
+    {
+      final LocalizableMessage message = ERR_LDIF_NO_ATTR_NAME.get(
+          record.lineNumber, ldifLine.toString());
+      throw DecodeException.error(message);
+    }
+
+    String attrName = toLowerCase(ldifLine.substring(0, colonPos));
+    if (attrName.equals("version"))
+    {
+      // This is the version line, try the next line if there is one.
+      if (!record.iterator.hasNext())
+      {
+        return null;
+      }
+
+      ldifLine = record.iterator.next();
+      colonPos = ldifLine.indexOf(":");
+      if (colonPos <= 0)
+      {
+        final LocalizableMessage message = ERR_LDIF_NO_ATTR_NAME.get(
+            record.lineNumber, ldifLine.toString());
+        throw DecodeException.error(message);
+      }
+
+      attrName = toLowerCase(ldifLine.substring(0, colonPos));
+    }
+
+    if (!attrName.equals("dn"))
+    {
+      final LocalizableMessage message = ERR_LDIF_NO_DN.get(record.lineNumber,
+          ldifLine.toString());
+      throw DecodeException.error(message);
+    }
+
+    // Look at the character immediately after the colon. If there is
+    // none, then assume the null DN. If it is another colon, then the
+    // DN must be base64-encoded. Otherwise, it may be one or more
+    // spaces.
+    final int length = ldifLine.length();
+    if (colonPos == length - 1)
+    {
+      return DN.rootDN();
+    }
+
+    String dnString = null;
+
+    if (ldifLine.charAt(colonPos + 1) == ':')
+    {
+      // The DN is base64-encoded. Find the first non-blank character
+      // and take the rest of the line and base64-decode it.
+      int pos = colonPos + 2;
+      while (pos < length && ldifLine.charAt(pos) == ' ')
+      {
+        pos++;
+      }
+
+      final String base64DN = ldifLine.substring(pos);
+      try
+      {
+        dnString = Base64.decode(base64DN).toString();
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        // The value did not have a valid base64-encoding.
+        final LocalizableMessage message = ERR_LDIF_COULD_NOT_BASE64_DECODE_DN
+            .get(record.lineNumber, ldifLine, e.getMessageObject());
+        throw DecodeException.error(message);
+      }
+    }
+    else
+    {
+      // The rest of the value should be the DN. Skip over any spaces
+      // and attempt to decode the rest of the line as the DN.
+      int pos = colonPos + 1;
+      while (pos < length && ldifLine.charAt(pos) == ' ')
+      {
+        pos++;
+      }
+
+      dnString = ldifLine.substring(pos);
+    }
+
+    try
+    {
+      return DN.valueOf(dnString, schema);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      final LocalizableMessage message = ERR_LDIF_INVALID_DN.get(
+          record.lineNumber, ldifLine, e.getMessageObject());
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  final String readLDIFRecordKeyValuePair(final LDIFRecord record,
+      final KeyValuePair pair, final boolean allowBase64)
+      throws DecodeException
+  {
+    final String ldifLine = record.iterator.next();
+    final int colonPos = ldifLine.indexOf(":");
+    if (colonPos <= 0)
+    {
+      final LocalizableMessage message = ERR_LDIF_NO_ATTR_NAME.get(
+          record.lineNumber, ldifLine);
+      throw DecodeException.error(message);
+    }
+    pair.key = ldifLine.substring(0, colonPos);
+
+    // Look at the character immediately after the colon. If there is
+    // none, then no value was specified. Throw an exception
+    final int length = ldifLine.length();
+    if (colonPos == length - 1)
+    {
+      // FIXME: improve error.
+      final LocalizableMessage message = LocalizableMessage
+          .raw("Malformed changetype attribute");
+      throw DecodeException.error(message);
+    }
+
+    if (allowBase64 && ldifLine.charAt(colonPos + 1) == ':')
+    {
+      // The value is base64-encoded. Find the first non-blank
+      // character, take the rest of the line, and base64-decode it.
+      int pos = colonPos + 2;
+      while (pos < length && ldifLine.charAt(pos) == ' ')
+      {
+        pos++;
+      }
+
+      try
+      {
+        pair.value = Base64.decode(ldifLine.substring(pos)).toString();
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        // The value did not have a valid base64-encoding.
+        // FIXME: improve error.
+        final LocalizableMessage message = LocalizableMessage
+            .raw("Malformed base64 changetype attribute");
+        throw DecodeException.error(message);
+      }
+    }
+    else
+    {
+      // The rest of the value should be the changetype. Skip over any
+      // spaces and attempt to decode the rest of the line as the
+      // changetype string.
+      int pos = colonPos + 1;
+      while (pos < length && ldifLine.charAt(pos) == ' ')
+      {
+        pos++;
+      }
+
+      pair.value = ldifLine.substring(pos);
+    }
+
+    return ldifLine;
+  }
+
+
+
+  final void rejectLDIFRecord(final LDIFRecord record,
+      final LocalizableMessage message) throws DecodeException
+  {
+    // FIXME: not yet implemented.
+    throw DecodeException.error(message);
+  }
+
+
+
+  final void skipLDIFRecord(final LDIFRecord record,
+      final LocalizableMessage message)
+  {
+    // FIXME: not yet implemented.
+  }
+
+
+
+  // Determine whether the provided line is a continuation line. Note
+  // that while RFC 2849 technically only allows a space in this
+  // position, both OpenLDAP and the Sun Java System Directory Server
+  // allow a tab as well, so we will too for compatibility reasons. See
+  // issue #852 for details.
+  private boolean isContinuationLine(final String line)
+  {
+    return line.charAt(0) == ' ' || line.charAt(0) == '\t';
+  }
+
+
+
+  private String readLine() throws IOException
+  {
+    final String line = impl.readLine();
+    if (line != null)
+    {
+      lineNumber++;
+    }
+    return line;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFStream.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFStream.java
new file mode 100644
index 0000000..fbf1f08
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFStream.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.opends.sdk.AttributeDescription;
+import org.opends.sdk.DN;
+import org.opends.sdk.Entry;
+import org.opends.sdk.Matcher;
+import org.opends.sdk.schema.AttributeType;
+import org.opends.sdk.schema.Schema;
+
+
+
+/**
+ * Common LDIF reader/writer functionality.
+ */
+abstract class AbstractLDIFStream
+{
+
+  final Set<AttributeDescription> excludeAttributes = new HashSet<AttributeDescription>();
+
+  boolean excludeOperationalAttributes = false;
+
+  boolean excludeUserAttributes = false;
+
+  final Set<AttributeDescription> includeAttributes = new HashSet<AttributeDescription>();
+
+  Schema schema = Schema.getDefaultSchema();
+
+  final Set<DN> includeBranches = new HashSet<DN>();
+
+  final Set<DN> excludeBranches = new HashSet<DN>();
+
+  final List<Matcher> includeFilters = new LinkedList<Matcher>();
+
+  final List<Matcher> excludeFilters = new LinkedList<Matcher>();
+
+
+
+  /**
+   * Creates a new abstract LDIF stream.
+   */
+  AbstractLDIFStream()
+  {
+    // Nothing to do.
+  }
+
+
+
+  final boolean isAttributeExcluded(
+      final AttributeDescription attributeDescription)
+  {
+    if (!excludeAttributes.isEmpty()
+        && excludeAttributes.contains(attributeDescription))
+    {
+      return true;
+    }
+
+    // Let explicit include override more general exclude.
+    if (!includeAttributes.isEmpty())
+    {
+      return !includeAttributes.contains(attributeDescription);
+    }
+
+    final AttributeType type = attributeDescription.getAttributeType();
+
+    if (excludeOperationalAttributes && type.isOperational())
+    {
+      return true;
+    }
+
+    if (excludeUserAttributes && !type.isOperational())
+    {
+      return true;
+    }
+
+    return false;
+  }
+
+
+
+  final boolean isBranchExcluded(final DN dn)
+  {
+    if (!excludeBranches.isEmpty())
+    {
+      for (final DN excludeBranch : excludeBranches)
+      {
+        if (excludeBranch.isSuperiorOrEqualTo(dn))
+        {
+          return true;
+        }
+      }
+    }
+
+    if (!includeBranches.isEmpty())
+    {
+      for (final DN includeBranch : includeBranches)
+      {
+        if (includeBranch.isSuperiorOrEqualTo(dn))
+        {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    return false;
+  }
+
+
+
+  final boolean isEntryExcluded(final Entry entry)
+  {
+    if (!excludeFilters.isEmpty())
+    {
+      for (final Matcher excludeFilter : excludeFilters)
+      {
+        if (excludeFilter.matches(entry).toBoolean())
+        {
+          return true;
+        }
+      }
+    }
+
+    if (!includeFilters.isEmpty())
+    {
+      for (final Matcher includeFilter : includeFilters)
+      {
+        if (includeFilter.matches(entry).toBoolean())
+        {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    return false;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFWriter.java
new file mode 100644
index 0000000..8ffade1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/AbstractLDIFWriter.java
@@ -0,0 +1,544 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.controls.Control;
+
+import com.sun.opends.sdk.util.Base64;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Common LDIF writer functionality.
+ */
+abstract class AbstractLDIFWriter extends AbstractLDIFStream
+{
+
+  /**
+   * LDIF writer implementation interface.
+   */
+  interface LDIFWriterImpl
+  {
+
+    /**
+     * Closes any resources associated with this LDIF writer implementation.
+     *
+     * @throws IOException
+     *           If an error occurs while closing.
+     */
+    void close() throws IOException;
+
+
+
+    /**
+     * Flushes this LDIF writer implementation so that any buffered data is
+     * written immediately to underlying stream, flushing the stream if it is
+     * also {@code Flushable}.
+     * <p>
+     * If the intended destination of this stream is an abstraction provided by
+     * the underlying operating system, for example a file, then flushing the
+     * stream guarantees only that bytes previously written to the stream are
+     * passed to the operating system for writing; it does not guarantee that
+     * they are actually written to a physical device such as a disk drive.
+     *
+     * @throws IOException
+     *           If an error occurs while flushing.
+     */
+    void flush() throws IOException;
+
+
+
+    /**
+     * Prints the provided {@code CharSequence}. Implementations must not add a
+     * new-line character sequence.
+     *
+     * @param s
+     *          The {@code CharSequence} to be printed.
+     * @throws IOException
+     *           If an error occurs while printing {@code s}.
+     */
+    void print(CharSequence s) throws IOException;
+
+
+
+    /**
+     * Prints a new-line character sequence.
+     *
+     * @throws IOException
+     *           If an error occurs while printing the new-line character
+     *           sequence.
+     */
+    void println() throws IOException;
+  }
+
+
+
+  /**
+   * LDIF string list writer implementation.
+   */
+  private static final class LDIFWriterListImpl implements LDIFWriterImpl
+  {
+
+    private final StringBuilder builder = new StringBuilder();
+
+    private final List<String> ldifLines;
+
+
+
+    /**
+     * Creates a new LDIF list writer.
+     *
+     * @param ldifLines
+     *          The string list.
+     */
+    LDIFWriterListImpl(final List<String> ldifLines)
+    {
+      this.ldifLines = ldifLines;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException
+    {
+      // Nothing to do.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void flush() throws IOException
+    {
+      // Nothing to do.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void print(final CharSequence s) throws IOException
+    {
+      builder.append(s);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void println() throws IOException
+    {
+      ldifLines.add(builder.toString());
+      builder.setLength(0);
+    }
+  }
+
+
+
+  /**
+   * LDIF output stream writer implementation.
+   */
+  private static final class LDIFWriterOutputStreamImpl implements
+      LDIFWriterImpl
+  {
+
+    private final BufferedWriter writer;
+
+
+
+    /**
+     * Creates a new LDIF output stream writer.
+     *
+     * @param out
+     *          The output stream.
+     */
+    LDIFWriterOutputStreamImpl(final OutputStream out)
+    {
+      this.writer = new BufferedWriter(new OutputStreamWriter(out));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException
+    {
+      writer.close();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void flush() throws IOException
+    {
+      writer.flush();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void print(final CharSequence s) throws IOException
+    {
+      writer.append(s);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void println() throws IOException
+    {
+      writer.newLine();
+    }
+  }
+
+
+
+  // Regular expression used for splitting comments on line-breaks.
+  private static final Pattern SPLIT_NEWLINE = Pattern.compile("\\r?\\n");
+
+  boolean addUserFriendlyComments = false;
+
+  final LDIFWriterImpl impl;
+
+  int wrapColumn = 0;
+
+  private final StringBuilder builder = new StringBuilder(80);
+
+
+
+  /**
+   * Creates a new LDIF entry writer which will append lines of LDIF to the
+   * provided list.
+   *
+   * @param ldifLines
+   *          The list to which lines of LDIF should be appended.
+   */
+  public AbstractLDIFWriter(final List<String> ldifLines)
+  {
+    Validator.ensureNotNull(ldifLines);
+    this.impl = new LDIFWriterListImpl(ldifLines);
+  }
+
+
+
+  /**
+   * Creates a new LDIF entry writer whose destination is the provided output
+   * stream.
+   *
+   * @param out
+   *          The output stream to use.
+   */
+  public AbstractLDIFWriter(final OutputStream out)
+  {
+    Validator.ensureNotNull(out);
+    this.impl = new LDIFWriterOutputStreamImpl(out);
+  }
+
+
+
+  final void close0() throws IOException
+  {
+    flush0();
+    impl.close();
+  }
+
+
+
+  final void flush0() throws IOException
+  {
+    impl.flush();
+  }
+
+
+
+  final void writeComment0(final CharSequence comment) throws IOException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(comment);
+
+    // First, break up the comment into multiple lines to preserve the
+    // original spacing that it contained.
+    final String[] lines = SPLIT_NEWLINE.split(comment);
+
+    // Now iterate through the lines and write them out, prefixing and
+    // wrapping them as necessary.
+    for (final String line : lines)
+    {
+      if (!shouldWrap())
+      {
+        impl.print("# ");
+        impl.print(line);
+        impl.println();
+      }
+      else
+      {
+        final int breakColumn = wrapColumn - 2;
+
+        if (line.length() <= breakColumn)
+        {
+          impl.print("# ");
+          impl.print(line);
+          impl.println();
+        }
+        else
+        {
+          int startPos = 0;
+          outerLoop: while (startPos < line.length())
+          {
+            if (startPos + breakColumn >= line.length())
+            {
+              impl.print("# ");
+              impl.print(line.substring(startPos));
+              impl.println();
+              startPos = line.length();
+            }
+            else
+            {
+              final int endPos = startPos + breakColumn;
+
+              int i = endPos - 1;
+              while (i > startPos)
+              {
+                if (line.charAt(i) == ' ')
+                {
+                  impl.print("# ");
+                  impl.print(line.substring(startPos, i));
+                  impl.println();
+
+                  startPos = i + 1;
+                  continue outerLoop;
+                }
+
+                i--;
+              }
+
+              // If we've gotten here, then there are no spaces on the
+              // entire line. If that happens, then we'll have to break
+              // in the middle of a word.
+              impl.print("# ");
+              impl.print(line.substring(startPos, endPos));
+              impl.println();
+
+              startPos = endPos;
+            }
+          }
+        }
+      }
+    }
+  }
+
+
+
+  final void writeControls(final List<Control> controls) throws IOException
+  {
+    for (final Control control : controls)
+    {
+      final StringBuilder key = new StringBuilder("control: ");
+      key.append(control.getOID());
+      key.append(control.isCritical() ? " true" : " false");
+
+      if (control.hasValue())
+      {
+        writeKeyAndValue(key, control.getValue());
+      }
+      else
+      {
+        writeLine(key);
+      }
+    }
+  }
+
+
+
+  final void writeKeyAndValue(final CharSequence key, final ByteSequence value)
+      throws IOException
+  {
+    builder.setLength(0);
+
+    // If the value is empty, then just append a single colon and a
+    // single space.
+    if (value.length() == 0)
+    {
+      builder.append(key);
+      builder.append(": ");
+    }
+    else if (needsBase64Encoding(value))
+    {
+      if (addUserFriendlyComments)
+      {
+        // TODO: Only display comments for valid UTF-8 values, not
+        // binary values.
+      }
+
+      builder.setLength(0);
+      builder.append(key);
+      builder.append(":: ");
+      builder.append(Base64.encode(value));
+    }
+    else
+    {
+      builder.append(key);
+      builder.append(": ");
+      builder.append(value.toString());
+    }
+
+    writeLine(builder);
+  }
+
+
+
+  final void writeKeyAndValue(final CharSequence key, final CharSequence value)
+      throws IOException
+  {
+    // FIXME: We should optimize this at some point.
+    writeKeyAndValue(key, ByteString.valueOf(value.toString()));
+  }
+
+
+
+  final void writeLine(final CharSequence line) throws IOException
+  {
+    final int length = line.length();
+    if (shouldWrap() && length > wrapColumn)
+    {
+      impl.print(line.subSequence(0, wrapColumn));
+      impl.println();
+      int pos = wrapColumn;
+      while (pos < length)
+      {
+        final int writeLength = Math.min(wrapColumn - 1, length - pos);
+        impl.print(" ");
+        impl.print(line.subSequence(pos, pos + writeLength));
+        impl.println();
+        pos += wrapColumn - 1;
+      }
+    }
+    else
+    {
+      impl.print(line);
+      impl.println();
+    }
+  }
+
+
+
+  private boolean needsBase64Encoding(final ByteSequence bytes)
+  {
+    final int length = bytes.length();
+    if (length == 0)
+    {
+      return false;
+    }
+
+    // If the value starts with a space, colon, or less than, then it
+    // needs to be base64 encoded.
+    switch (bytes.byteAt(0))
+    {
+    case 0x20: // Space
+    case 0x3A: // Colon
+    case 0x3C: // Less-than
+      return true;
+    }
+
+    // If the value ends with a space, then it needs to be
+    // base64 encoded.
+    if (length > 1 && bytes.byteAt(length - 1) == 0x20)
+    {
+      return true;
+    }
+
+    // If the value contains a null, newline, or return character, then
+    // it needs to be base64 encoded.
+    byte b;
+    for (int i = 0; i < bytes.length(); i++)
+    {
+      b = bytes.byteAt(i);
+      if (b > 127 || b < 0)
+      {
+        return true;
+      }
+
+      switch (b)
+      {
+      case 0x00: // Null
+      case 0x0A: // New line
+      case 0x0D: // Carriage return
+        return true;
+      }
+    }
+
+    // If we've made it here, then there's no reason to base64 encode.
+    return false;
+  }
+
+
+
+  private boolean shouldWrap()
+  {
+    return wrapColumn > 1;
+  }
+
+
+
+  @SuppressWarnings("unused")
+  private void writeKeyAndURL(final CharSequence key, final CharSequence url)
+      throws IOException
+  {
+    builder.setLength(0);
+
+    builder.append(key);
+    builder.append(":: ");
+    builder.append(url);
+
+    writeLine(builder);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecord.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecord.java
new file mode 100644
index 0000000..7ab93d4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecord.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import org.opends.sdk.DN;
+
+
+
+/**
+ * A request to modify the content of the Directory in some way. A change record
+ * represents one of the following operations:
+ * <ul>
+ * <li>An {@code Add} operation.
+ * <li>An {@code Delete} operation.
+ * <li>An {@code Modify} operation.
+ * <li>An {@code ModifyDN} operation.
+ * </ul>
+ */
+public interface ChangeRecord
+{
+  /**
+   * Applies a {@code ChangeRecordVisitor} to this {@code ChangeRecord}.
+   *
+   * @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 change record visitor.
+   * @param p
+   *          Optional additional visitor parameter.
+   * @return A result as specified by the visitor.
+   */
+  <R, P> R accept(ChangeRecordVisitor<R, P> v, P p);
+
+
+
+  /**
+   * Returns the distinguished name of the entry being modified by this {@code
+   * ChangeRecord}.
+   *
+   * @return The distinguished name of the entry being modified.
+   */
+  DN getName();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordReader.java
new file mode 100644
index 0000000..5364319
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordReader.java
@@ -0,0 +1,91 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+
+
+/**
+ * An interface for reading change records from a data source, typically an LDIF
+ * file.
+ * <p>
+ * Implementations must specify the following:
+ * <ul>
+ * <li>Whether or not it is possible for the implementation to encounter
+ * malformed change records and, if it is possible, how they are handled.
+ * <li>Any synchronization limitations.
+ * </ul>
+ */
+public interface ChangeRecordReader extends Closeable
+{
+
+  /**
+   * Closes this change record reader if it not already closed. Note that this
+   * method does not need to be called if a previous call of
+   * {@link #readChangeRecord()} has returned {@code null}.
+   *
+   * @throws IOException
+   *           If an unexpected IO error occurred while closing.
+   */
+  @Override
+  void close() throws IOException;
+
+
+
+  /**
+   * Returns {@code true} if this reader contains another change record,
+   * blocking if necessary until either the next change record is available or
+   * the end of the stream is reached.
+   *
+   * @return {@code true} if this reader contains another change record.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  boolean hasNext() throws IOException;
+
+
+
+  /**
+   * Reads the next change record, blocking if necessary until a change record
+   * is available. If the next change record does not contain a change type then
+   * it will be treated as an {@code Add} change record.
+   *
+   * @return The next change record.
+   * @throws IOException
+   *           If an unexpected IO error occurred while reading the change
+   *           record.
+   * @throws NoSuchElementException
+   *           If this reader does not contain any more change records.
+   */
+  ChangeRecord readChangeRecord() throws IOException, NoSuchElementException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitor.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitor.java
new file mode 100644
index 0000000..8dc9de8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitor.java
@@ -0,0 +1,109 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import org.opends.sdk.requests.AddRequest;
+import org.opends.sdk.requests.DeleteRequest;
+import org.opends.sdk.requests.ModifyDNRequest;
+import org.opends.sdk.requests.ModifyRequest;
+
+
+
+/**
+ * A visitor of {@code ChangeRecord}s, in the style of the visitor design
+ * pattern.
+ * <p>
+ * Classes implementing this interface can query change records in a type-safe
+ * manner. When a visitor is passed to a change record's accept method, the
+ * corresponding visit method most applicable to that change record 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 ChangeRecordVisitor<R, P>
+{
+
+  /**
+   * Visits an {@code Add} change record.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param change
+   *          The {@code Add} change record.
+   * @return Returns a visitor specified result.
+   */
+  R visitChangeRecord(P p, AddRequest change);
+
+
+
+  /**
+   * Visits an {@code Delete} change record.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param change
+   *          The {@code Delete} change record.
+   * @return Returns a visitor specified result.
+   */
+  R visitChangeRecord(P p, DeleteRequest change);
+
+
+
+  /**
+   * Visits an {@code ModifyDN} change record.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param change
+   *          The {@code ModifyDN} change record.
+   * @return Returns a visitor specified result.
+   */
+  R visitChangeRecord(P p, ModifyDNRequest change);
+
+
+
+  /**
+   * Visits an {@code Modify} change record.
+   *
+   * @param p
+   *          A visitor specified parameter.
+   * @param change
+   *          The {@code Modify} change record.
+   * @return Returns a visitor specified result.
+   */
+  R visitChangeRecord(P p, ModifyRequest change);
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitorWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitorWriter.java
new file mode 100644
index 0000000..e7b505b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordVisitorWriter.java
@@ -0,0 +1,132 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.requests.AddRequest;
+import org.opends.sdk.requests.DeleteRequest;
+import org.opends.sdk.requests.ModifyDNRequest;
+import org.opends.sdk.requests.ModifyRequest;
+
+
+
+/**
+ * A visitor which can be used to write generic change records.
+ */
+final class ChangeRecordVisitorWriter implements
+    ChangeRecordVisitor<IOException, ChangeRecordWriter>
+{
+  // Visitor used for writing generic change records.
+  private static final ChangeRecordVisitorWriter VISITOR = new ChangeRecordVisitorWriter();
+
+
+
+  /**
+   * Returns the singleton instance.
+   *
+   * @return The instance.
+   */
+  static ChangeRecordVisitorWriter getInstance()
+  {
+    return VISITOR;
+  }
+
+
+
+  private ChangeRecordVisitorWriter()
+  {
+    // Nothing to do.
+  }
+
+
+
+  public IOException visitChangeRecord(final ChangeRecordWriter p,
+      final AddRequest change)
+  {
+    try
+    {
+      p.writeChangeRecord(change);
+      return null;
+    }
+    catch (final IOException e)
+    {
+      return e;
+    }
+  }
+
+
+
+  public IOException visitChangeRecord(final ChangeRecordWriter p,
+      final DeleteRequest change)
+  {
+    try
+    {
+      p.writeChangeRecord(change);
+      return null;
+    }
+    catch (final IOException e)
+    {
+      return e;
+    }
+  }
+
+
+
+  public IOException visitChangeRecord(final ChangeRecordWriter p,
+      final ModifyDNRequest change)
+  {
+    try
+    {
+      p.writeChangeRecord(change);
+      return null;
+    }
+    catch (final IOException e)
+    {
+      return e;
+    }
+  }
+
+
+
+  public IOException visitChangeRecord(final ChangeRecordWriter p,
+      final ModifyRequest change)
+  {
+    try
+    {
+      p.writeChangeRecord(change);
+      return null;
+    }
+    catch (final IOException e)
+    {
+      return e;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordWriter.java
new file mode 100644
index 0000000..a15794e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ChangeRecordWriter.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+
+import org.opends.sdk.requests.AddRequest;
+import org.opends.sdk.requests.DeleteRequest;
+import org.opends.sdk.requests.ModifyDNRequest;
+import org.opends.sdk.requests.ModifyRequest;
+
+
+
+/**
+ * An interface for writing change records to a data source, typically an LDIF
+ * file.
+ * <p>
+ * TODO: FilteredChangeRecordWriter
+ */
+public interface ChangeRecordWriter extends Closeable, Flushable
+{
+  /**
+   * Closes this change record writer, flushing it first. Closing a previously
+   * closed change record writer has no effect.
+   *
+   * @throws IOException
+   *           If an unexpected IO error occurred while closing.
+   */
+  void close() throws IOException;
+
+
+
+  /**
+   * Flushes this change record writer so that any buffered data is written
+   * immediately to underlying stream, flushing the stream if it is also {@code
+   * Flushable}.
+   * <p>
+   * If the intended destination of this stream is an abstraction provided by
+   * the underlying operating system, for example a file, then flushing the
+   * stream guarantees only that bytes previously written to the stream are
+   * passed to the operating system for writing; it does not guarantee that they
+   * are actually written to a physical device such as a disk drive.
+   *
+   * @throws IOException
+   *           If an unexpected IO error occurred while flushing.
+   */
+  void flush() throws IOException;
+
+
+
+  /**
+   * Writes an {@code Add} change record.
+   *
+   * @param change
+   *          The {@code AddRequest} to be written as an {@code Add} change
+   *          record.
+   * @return A reference to this change record writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the change
+   *           record.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  ChangeRecordWriter writeChangeRecord(AddRequest change) throws IOException,
+      NullPointerException;
+
+
+
+  /**
+   * Writes a change record.
+   *
+   * @param change
+   *          The {@code ChangeRecord} to be written.
+   * @return A reference to this change record writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the change
+   *           record.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  ChangeRecordWriter writeChangeRecord(ChangeRecord change) throws IOException,
+      NullPointerException;
+
+
+
+  /**
+   * Writes a {@code Delete} change record.
+   *
+   * @param change
+   *          The {@code DeleteRequest} to be written as an {@code Delete}
+   *          change record.
+   * @return A reference to this change record writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the change
+   *           record.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  ChangeRecordWriter writeChangeRecord(DeleteRequest change)
+      throws IOException, NullPointerException;
+
+
+
+  /**
+   * Writes a {@code ModifyDN} change record.
+   *
+   * @param change
+   *          The {@code ModifyDNRequest} to be written as an {@code ModifyDN}
+   *          change record.
+   * @return A reference to this change record writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the change
+   *           record.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  ChangeRecordWriter writeChangeRecord(ModifyDNRequest change)
+      throws IOException, NullPointerException;
+
+
+
+  /**
+   * Writes a {@code Modify} change record.
+   *
+   * @param change
+   *          The {@code ModifyRequest} to be written as an {@code Modify}
+   *          change record.
+   * @return A reference to this change record writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the change
+   *           record.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  ChangeRecordWriter writeChangeRecord(ModifyRequest change)
+      throws IOException, NullPointerException;
+
+
+
+  /**
+   * Writes a comment.
+   *
+   * @param comment
+   *          The {@code CharSequence} to be written as a comment.
+   * @return A reference to this change record writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the comment.
+   * @throws NullPointerException
+   *           If {@code comment} was {@code null}.
+   */
+  ChangeRecordWriter writeComment(CharSequence comment) throws IOException,
+      NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionChangeRecordWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionChangeRecordWriter.java
new file mode 100644
index 0000000..8cadd45
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionChangeRecordWriter.java
@@ -0,0 +1,322 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+import org.opends.sdk.Connection;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ErrorResultIOException;
+import org.opends.sdk.requests.AddRequest;
+import org.opends.sdk.requests.DeleteRequest;
+import org.opends.sdk.requests.ModifyDNRequest;
+import org.opends.sdk.requests.ModifyRequest;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A {@code ConnectionChangeRecordWriter} is a bridge from {@code Connection}s
+ * to {@code ChangeRecordWriter}s. A connection change record writer writes
+ * change records by sending appropriate update requests (Add, Delete, Modify,
+ * or ModifyDN) to an underlying connection.
+ * <p>
+ * All update requests are performed synchronously, blocking until an update
+ * result is received. If an update result indicates that an update request has
+ * failed for some reason then the error result is propagated to the caller
+ * using an {@code ErrorResultIOException}.
+ * <p>
+ * <b>Note:</b> comments are not supported by connection change record writers.
+ * Attempts to write comments will be ignored.
+ */
+public final class ConnectionChangeRecordWriter implements ChangeRecordWriter
+{
+  private final Connection connection;
+
+
+
+  /**
+   * Creates a new connection change record writer whose destination is the
+   * provided connection.
+   *
+   * @param connection
+   *          The connection to use.
+   * @throws NullPointerException
+   *           If {@code connection} was {@code null}.
+   */
+  public ConnectionChangeRecordWriter(final Connection connection)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(connection);
+    this.connection = connection;
+  }
+
+
+
+  /**
+   * Closes this connection change record writer, including the underlying
+   * connection. Closing a previously closed change record writer has no effect.
+   */
+  public void close()
+  {
+    connection.close();
+  }
+
+
+
+  /**
+   * Connection change record writers do not require flushing, so this method
+   * has no effect.
+   */
+  public void flush()
+  {
+    // Do nothing.
+  }
+
+
+
+  /**
+   * Writes the provided Add request to the underlying connection, blocking
+   * until the request completes.
+   *
+   * @param change
+   *          The {@code AddRequest} to be written.
+   * @return A reference to this connection change record writer.
+   * @throws ErrorResultIOException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  public ConnectionChangeRecordWriter writeChangeRecord(final AddRequest change)
+      throws ErrorResultIOException, InterruptedIOException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(change);
+    try
+    {
+      connection.add(change);
+    }
+    catch (final ErrorResultException e)
+    {
+      throw new ErrorResultIOException(e);
+    }
+    catch (final InterruptedException e)
+    {
+      throw new InterruptedIOException(e.getMessage());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Writes the provided change record to the underlying connection, blocking
+   * until the request completes.
+   *
+   * @param change
+   *          The change record to be written.
+   * @return A reference to this connection change record writer.
+   * @throws ErrorResultIOException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  public ConnectionChangeRecordWriter writeChangeRecord(
+      final ChangeRecord change) throws ErrorResultIOException,
+      InterruptedIOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+
+    final IOException e = change.accept(
+        ChangeRecordVisitorWriter.getInstance(), this);
+    try
+    {
+      if (e != null)
+      {
+        throw e;
+      }
+    }
+    catch (final ErrorResultIOException e1)
+    {
+      throw e1;
+    }
+    catch (final InterruptedIOException e1)
+    {
+      throw e1;
+    }
+    catch (final IOException e1)
+    {
+      // Should not happen.
+      throw new RuntimeException(e1);
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Writes the provided Delete request to the underlying connection, blocking
+   * until the request completes.
+   *
+   * @param change
+   *          The {@code DeleteRequest} to be written.
+   * @return A reference to this connection change record writer.
+   * @throws ErrorResultIOException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  public ConnectionChangeRecordWriter writeChangeRecord(
+      final DeleteRequest change) throws ErrorResultIOException,
+      InterruptedIOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+    try
+    {
+      connection.delete(change);
+    }
+    catch (final ErrorResultException e)
+    {
+      throw new ErrorResultIOException(e);
+    }
+    catch (final InterruptedException e)
+    {
+      throw new InterruptedIOException(e.getMessage());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Writes the provided ModifyDN request to the underlying connection, blocking
+   * until the request completes.
+   *
+   * @param change
+   *          The {@code ModifyDNRequest} to be written.
+   * @return A reference to this connection change record writer.
+   * @throws ErrorResultIOException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  public ConnectionChangeRecordWriter writeChangeRecord(
+      final ModifyDNRequest change) throws ErrorResultIOException,
+      InterruptedIOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+    try
+    {
+      connection.modifyDN(change);
+    }
+    catch (final ErrorResultException e)
+    {
+      throw new ErrorResultIOException(e);
+    }
+    catch (final InterruptedException e)
+    {
+      throw new InterruptedIOException(e.getMessage());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Writes the provided Modify request to the underlying connection, blocking
+   * until the request completes.
+   *
+   * @param change
+   *          The {@code ModifyRequest} to be written.
+   * @return A reference to this connection change record writer.
+   * @throws ErrorResultIOException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NullPointerException
+   *           If {@code change} was {@code null}.
+   */
+  public ConnectionChangeRecordWriter writeChangeRecord(
+      final ModifyRequest change) throws ErrorResultIOException,
+      InterruptedIOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+    try
+    {
+      connection.modify(change);
+    }
+    catch (final ErrorResultException e)
+    {
+      throw new ErrorResultIOException(e);
+    }
+    catch (final InterruptedException e)
+    {
+      throw new InterruptedIOException(e.getMessage());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Connection change record writers do not support comments, so the provided
+   * comment will be ignored.
+   *
+   * @param comment
+   *          The {@code CharSequence} to be written as a comment.
+   * @return A reference to this connection change record writer.
+   * @throws NullPointerException
+   *           If {@code comment} was {@code null}.
+   */
+  public ConnectionChangeRecordWriter writeComment(final CharSequence comment)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(comment);
+
+    // Do nothing.
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryReader.java
new file mode 100644
index 0000000..8e6e353
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryReader.java
@@ -0,0 +1,429 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.InterruptedIOException;
+import java.util.NoSuchElementException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A {@code ConnectionEntryReader} is a bridge from
+ * {@code AsynchronousConnection}s to {@code EntryReader}s. A connection entry
+ * reader allows applications to iterate over search results as they are
+ * returned from the server during a search operation.
+ * <p>
+ * The Search operation is performed synchronously, blocking until a search
+ * result entry is received. If a search result indicates that the search
+ * operation has failed for some reason then the error result is propagated to
+ * the caller using an {@code ErrorResultIOException}. If a search result
+ * reference is returned then it is propagated to the caller using a
+ * {@code SearchResultReferenceIOException}.
+ * <p>
+ * The following code illustrates how a {@code ConnectionEntryReader} may be
+ * used:
+ *
+ * <pre>
+ * Connection connection = ...;
+ * ConnectionEntryReader results = connection.search(&quot;dc=example,dc=com&quot;,
+ *     SearchScope.WHOLE_SUBTREE, &quot;(objectClass=person)&quot;);
+ * try
+ * {
+ *   while (reader.hasNext())
+ *   {
+ *     if (!reader.isReference())
+ *     {
+ *       SearchResultEntry entry = reader.readEntry();
+ *
+ *       // Handle entry...
+ *     }
+ *     else
+ *     {
+ *       SearchResultReference ref = reader.readReference();
+ *
+ *       // Handle continuation reference...
+ *     }
+ *   }
+ * }
+ * catch (IOException e)
+ * {
+ *   // Handle exceptions...
+ * }
+ * finally
+ * {
+ *   results.close();
+ * }
+ * </pre>
+ */
+public final class ConnectionEntryReader implements EntryReader
+{
+
+  /**
+   * Result handler that places all responses in a queue.
+   */
+  private final static class BufferHandler implements SearchResultHandler
+  {
+    private final BlockingQueue<Response> responses;
+    private volatile boolean isInterrupted = false;
+
+
+
+    private BufferHandler(final BlockingQueue<Response> responses)
+    {
+      this.responses = responses;
+    }
+
+
+
+    @Override
+    public boolean handleEntry(final SearchResultEntry entry)
+    {
+      try
+      {
+        responses.put(entry);
+        return true;
+      }
+      catch (final InterruptedException e)
+      {
+        // Prevent the reader from waiting for a result that will never arrive.
+        isInterrupted = true;
+
+        Thread.currentThread().interrupt();
+        return false;
+      }
+    }
+
+
+
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      try
+      {
+        responses.put(error.getResult());
+      }
+      catch (final InterruptedException e)
+      {
+        // Prevent the reader from waiting for a result that will never arrive.
+        isInterrupted = true;
+
+        Thread.currentThread().interrupt();
+      }
+    }
+
+
+
+    @Override
+    public boolean handleReference(final SearchResultReference reference)
+    {
+      try
+      {
+        responses.put(reference);
+        return true;
+      }
+      catch (final InterruptedException e)
+      {
+        // Prevent the reader from waiting for a result that will never arrive.
+        isInterrupted = true;
+
+        Thread.currentThread().interrupt();
+        return false;
+      }
+    }
+
+
+
+    @Override
+    public void handleResult(final Result result)
+    {
+      try
+      {
+        responses.put(result);
+      }
+      catch (final InterruptedException e)
+      {
+        // Prevent the reader from waiting for a result that will never arrive.
+        isInterrupted = true;
+
+        Thread.currentThread().interrupt();
+      }
+    }
+  }
+
+
+
+  private final BufferHandler buffer;
+  private final FutureResult<Result> future;
+  private Response nextResponse = null;
+
+
+
+  /**
+   * Creates a new connection entry reader whose destination is the provided
+   * connection using an unbounded {@code LinkedBlockingQueue}.
+   *
+   * @param connection
+   *          The connection to use.
+   * @param searchRequest
+   *          The search request to retrieve entries with.
+   * @throws NullPointerException
+   *           If {@code connection} was {@code null}.
+   */
+  public ConnectionEntryReader(final AsynchronousConnection connection,
+      final SearchRequest searchRequest) throws NullPointerException
+  {
+    this(connection, searchRequest, new LinkedBlockingQueue<Response>());
+  }
+
+
+
+  /**
+   * Creates a new connection entry reader whose destination is the provided
+   * connection.
+   *
+   * @param connection
+   *          The connection to use.
+   * @param searchRequest
+   *          The search request to retrieve entries with.
+   * @param entries
+   *          The {@code BlockingQueue} implementation to use when queuing the
+   *          returned entries.
+   * @throws NullPointerException
+   *           If {@code connection} was {@code null}.
+   */
+  public ConnectionEntryReader(final AsynchronousConnection connection,
+      final SearchRequest searchRequest, final BlockingQueue<Response> entries)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(connection);
+    buffer = new BufferHandler(entries);
+    future = connection.search(searchRequest, buffer);
+  }
+
+
+
+  /**
+   * Closes this connection entry reader, cancelling the search request if it is
+   * still active.
+   */
+  @Override
+  public void close()
+  {
+    // Cancel the search if it is still running.
+    future.cancel(true);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasNext() throws ErrorResultIOException,
+      InterruptedIOException
+  {
+    // Poll for the next response if needed.
+    final Response r = getNextResponse();
+    if (!(r instanceof Result))
+    {
+      // Entry or reference.
+      return true;
+    }
+
+    // Final result.
+    final Result result = (Result) r;
+    if (result.isSuccess())
+    {
+      return false;
+    }
+
+    final ErrorResultException e = ErrorResultException.wrap(result);
+    throw new ErrorResultIOException(e);
+  }
+
+
+
+  /**
+   * Waits for the next search result entry or reference to become available and
+   * returns {@code true} if it is a reference, or {@code false} if it is an
+   * entry.
+   *
+   * @return {@code true} if the next search result is a reference, or
+   *         {@code false} if it is an entry.
+   * @throws ErrorResultIOException
+   *           If there are no more search result entries or references and the
+   *           search result code indicates that the search operation failed for
+   *           some reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NoSuchElementException
+   *           If there are no more search result entries or references and the
+   *           search result code indicates that the search operation succeeded.
+   */
+  public boolean isReference() throws ErrorResultIOException,
+      InterruptedIOException, NoSuchElementException
+  {
+    // Throws ErrorResultIOException if search returned error.
+    if (!hasNext())
+    {
+      // Search has completed successfully.
+      throw new NoSuchElementException();
+    }
+
+    // Entry or reference.
+    final Response r = nextResponse;
+    if (r instanceof SearchResultEntry)
+    {
+      return false;
+    }
+    else if (r instanceof SearchResultReference)
+    {
+      return true;
+    }
+    else
+    {
+      throw new RuntimeException("Unexpected response type: "
+          + r.getClass().toString());
+    }
+  }
+
+
+
+  /**
+   * Waits for the next search result entry or reference to become available
+   * and, if it is an entry, returns it as a {@code SearchResultEntry}. If the
+   * next search response is a reference then this method will throw a
+   * {@code SearchResultReferenceIOException}.
+   *
+   * @return The next search result entry.
+   * @throws SearchResultReferenceIOException
+   *           If the next search response was a search result reference. This
+   *           connection entry reader may still contain remaining search
+   *           results and references which can be retrieved using additional
+   *           calls to this method.
+   * @throws ErrorResultIOException
+   *           If there are no more search result entries or references and the
+   *           search result code indicates that the search operation failed for
+   *           some reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NoSuchElementException
+   *           If there are no more search result entries or references and the
+   *           search result code indicates that the search operation succeeded.
+   */
+  @Override
+  public SearchResultEntry readEntry() throws SearchResultReferenceIOException,
+      ErrorResultIOException, InterruptedIOException, NoSuchElementException
+  {
+    if (!isReference())
+    {
+      final SearchResultEntry entry = (SearchResultEntry) nextResponse;
+      nextResponse = null;
+      return entry;
+    }
+    else
+    {
+      final SearchResultReference reference = (SearchResultReference) nextResponse;
+      nextResponse = null;
+      throw new SearchResultReferenceIOException(reference);
+    }
+  }
+
+
+
+  /**
+   * Waits for the next search result entry or reference to become available
+   * and, if it is a reference, returns it as a {@code SearchResultReference}.
+   * If the next search response is an entry then this method will return
+   * {@code null}.
+   *
+   * @return The next search result reference, or {@code null} if the next
+   *         response was a search result entry.
+   * @throws ErrorResultIOException
+   *           If there are no more search result entries or references and the
+   *           search result code indicates that the search operation failed for
+   *           some reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NoSuchElementException
+   *           If there are no more search result entries or references and the
+   *           search result code indicates that the search operation succeeded.
+   */
+  public SearchResultReference readReference() throws ErrorResultIOException,
+      InterruptedIOException, NoSuchElementException
+  {
+    if (isReference())
+    {
+      final SearchResultReference reference = (SearchResultReference) nextResponse;
+      nextResponse = null;
+      return reference;
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
+  private Response getNextResponse() throws InterruptedIOException
+  {
+    while (nextResponse == null)
+    {
+      try
+      {
+        nextResponse = buffer.responses.poll(50, TimeUnit.MILLISECONDS);
+      }
+      catch (final InterruptedException e)
+      {
+        throw new InterruptedIOException(e.getMessage());
+      }
+
+      if (nextResponse == null && buffer.isInterrupted)
+      {
+        // The worker thread processing the result was interrupted so no
+        // result will ever arrive. We don't want to hang this thread
+        // forever while we wait, so terminate now.
+        nextResponse = Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR);
+        break;
+      }
+    }
+    return nextResponse;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryWriter.java
new file mode 100644
index 0000000..2e0ab68
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/ConnectionEntryWriter.java
@@ -0,0 +1,158 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.InterruptedIOException;
+
+import org.opends.sdk.Connection;
+import org.opends.sdk.Entry;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ErrorResultIOException;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * A {@code ConnectionEntryWriter} is a bridge from {@code Connection}s to
+ * {@code EntryWriter}s. A connection entry writer writes entries by sending Add
+ * requests to an underlying connection.
+ * <p>
+ * All Add requests are performed synchronously, blocking until an Add result is
+ * received. If an Add result indicates that an Add request has failed for some
+ * reason then the error result is propagated to the caller using an {@code
+ * ErrorResultIOException}.
+ * <p>
+ * <b>Note:</b> comments are not supported by connection change record writers.
+ * Attempts to write comments will be ignored.
+ */
+public final class ConnectionEntryWriter implements EntryWriter
+{
+  private final Connection connection;
+
+
+
+  /**
+   * Creates a new connection entry writer whose destination is the provided
+   * connection.
+   *
+   * @param connection
+   *          The connection to use.
+   * @throws NullPointerException
+   *           If {@code connection} was {@code null}.
+   */
+  public ConnectionEntryWriter(final Connection connection)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(connection);
+    this.connection = connection;
+  }
+
+
+
+  /**
+   * Closes this connection entry writer, including the underlying connection.
+   * Closing a previously closed entry writer has no effect.
+   */
+  public void close()
+  {
+    connection.close();
+  }
+
+
+
+  /**
+   * Connection entry writers do not require flushing, so this method has no
+   * effect.
+   */
+  public void flush()
+  {
+    // Do nothing.
+  }
+
+
+
+  /**
+   * Connection entry writers do not support comments, so the provided comment
+   * will be ignored.
+   *
+   * @param comment
+   *          The {@code CharSequence} to be written as a comment.
+   * @return A reference to this connection entry writer.
+   * @throws NullPointerException
+   *           If {@code comment} was {@code null}.
+   */
+  public ConnectionEntryWriter writeComment(final CharSequence comment)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(comment);
+
+    // Do nothing.
+    return this;
+  }
+
+
+
+  /**
+   * Writes an entry to the underlying connection using an Add request, blocking
+   * until the request completes.
+   *
+   * @param entry
+   *          The {@code Entry} to be written.
+   * @return A reference to this connection entry writer.
+   * @throws ErrorResultIOException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedIOException
+   *           If the current thread was interrupted while waiting.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public ConnectionEntryWriter writeEntry(final Entry entry)
+      throws ErrorResultIOException, InterruptedIOException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(entry);
+    try
+    {
+      connection.add(entry);
+    }
+    catch (final ErrorResultException e)
+    {
+      throw new ErrorResultIOException(e);
+    }
+    catch (final InterruptedException e)
+    {
+      throw new InterruptedIOException(e.getMessage());
+    }
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryReader.java
new file mode 100644
index 0000000..688b827
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryReader.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+import org.opends.sdk.Entry;
+
+
+
+/**
+ * An interface for reading entries from a data source, typically an LDIF file.
+ * <p>
+ * Implementations must specify the following:
+ * <ul>
+ * <li>Whether or not it is possible for the implementation to encounter
+ * malformed change records and, if it is possible, how they are handled.
+ * <li>Any synchronization limitations.
+ * </ul>
+ */
+public interface EntryReader extends Closeable
+{
+
+  /**
+   * Closes this entry reader if it is not already closed. Note that this method
+   * does not need to be called if a previous call of {@link #readEntry()} has
+   * returned {@code null}.
+   *
+   * @throws IOException
+   *           If an unexpected IO error occurred while closing.
+   */
+  @Override
+  void close() throws IOException;
+
+
+
+  /**
+   * Returns {@code true} if this reader contains another entry, blocking if
+   * necessary until either the next entry is available or the end of the stream
+   * is reached.
+   *
+   * @return {@code true} if this reader contains another entry.
+   * @throws IOException
+   *           If an unexpected IO error occurred.
+   */
+  boolean hasNext() throws IOException;
+
+
+
+  /**
+   * Reads the next entry, blocking if necessary until an entry is available.
+   *
+   * @return The next entry.
+   * @throws IOException
+   *           If an unexpected IO error occurred while reading the entry.
+   * @throws NoSuchElementException
+   *           If this reader does not contain any more entries.
+   */
+  Entry readEntry() throws IOException, NoSuchElementException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryWriter.java
new file mode 100644
index 0000000..438268c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/EntryWriter.java
@@ -0,0 +1,104 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+
+import org.opends.sdk.Entry;
+
+
+
+/**
+ * An interface for writing entries to a data source, typically an LDIF file.
+ * <p>
+ * TODO: FilteredChangeRecordWriter
+ */
+public interface EntryWriter extends Closeable, Flushable
+{
+  /**
+   * Closes this entry writer, flushing it first. Closing a previously closed
+   * entry writer has no effect.
+   *
+   * @throws IOException
+   *           If an unexpected IO error occurred while closing.
+   */
+  void close() throws IOException;
+
+
+
+  /**
+   * Flushes this entry writer so that any buffered data is written immediately
+   * to underlying stream, flushing the stream if it is also {@code Flushable}.
+   * <p>
+   * If the intended destination of this stream is an abstraction provided by
+   * the underlying operating system, for example a file, then flushing the
+   * stream guarantees only that bytes previously written to the stream are
+   * passed to the operating system for writing; it does not guarantee that they
+   * are actually written to a physical device such as a disk drive.
+   *
+   * @throws IOException
+   *           If an unexpected IO error occurred while flushing.
+   */
+  void flush() throws IOException;
+
+
+
+  /**
+   * Writes a comment.
+   *
+   * @param comment
+   *          The {@code CharSequence} to be written as a comment.
+   * @return A reference to this entry writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the comment.
+   * @throws NullPointerException
+   *           If {@code comment} was {@code null}.
+   */
+  EntryWriter writeComment(CharSequence comment) throws IOException,
+      NullPointerException;
+
+
+
+  /**
+   * Writes an entry.
+   *
+   * @param entry
+   *          The {@code Entry} to be written.
+   * @return A reference to this entry writer.
+   * @throws IOException
+   *           If an unexpected IO error occurred while writing the entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  EntryWriter writeEntry(Entry entry) throws IOException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordReader.java
new file mode 100644
index 0000000..3a8fec6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordReader.java
@@ -0,0 +1,751 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.ModifyDNRequest;
+import org.opends.sdk.requests.ModifyRequest;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An LDIF change record reader reads change records using the LDAP Data
+ * Interchange Format (LDIF) from a user defined source.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP Data
+ *      Interchange Format (LDIF) - Technical Specification </a>
+ */
+public final class LDIFChangeRecordReader extends AbstractLDIFReader implements
+    ChangeRecordReader
+{
+  /**
+   * Parses the provided array of LDIF lines as a single LDIF change record.
+   *
+   * @param ldifLines
+   *          The lines of LDIF to be parsed.
+   * @return The parsed LDIF change record.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} did not contain an LDIF change record, if it
+   *           contained multiple change records, if contained malformed LDIF,
+   *           or if the change record could not be decoded using the default
+   *           schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null}.
+   */
+  public static ChangeRecord valueOfLDIFChangeRecord(final String... ldifLines)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    // LDIF change record reader is tolerant to missing change types.
+    final LDIFChangeRecordReader reader = new LDIFChangeRecordReader(ldifLines);
+    try
+    {
+      if (!reader.hasNext())
+      {
+        // No change record found.
+        final LocalizableMessage message = WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      final ChangeRecord record = reader.readChangeRecord();
+
+      if (reader.hasNext())
+      {
+        // Multiple change records found.
+        final LocalizableMessage message = WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      return record;
+    }
+    catch (final DecodeException e)
+    {
+      // Badly formed LDIF.
+      throw new LocalizedIllegalArgumentException(e.getMessageObject());
+    }
+    catch (final IOException e)
+    {
+      // This should never happen for a String based reader.
+      final LocalizableMessage message = WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR
+          .get(e.getMessage());
+      throw new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  private ChangeRecord nextChangeRecord = null;
+
+  // Poison used to indicate end of LDIF.
+  private static final ChangeRecord EOF = Requests.newAddRequest(DN.rootDN());
+
+
+
+  /**
+   * Creates a new LDIF change record reader whose source is the provided input
+   * stream.
+   *
+   * @param in
+   *          The input stream to use.
+   * @throws NullPointerException
+   *           If {@code in} was {@code null}.
+   */
+  public LDIFChangeRecordReader(final InputStream in)
+      throws NullPointerException
+  {
+    super(in);
+  }
+
+
+
+  /**
+   * Creates a new LDIF change record reader which will read lines of LDIF from
+   * the provided list of LDIF lines.
+   *
+   * @param ldifLines
+   *          The lines of LDIF to be read.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null}.
+   */
+  public LDIFChangeRecordReader(final List<String> ldifLines)
+      throws NullPointerException
+  {
+    super(ldifLines);
+  }
+
+
+
+  /**
+   * Creates a new LDIF change record reader which will read lines of LDIF from
+   * the provided array of LDIF lines.
+   *
+   * @param ldifLines
+   *          The lines of LDIF to be read.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null}.
+   */
+  public LDIFChangeRecordReader(final String... ldifLines)
+      throws NullPointerException
+  {
+    super(Arrays.asList(ldifLines));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close() throws IOException
+  {
+    close0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   *
+   * @throws DecodeException
+   *           If the change record could not be decoded because it was
+   *           malformed.
+   */
+  @Override
+  public boolean hasNext() throws DecodeException, IOException
+  {
+    return getNextChangeRecord() != EOF;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   *
+   * @throws DecodeException
+   *           If the entry could not be decoded because it was malformed.
+   */
+  @Override
+  public ChangeRecord readChangeRecord() throws DecodeException, IOException
+  {
+    if (!hasNext())
+    {
+      // LDIF reader has completed successfully.
+      throw new NoSuchElementException();
+    }
+
+    final ChangeRecord changeRecord = nextChangeRecord;
+    nextChangeRecord = null;
+    return changeRecord;
+  }
+
+
+
+  /**
+   * Specifies whether or not all operational attributes should be excluded from
+   * any change records that are read from LDIF. The default is {@code false}.
+   *
+   * @param excludeOperationalAttributes
+   *          {@code true} if all operational attributes should be excluded, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setExcludeAllOperationalAttributes(
+      final boolean excludeOperationalAttributes)
+  {
+    this.excludeOperationalAttributes = excludeOperationalAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not all user attributes should be excluded from any
+   * change records that are read from LDIF. The default is {@code false}.
+   *
+   * @param excludeUserAttributes
+   *          {@code true} if all user attributes should be excluded, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setExcludeAllUserAttributes(
+      final boolean excludeUserAttributes)
+  {
+    this.excludeUserAttributes = excludeUserAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Excludes the named attribute from any change records that are read from
+   * LDIF. By default all attributes are included unless explicitly excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be excluded.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setExcludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    excludeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Excludes all change records which target entries beneath the named entry
+   * (inclusive) from being read from LDIF. By default all change records are
+   * read unless explicitly excluded or included.
+   *
+   * @param excludeBranch
+   *          The distinguished name of the branch to be excluded.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setExcludeBranch(final DN excludeBranch)
+  {
+    Validator.ensureNotNull(excludeBranch);
+    excludeBranches.add(excludeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that the named attribute is not excluded from any change records
+   * that are read from LDIF. By default all attributes are included unless
+   * explicitly excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be included.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setIncludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    includeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that all change records which target entries beneath the named
+   * entry (inclusive) are read from LDIF. By default all change records are
+   * read unless explicitly excluded or included.
+   *
+   * @param includeBranch
+   *          The distinguished name of the branch to be included.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setIncludeBranch(final DN includeBranch)
+  {
+    Validator.ensureNotNull(includeBranch);
+    includeBranches.add(includeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Sets the schema which should be used for decoding change records that are
+   * read from LDIF. The default schema is used if no other is specified.
+   *
+   * @param schema
+   *          The schema which should be used for decoding change records that
+   *          are read from LDIF.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setSchema(final Schema schema)
+  {
+    Validator.ensureNotNull(schema);
+    this.schema = schema;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not schema validation should be performed for change
+   * records that are read from LDIF. The default is {@code true} .
+   *
+   * @param validateSchema
+   *          {@code true} if schema validation should be performed, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFChangeRecordReader}.
+   */
+  public LDIFChangeRecordReader setValidateSchema(final boolean validateSchema)
+  {
+    this.validateSchema = validateSchema;
+    return this;
+  }
+
+
+
+  private ChangeRecord getNextChangeRecord() throws DecodeException,
+      IOException
+  {
+    while (nextChangeRecord == null)
+    {
+      LDIFRecord record = null;
+
+      // Read the set of lines that make up the next entry.
+      record = readLDIFRecord();
+      if (record == null)
+      {
+        nextChangeRecord = EOF;
+        break;
+      }
+
+      // Read the DN of the entry and see if it is one that should be
+      // included in the import.
+      DN entryDN;
+      try
+      {
+        entryDN = readLDIFRecordDN(record);
+        if (entryDN == null)
+        {
+          // Skip version record.
+          continue;
+        }
+      }
+      catch (final DecodeException e)
+      {
+        rejectLDIFRecord(record, e.getMessageObject());
+        continue;
+      }
+
+      // Skip if branch containing the entry DN is excluded.
+      if (isBranchExcluded(entryDN))
+      {
+        final LocalizableMessage message = LocalizableMessage
+            .raw("Skipping entry because it is in excluded branch");
+        skipLDIFRecord(record, message);
+        continue;
+      }
+
+      ChangeRecord changeRecord = null;
+      try
+      {
+        if (!record.iterator.hasNext())
+        {
+          // FIXME: improve error.
+          final LocalizableMessage message = LocalizableMessage
+              .raw("Missing changetype");
+          throw DecodeException.error(message);
+        }
+
+        final KeyValuePair pair = new KeyValuePair();
+        final String ldifLine = readLDIFRecordKeyValuePair(record, pair, false);
+
+        if (!toLowerCase(pair.key).equals("changetype"))
+        {
+          // Default to add change record.
+          changeRecord = parseAddChangeRecordEntry(entryDN, ldifLine, record);
+        }
+        else
+        {
+          final String changeType = toLowerCase(pair.value);
+          if (changeType.equals("add"))
+          {
+            changeRecord = parseAddChangeRecordEntry(entryDN, null, record);
+          }
+          else if (changeType.equals("delete"))
+          {
+            changeRecord = parseDeleteChangeRecordEntry(entryDN, record);
+          }
+          else if (changeType.equals("modify"))
+          {
+            changeRecord = parseModifyChangeRecordEntry(entryDN, record);
+          }
+          else if (changeType.equals("modrdn"))
+          {
+            changeRecord = parseModifyDNChangeRecordEntry(entryDN, record);
+          }
+          else if (changeType.equals("moddn"))
+          {
+            changeRecord = parseModifyDNChangeRecordEntry(entryDN, record);
+          }
+          else
+          {
+            // FIXME: improve error.
+            final LocalizableMessage message = ERR_LDIF_INVALID_CHANGETYPE_ATTRIBUTE
+                .get(pair.value, "add, delete, modify, moddn, modrdn");
+            throw DecodeException.error(message);
+          }
+        }
+      }
+      catch (final DecodeException e)
+      {
+        rejectLDIFRecord(record, e.getMessageObject());
+        continue;
+      }
+
+      if (changeRecord != null)
+      {
+        nextChangeRecord = changeRecord;
+      }
+    }
+    return nextChangeRecord;
+  }
+
+
+
+  private ChangeRecord parseAddChangeRecordEntry(final DN entryDN,
+      final String lastLDIFLine, final LDIFRecord record)
+      throws DecodeException
+  {
+    // Use an Entry for the AttributeSequence.
+    final Entry entry = new LinkedHashMapEntry(entryDN);
+
+    if (lastLDIFLine != null)
+    {
+      // This line was read when looking for the change type.
+      readLDIFRecordAttributeValue(record, lastLDIFLine, entry);
+    }
+
+    while (record.iterator.hasNext())
+    {
+      final String ldifLine = record.iterator.next();
+      readLDIFRecordAttributeValue(record, ldifLine, entry);
+    }
+
+    return Requests.newAddRequest(entry);
+  }
+
+
+
+  private ChangeRecord parseDeleteChangeRecordEntry(final DN entryDN,
+      final LDIFRecord record) throws DecodeException
+  {
+    if (record.iterator.hasNext())
+    {
+      // FIXME: include line number in error.
+      final LocalizableMessage message = ERR_LDIF_INVALID_DELETE_ATTRIBUTES
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    return Requests.newDeleteRequest(entryDN);
+  }
+
+
+
+  private ChangeRecord parseModifyChangeRecordEntry(final DN entryDN,
+      final LDIFRecord record) throws DecodeException
+  {
+    final ModifyRequest modifyRequest = Requests.newModifyRequest(entryDN);
+
+    final KeyValuePair pair = new KeyValuePair();
+    final List<ByteString> attributeValues = new ArrayList<ByteString>();
+
+    while (record.iterator.hasNext())
+    {
+      readLDIFRecordKeyValuePair(record, pair, false);
+      final String changeType = toLowerCase(pair.key);
+
+      ModificationType modType;
+      if (changeType.equals("add"))
+      {
+        modType = ModificationType.ADD;
+      }
+      else if (changeType.equals("delete"))
+      {
+        modType = ModificationType.DELETE;
+      }
+      else if (changeType.equals("replace"))
+      {
+        modType = ModificationType.REPLACE;
+      }
+      else if (changeType.equals("increment"))
+      {
+        modType = ModificationType.INCREMENT;
+      }
+      else
+      {
+        // FIXME: improve error.
+        final LocalizableMessage message = ERR_LDIF_INVALID_MODIFY_ATTRIBUTE
+            .get(pair.key, "add, delete, replace, increment");
+        throw DecodeException.error(message);
+      }
+
+      AttributeDescription attributeDescription;
+      try
+      {
+        attributeDescription = AttributeDescription.valueOf(pair.value, schema);
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        throw DecodeException.error(e.getMessageObject());
+      }
+
+      // Skip the attribute if requested before performing any schema
+      // checking: the attribute may have been excluded because it is
+      // known to violate the schema.
+      if (isAttributeExcluded(attributeDescription))
+      {
+        continue;
+      }
+
+      // Ensure that the binary option is present if required.
+      if (!attributeDescription.getAttributeType().getSyntax()
+          .isBEREncodingRequired())
+      {
+        if (validateSchema && attributeDescription.containsOption("binary"))
+        {
+          final LocalizableMessage message = ERR_LDIF_INVALID_ATTR_OPTION.get(
+              entryDN.toString(), record.lineNumber, pair.value);
+          throw DecodeException.error(message);
+        }
+      }
+      else
+      {
+        attributeDescription = AttributeDescription.create(
+            attributeDescription, "binary");
+      }
+
+      // Now go through the rest of the attributes until the "-" line is
+      // reached.
+      attributeValues.clear();
+      while (record.iterator.hasNext())
+      {
+        final String ldifLine = record.iterator.next();
+        if (ldifLine.equals("-"))
+        {
+          break;
+        }
+
+        // Parse the attribute description.
+        final int colonPos = parseColonPosition(record, ldifLine);
+        final String attrDescr = ldifLine.substring(0, colonPos);
+
+        AttributeDescription attributeDescription2;
+        try
+        {
+          attributeDescription2 = AttributeDescription.valueOf(attrDescr,
+              schema);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          throw DecodeException.error(e.getMessageObject());
+        }
+
+        // Ensure that the binary option is present if required.
+        if (attributeDescription.getAttributeType().getSyntax()
+            .isBEREncodingRequired())
+        {
+          attributeDescription2 = AttributeDescription.create(
+              attributeDescription2, "binary");
+        }
+
+        if (!attributeDescription2.equals(attributeDescription))
+        {
+          // TODO: include line number.
+          final LocalizableMessage message = ERR_LDIF_INVALID_CHANGERECORD_ATTRIBUTE
+              .get(attributeDescription2.toString(),
+                  attributeDescription.toString());
+          throw DecodeException.error(message);
+        }
+
+        // Now parse the attribute value.
+        attributeValues.add(parseSingleValue(record, ldifLine, entryDN,
+            colonPos, attrDescr));
+      }
+
+      final Modification change = new Modification(modType,
+          new LinkedAttribute(attributeDescription, attributeValues));
+      modifyRequest.addModification(change);
+    }
+
+    return modifyRequest;
+  }
+
+
+
+  private ChangeRecord parseModifyDNChangeRecordEntry(final DN entryDN,
+      final LDIFRecord record) throws DecodeException
+  {
+    ModifyDNRequest modifyDNRequest;
+
+    // Parse the newrdn.
+    if (!record.iterator.hasNext())
+    {
+      // TODO: include line number.
+      final LocalizableMessage message = ERR_LDIF_NO_MOD_DN_ATTRIBUTES.get();
+      throw DecodeException.error(message);
+    }
+
+    final KeyValuePair pair = new KeyValuePair();
+    String ldifLine = record.iterator.next();
+    readLDIFRecordKeyValuePair(record, pair, true);
+    if (!toLowerCase(pair.key).equals("newrdn"))
+    {
+      // FIXME: improve error.
+      final LocalizableMessage message = LocalizableMessage
+          .raw("Missing newrdn");
+      throw DecodeException.error(message);
+    }
+
+    try
+    {
+      final RDN newRDN = RDN.valueOf(pair.value, schema);
+      modifyDNRequest = Requests.newModifyDNRequest(entryDN, newRDN);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      final LocalizableMessage message = ERR_LDIF_INVALID_DN.get(
+          record.lineNumber, ldifLine, e.getMessageObject());
+      throw DecodeException.error(message);
+    }
+
+    // Parse the deleteoldrdn.
+    if (!record.iterator.hasNext())
+    {
+      // TODO: include line number.
+      final LocalizableMessage message = ERR_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    ldifLine = record.iterator.next();
+    readLDIFRecordKeyValuePair(record, pair, true);
+    if (!toLowerCase(pair.key).equals("deleteoldrdn"))
+    {
+      // FIXME: improve error.
+      final LocalizableMessage message = LocalizableMessage
+          .raw("Missing deleteoldrdn");
+      throw DecodeException.error(message);
+    }
+
+    final String delStr = toLowerCase(pair.value);
+    if (delStr.equals("false") || delStr.equals("no") || delStr.equals("0"))
+    {
+      modifyDNRequest.setDeleteOldRDN(false);
+    }
+    else if (delStr.equals("true") || delStr.equals("yes")
+        || delStr.equals("1"))
+    {
+      modifyDNRequest.setDeleteOldRDN(true);
+    }
+    else
+    {
+      // FIXME: improve error.
+      final LocalizableMessage message = ERR_LDIF_INVALID_DELETE_OLDRDN_ATTRIBUTE
+          .get(pair.value);
+      throw DecodeException.error(message);
+    }
+
+    // Parse the newsuperior if present.
+    if (record.iterator.hasNext())
+    {
+      ldifLine = record.iterator.next();
+      readLDIFRecordKeyValuePair(record, pair, true);
+      if (!toLowerCase(pair.key).equals("newsuperior"))
+      {
+        // FIXME: improve error.
+        final LocalizableMessage message = LocalizableMessage
+            .raw("Missing newsuperior");
+        throw DecodeException.error(message);
+      }
+
+      try
+      {
+        final DN newSuperiorDN = DN.valueOf(pair.value, schema);
+        modifyDNRequest.setNewSuperior(newSuperiorDN.toString());
+      }
+      catch (final LocalizedIllegalArgumentException e)
+      {
+        final LocalizableMessage message = ERR_LDIF_INVALID_DN.get(
+            record.lineNumber, ldifLine, e.getMessageObject());
+        throw DecodeException.error(message);
+      }
+    }
+
+    return modifyDNRequest;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordWriter.java
new file mode 100644
index 0000000..b5862ff
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFChangeRecordWriter.java
@@ -0,0 +1,471 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.AddRequest;
+import org.opends.sdk.requests.DeleteRequest;
+import org.opends.sdk.requests.ModifyDNRequest;
+import org.opends.sdk.requests.ModifyRequest;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An LDIF change record writer writes change records using the LDAP Data
+ * Interchange Format (LDIF) to a user defined destination.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP Data
+ *      Interchange Format (LDIF) - Technical Specification </a>
+ */
+public final class LDIFChangeRecordWriter extends AbstractLDIFWriter implements
+    ChangeRecordWriter
+{
+
+  /**
+   * Creates a new LDIF change record writer which will append lines of LDIF to
+   * the provided list.
+   *
+   * @param ldifLines
+   *          The list to which lines of LDIF should be appended.
+   */
+  public LDIFChangeRecordWriter(final List<String> ldifLines)
+  {
+    super(ldifLines);
+  }
+
+
+
+  /**
+   * Creates a new LDIF change record writer whose destination is the provided
+   * output stream.
+   *
+   * @param out
+   *          The output stream to use.
+   */
+  public LDIFChangeRecordWriter(final OutputStream out)
+  {
+    super(out);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException
+  {
+    close0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void flush() throws IOException
+  {
+    flush0();
+  }
+
+
+
+  /**
+   * Specifies whether or not user-friendly comments should be added whenever
+   * distinguished names or UTF-8 attribute values are encountered which
+   * contained non-ASCII characters. The default is {@code false}.
+   *
+   * @param addUserFriendlyComments
+   *          {@code true} if user-friendly comments should be added, or {@code
+   *          false} otherwise.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFChangeRecordWriter setAddUserFriendlyComments(
+      final boolean addUserFriendlyComments)
+  {
+    this.addUserFriendlyComments = addUserFriendlyComments;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not all operational attributes should be excluded from
+   * any change records that are written to LDIF. The default is {@code false}.
+   *
+   * @param excludeOperationalAttributes
+   *          {@code true} if all operational attributes should be excluded, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFChangeRecordWriter}.
+   */
+  public LDIFChangeRecordWriter setExcludeAllOperationalAttributes(
+      final boolean excludeOperationalAttributes)
+  {
+    this.excludeOperationalAttributes = excludeOperationalAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not all user attributes should be excluded from any
+   * change records that are written to LDIF. The default is {@code false}.
+   *
+   * @param excludeUserAttributes
+   *          {@code true} if all user attributes should be excluded, or {@code
+   *          false} otherwise.
+   * @return A reference to this {@code LDIFChangeRecordWriter}.
+   */
+  public LDIFChangeRecordWriter setExcludeAllUserAttributes(
+      final boolean excludeUserAttributes)
+  {
+    this.excludeUserAttributes = excludeUserAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Excludes the named attribute from any change records that are written to
+   * LDIF. By default all attributes are included unless explicitly excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be excluded.
+   * @return A reference to this {@code LDIFChangeRecordWriter}.
+   */
+  public LDIFChangeRecordWriter setExcludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    excludeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Excludes all change records which target entries beneath the named entry
+   * (inclusive) from being written to LDIF. By default all change records are
+   * written unless explicitly excluded or included.
+   *
+   * @param excludeBranch
+   *          The distinguished name of the branch to be excluded.
+   * @return A reference to this {@code LDIFChangeRecordWriter}.
+   */
+  public LDIFChangeRecordWriter setExcludeBranch(final DN excludeBranch)
+  {
+    Validator.ensureNotNull(excludeBranch);
+    excludeBranches.add(excludeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that the named attribute is not excluded from any change records
+   * that are written to LDIF. By default all attributes are included unless
+   * explicitly excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be included.
+   * @return A reference to this {@code LDIFChangeRecordWriter}.
+   */
+  public LDIFChangeRecordWriter setIncludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    includeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that all change records which target entries beneath the named
+   * entry (inclusive) are written to LDIF. By default all change records are
+   * written unless explicitly excluded or included.
+   *
+   * @param includeBranch
+   *          The distinguished name of the branch to be included.
+   * @return A reference to this {@code LDIFChangeRecordWriter}.
+   */
+  public LDIFChangeRecordWriter setIncludeBranch(final DN includeBranch)
+  {
+    Validator.ensureNotNull(includeBranch);
+    includeBranches.add(includeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Sets the schema which should be used when filtering change records (not
+   * required if no filtering is to be performed). The default schema is used if
+   * no other is specified.
+   *
+   * @param schema
+   *          The schema which should be used when filtering change records.
+   * @return A reference to this {@code LDIFChangeRecordWriter}.
+   */
+  public LDIFChangeRecordWriter setSchema(final Schema schema)
+  {
+    Validator.ensureNotNull(schema);
+    this.schema = schema;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies the column at which long lines should be wrapped. A value less
+   * than or equal to zero (the default) indicates that no wrapping should be
+   * performed.
+   *
+   * @param wrapColumn
+   *          The column at which long lines should be wrapped.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFChangeRecordWriter setWrapColumn(final int wrapColumn)
+  {
+    this.wrapColumn = wrapColumn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFChangeRecordWriter writeChangeRecord(final AddRequest change)
+      throws IOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+
+    // Skip if branch containing the entry is excluded.
+    if (isBranchExcluded(change.getName()))
+    {
+      return this;
+    }
+
+    writeKeyAndValue("dn", change.getName().toString());
+    writeControls(change.getControls());
+    writeLine("changetype: add");
+    for (final Attribute attribute : change.getAllAttributes())
+    {
+      // Filter the attribute if required.
+      if (isAttributeExcluded(attribute.getAttributeDescription()))
+      {
+        continue;
+      }
+
+      final String attributeDescription = attribute
+          .getAttributeDescriptionAsString();
+      for (final ByteString value : attribute)
+      {
+        writeKeyAndValue(attributeDescription, value);
+      }
+    }
+
+    // Make sure there is a blank line after the entry.
+    impl.println();
+
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFChangeRecordWriter writeChangeRecord(final ChangeRecord change)
+      throws IOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+
+    // Skip if branch containing the entry is excluded.
+    if (isBranchExcluded(change.getName()))
+    {
+      return this;
+    }
+
+    final IOException e = change.accept(
+        ChangeRecordVisitorWriter.getInstance(), this);
+    if (e != null)
+    {
+      throw e;
+    }
+    else
+    {
+      return this;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFChangeRecordWriter writeChangeRecord(final DeleteRequest change)
+      throws IOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+
+    // Skip if branch containing the entry is excluded.
+    if (isBranchExcluded(change.getName()))
+    {
+      return this;
+    }
+
+    writeKeyAndValue("dn", change.getName().toString());
+    writeControls(change.getControls());
+    writeLine("changetype: delete");
+
+    // Make sure there is a blank line after the entry.
+    impl.println();
+
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFChangeRecordWriter writeChangeRecord(final ModifyDNRequest change)
+      throws IOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+
+    // Skip if branch containing the entry is excluded.
+    if (isBranchExcluded(change.getName()))
+    {
+      return this;
+    }
+
+    writeKeyAndValue("dn", change.getName().toString());
+    writeControls(change.getControls());
+
+    // Write the changetype. Some older tools may not support the
+    // "moddn" changetype, so only use it if a newSuperior element has
+    // been provided, but use modrdn elsewhere.
+    if (change.getNewSuperior() == null)
+    {
+      writeLine("changetype: modrdn");
+    }
+    else
+    {
+      writeLine("changetype: moddn");
+    }
+
+    writeKeyAndValue("newrdn", change.getNewRDN().toString());
+    writeKeyAndValue("deleteoldrdn", change.isDeleteOldRDN() ? "1" : "0");
+    if (change.getNewSuperior() != null)
+    {
+      writeKeyAndValue("newsuperior", change.getNewSuperior().toString());
+    }
+
+    // Make sure there is a blank line after the entry.
+    impl.println();
+
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFChangeRecordWriter writeChangeRecord(final ModifyRequest change)
+      throws IOException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+
+    // If there aren't any modifications, then there's nothing to do.
+    if (change.getModifications().isEmpty())
+    {
+      return this;
+    }
+
+    // Skip if branch containing the entry is excluded.
+    if (isBranchExcluded(change.getName()))
+    {
+      return this;
+    }
+
+    writeKeyAndValue("dn", change.getName().toString());
+    writeControls(change.getControls());
+    writeLine("changetype: modify");
+
+    for (final Modification modification : change.getModifications())
+    {
+      final ModificationType type = modification.getModificationType();
+      final Attribute attribute = modification.getAttribute();
+      final String attributeDescription = attribute
+          .getAttributeDescriptionAsString();
+
+      // Filter the attribute if required.
+      if (isAttributeExcluded(attribute.getAttributeDescription()))
+      {
+        continue;
+      }
+
+      writeKeyAndValue(type.toString(), attributeDescription);
+      for (final ByteString value : attribute)
+      {
+        writeKeyAndValue(attributeDescription, value);
+      }
+      writeLine("-");
+    }
+
+    // Make sure there is a blank line after the entry.
+    impl.println();
+
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFChangeRecordWriter writeComment(final CharSequence comment)
+      throws IOException, NullPointerException
+  {
+    writeComment0(comment);
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryReader.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryReader.java
new file mode 100644
index 0000000..b51cd73
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryReader.java
@@ -0,0 +1,468 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An LDIF entry reader reads attribute value records (entries) using the LDAP
+ * Data Interchange Format (LDIF) from a user defined source.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP Data
+ *      Interchange Format (LDIF) - Technical Specification </a>
+ */
+public final class LDIFEntryReader extends AbstractLDIFReader implements
+    EntryReader
+{
+  // Poison used to indicate end of LDIF.
+  private static final Entry EOF = new LinkedHashMapEntry();
+
+
+
+  /**
+   * Parses the provided array of LDIF lines as a single LDIF entry.
+   *
+   * @param ldifLines
+   *          The lines of LDIF to be parsed.
+   * @return The parsed LDIF entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} did not contain an LDIF entry, if it
+   *           contained multiple entries, if contained malformed LDIF, or if
+   *           the entry could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null}.
+   */
+  public static Entry valueOfLDIFEntry(final String... ldifLines)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    final LDIFEntryReader reader = new LDIFEntryReader(ldifLines);
+    try
+    {
+      if (!reader.hasNext())
+      {
+        // No change record found.
+        final LocalizableMessage message = WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      final Entry entry = reader.readEntry();
+
+      if (reader.hasNext())
+      {
+        // Multiple change records found.
+        final LocalizableMessage message = WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      return entry;
+    }
+    catch (final DecodeException e)
+    {
+      // Badly formed LDIF.
+      throw new LocalizedIllegalArgumentException(e.getMessageObject());
+    }
+    catch (final IOException e)
+    {
+      // This should never happen for a String based reader.
+      final LocalizableMessage message = WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR
+          .get(e.getMessage());
+      throw new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  private Entry nextEntry = null;
+
+
+
+  /**
+   * Creates a new LDIF entry reader whose source is the provided input stream.
+   *
+   * @param in
+   *          The input stream to use.
+   * @throws NullPointerException
+   *           If {@code in} was {@code null}.
+   */
+  public LDIFEntryReader(final InputStream in) throws NullPointerException
+  {
+    super(in);
+  }
+
+
+
+  /**
+   * Creates a new LDIF entry reader which will read lines of LDIF from the
+   * provided list of LDIF lines.
+   *
+   * @param ldifLines
+   *          The lines of LDIF to be read.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null}.
+   */
+  public LDIFEntryReader(final List<String> ldifLines)
+      throws NullPointerException
+  {
+    super(ldifLines);
+  }
+
+
+
+  /**
+   * Creates a new LDIF entry reader which will read lines of LDIF from the
+   * provided array of LDIF lines.
+   *
+   * @param ldifLines
+   *          The lines of LDIF to be read.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null}.
+   */
+  public LDIFEntryReader(final String... ldifLines) throws NullPointerException
+  {
+    super(Arrays.asList(ldifLines));
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void close() throws IOException
+  {
+    close0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   *
+   * @throws DecodeException
+   *           If the entry could not be decoded because it was malformed.
+   */
+  @Override
+  public boolean hasNext() throws DecodeException, IOException
+  {
+    return getNextEntry() != EOF;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   *
+   * @throws DecodeException
+   *           If the entry could not be decoded because it was malformed.
+   */
+  @Override
+  public Entry readEntry() throws DecodeException, IOException
+  {
+    if (!hasNext())
+    {
+      // LDIF reader has completed successfully.
+      throw new NoSuchElementException();
+    }
+
+    final Entry entry = nextEntry;
+    nextEntry = null;
+    return entry;
+  }
+
+
+
+  /**
+   * Specifies whether or not all operational attributes should be excluded from
+   * any entries that are read from LDIF. The default is {@code false}.
+   *
+   * @param excludeOperationalAttributes
+   *          {@code true} if all operational attributes should be excluded, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setExcludeAllOperationalAttributes(
+      final boolean excludeOperationalAttributes)
+  {
+    this.excludeOperationalAttributes = excludeOperationalAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not all user attributes should be excluded from any
+   * entries that are read from LDIF. The default is {@code false}.
+   *
+   * @param excludeUserAttributes
+   *          {@code true} if all user attributes should be excluded, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setExcludeAllUserAttributes(
+      final boolean excludeUserAttributes)
+  {
+    this.excludeUserAttributes = excludeUserAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Excludes the named attribute from any entries that are read from LDIF. By
+   * default all attributes are included unless explicitly excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be excluded.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setExcludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    excludeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Excludes all entries beneath the named entry (inclusive) from being read
+   * from LDIF. By default all entries are written unless explicitly excluded or
+   * included by branches or filters.
+   *
+   * @param excludeBranch
+   *          The distinguished name of the branch to be excluded.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setExcludeBranch(final DN excludeBranch)
+  {
+    Validator.ensureNotNull(excludeBranch);
+    excludeBranches.add(excludeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Excludes all entries which match the provided filter matcher from being
+   * read from LDIF. By default all entries are read unless explicitly excluded
+   * or included by branches or filters.
+   *
+   * @param excludeFilter
+   *          The filter matcher.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setExcludeFilter(final Matcher excludeFilter)
+  {
+    Validator.ensureNotNull(excludeFilter);
+    excludeFilters.add(excludeFilter);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that the named attribute is not excluded from any entries that are
+   * read from LDIF. By default all attributes are included unless explicitly
+   * excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be included.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setIncludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    includeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that all entries beneath the named entry (inclusive) are read from
+   * LDIF. By default all entries are written unless explicitly excluded or
+   * included by branches or filters.
+   *
+   * @param includeBranch
+   *          The distinguished name of the branch to be included.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setIncludeBranch(final DN includeBranch)
+  {
+    Validator.ensureNotNull(includeBranch);
+    includeBranches.add(includeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that all entries which match the provided filter matcher are read
+   * from LDIF. By default all entries are read unless explicitly excluded or
+   * included by branches or filters.
+   *
+   * @param includeFilter
+   *          The filter matcher.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setIncludeFilter(final Matcher includeFilter)
+  {
+    Validator.ensureNotNull(includeFilter);
+    includeFilters.add(includeFilter);
+    return this;
+  }
+
+
+
+  /**
+   * Sets the schema which should be used for decoding entries that are read
+   * from LDIF. The default schema is used if no other is specified.
+   *
+   * @param schema
+   *          The schema which should be used for decoding entries that are read
+   *          from LDIF.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setSchema(final Schema schema)
+  {
+    Validator.ensureNotNull(schema);
+    this.schema = schema;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not schema validation should be performed for entries
+   * that are read from LDIF. The default is {@code true}.
+   *
+   * @param validateSchema
+   *          {@code true} if schema validation should be performed, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFEntryReader}.
+   */
+  public LDIFEntryReader setValidateSchema(final boolean validateSchema)
+  {
+    this.validateSchema = validateSchema;
+    return this;
+  }
+
+
+
+  private Entry getNextEntry() throws DecodeException, IOException
+  {
+    while (nextEntry == null)
+    {
+      LDIFRecord record = null;
+
+      // Read the set of lines that make up the next entry.
+      record = readLDIFRecord();
+      if (record == null)
+      {
+        nextEntry = EOF;
+        break;
+      }
+
+      // Read the DN of the entry and see if it is one that should be
+      // included in the import.
+      DN entryDN;
+      try
+      {
+        entryDN = readLDIFRecordDN(record);
+        if (entryDN == null)
+        {
+          // Skip version record.
+          continue;
+        }
+      }
+      catch (final DecodeException e)
+      {
+        rejectLDIFRecord(record, e.getMessageObject());
+        continue;
+      }
+
+      // Skip if branch containing the entry DN is excluded.
+      if (isBranchExcluded(entryDN))
+      {
+        final LocalizableMessage message = LocalizableMessage
+            .raw("Skipping entry because it is in excluded branch");
+        skipLDIFRecord(record, message);
+        continue;
+      }
+
+      // Use an Entry for the AttributeSequence.
+      final Entry entry = new LinkedHashMapEntry(entryDN);
+      try
+      {
+        while (record.iterator.hasNext())
+        {
+          final String ldifLine = record.iterator.next();
+          readLDIFRecordAttributeValue(record, ldifLine, entry);
+        }
+      }
+      catch (final DecodeException e)
+      {
+        rejectLDIFRecord(record, e.getMessageObject());
+        continue;
+      }
+
+      // Skip if the entry is excluded by any filters.
+      if (isEntryExcluded(entry))
+      {
+        final LocalizableMessage message = LocalizableMessage
+            .raw("Skipping entry due to exclusing filters");
+        skipLDIFRecord(record, message);
+        continue;
+      }
+
+      nextEntry = entry;
+    }
+
+    return nextEntry;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryWriter.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryWriter.java
new file mode 100644
index 0000000..273b378
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/LDIFEntryWriter.java
@@ -0,0 +1,362 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.schema.Schema;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An LDIF entry writer writes attribute value records (entries) using the LDAP
+ * Data Interchange Format (LDIF) to a user defined destination.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2849">RFC 2849 - The LDAP Data
+ *      Interchange Format (LDIF) - Technical Specification </a>
+ */
+public final class LDIFEntryWriter extends AbstractLDIFWriter implements
+    EntryWriter
+{
+
+  /**
+   * Creates a new LDIF entry writer which will append lines of LDIF to the
+   * provided list.
+   *
+   * @param ldifLines
+   *          The list to which lines of LDIF should be appended.
+   */
+  public LDIFEntryWriter(final List<String> ldifLines)
+  {
+    super(ldifLines);
+  }
+
+
+
+  /**
+   * Creates a new LDIF entry writer whose destination is the provided output
+   * stream.
+   *
+   * @param out
+   *          The output stream to use.
+   */
+  public LDIFEntryWriter(final OutputStream out)
+  {
+    super(out);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException
+  {
+    close0();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void flush() throws IOException
+  {
+    flush0();
+  }
+
+
+
+  /**
+   * Specifies whether or not user-friendly comments should be added whenever
+   * distinguished names or UTF-8 attribute values are encountered which
+   * contained non-ASCII characters. The default is {@code false}.
+   *
+   * @param addUserFriendlyComments
+   *          {@code true} if user-friendly comments should be added, or {@code
+   *          false} otherwise.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setAddUserFriendlyComments(
+      final boolean addUserFriendlyComments)
+  {
+    this.addUserFriendlyComments = addUserFriendlyComments;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not all operational attributes should be excluded from
+   * any entries that are written to LDIF. The default is {@code false}.
+   *
+   * @param excludeOperationalAttributes
+   *          {@code true} if all operational attributes should be excluded, or
+   *          {@code false} otherwise.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setExcludeAllOperationalAttributes(
+      final boolean excludeOperationalAttributes)
+  {
+    this.excludeOperationalAttributes = excludeOperationalAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not all user attributes should be excluded from any
+   * entries that are written to LDIF. The default is {@code false}.
+   *
+   * @param excludeUserAttributes
+   *          {@code true} if all user attributes should be excluded, or {@code
+   *          false} otherwise.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setExcludeAllUserAttributes(
+      final boolean excludeUserAttributes)
+  {
+    this.excludeUserAttributes = excludeUserAttributes;
+    return this;
+  }
+
+
+
+  /**
+   * Excludes the named attribute from any entries that are written to LDIF. By
+   * default all attributes are included unless explicitly excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be excluded.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setExcludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    excludeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Excludes all entries beneath the named entry (inclusive) from being written
+   * to LDIF. By default all entries are written unless explicitly excluded or
+   * included by branches or filters.
+   *
+   * @param excludeBranch
+   *          The distinguished name of the branch to be excluded.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setExcludeBranch(final DN excludeBranch)
+  {
+    Validator.ensureNotNull(excludeBranch);
+    excludeBranches.add(excludeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Excludes all entries which match the provided filter matcher from being
+   * written to LDIF. By default all entries are written unless explicitly
+   * excluded or included by branches or filters.
+   *
+   * @param excludeFilter
+   *          The filter matcher.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setExcludeFilter(final Matcher excludeFilter)
+  {
+    Validator.ensureNotNull(excludeFilter);
+    excludeFilters.add(excludeFilter);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that the named attribute is not excluded from any entries that are
+   * written to LDIF. By default all attributes are included unless explicitly
+   * excluded.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be included.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setIncludeAttribute(
+      final AttributeDescription attributeDescription)
+  {
+    Validator.ensureNotNull(attributeDescription);
+    includeAttributes.add(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that all entries beneath the named entry (inclusive) are written to
+   * LDIF. By default all entries are written unless explicitly excluded or
+   * included by branches or filters.
+   *
+   * @param includeBranch
+   *          The distinguished name of the branch to be included.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setIncludeBranch(final DN includeBranch)
+  {
+    Validator.ensureNotNull(includeBranch);
+    includeBranches.add(includeBranch);
+    return this;
+  }
+
+
+
+  /**
+   * Ensures that all entries which match the provided filter matcher are
+   * written to LDIF. By default all entries are written unless explicitly
+   * excluded or included by branches or filters.
+   *
+   * @param includeFilter
+   *          The filter matcher.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setIncludeFilter(final Matcher includeFilter)
+  {
+    Validator.ensureNotNull(includeFilter);
+    includeFilters.add(includeFilter);
+    return this;
+  }
+
+
+
+  /**
+   * Sets the schema which should be used when filtering entries (not required
+   * if no filtering is to be performed). The default schema is used if no other
+   * is specified.
+   *
+   * @param schema
+   *          The schema which should be used when filtering entries.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setSchema(final Schema schema)
+  {
+    Validator.ensureNotNull(schema);
+    this.schema = schema;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies the column at which long lines should be wrapped. A value less
+   * than or equal to zero (the default) indicates that no wrapping should be
+   * performed.
+   *
+   * @param wrapColumn
+   *          The column at which long lines should be wrapped.
+   * @return A reference to this {@code LDIFEntryWriter}.
+   */
+  public LDIFEntryWriter setWrapColumn(final int wrapColumn)
+  {
+    this.wrapColumn = wrapColumn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFEntryWriter writeComment(final CharSequence comment)
+      throws IOException, NullPointerException
+  {
+    writeComment0(comment);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LDIFEntryWriter writeEntry(final Entry entry) throws IOException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(entry);
+
+    // Skip if branch containing the entry is excluded.
+    if (isBranchExcluded(entry.getName()))
+    {
+      return this;
+    }
+
+    // Skip if the entry is excluded by any filters.
+    if (isEntryExcluded(entry))
+    {
+      return this;
+    }
+
+    writeKeyAndValue("dn", entry.getName().toString());
+    for (final Attribute attribute : entry.getAllAttributes())
+    {
+      // Filter the attribute if required.
+      if (isAttributeExcluded(attribute.getAttributeDescription()))
+      {
+        continue;
+      }
+
+      final String attributeDescription = attribute
+          .getAttributeDescriptionAsString();
+      if (attribute.isEmpty())
+      {
+        writeKeyAndValue(attributeDescription, ByteString.empty());
+      }
+      else
+      {
+        for (final ByteString value : attribute)
+        {
+          writeKeyAndValue(attributeDescription, value);
+        }
+      }
+    }
+
+    // Make sure there is a blank line after the entry.
+    impl.println();
+
+    return this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/package-info.java
new file mode 100755
index 0000000..74795fb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/ldif/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes and interfaces for reading and writing LDIF.
+ */
+package org.opends.sdk.ldif;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/package-info.java
new file mode 100755
index 0000000..6275f95
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes and interfaces for core types including connections, entries, and
+ * attributes.
+ */
+package org.opends.sdk;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequest.java
new file mode 100644
index 0000000..305c931
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequest.java
@@ -0,0 +1,92 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The Abandon operation allows a client to request that the server abandon an
+ * uncompleted operation.
+ * <p>
+ * Abandon, Bind, Unbind, and StartTLS operations cannot be abandoned.
+ */
+public interface AbandonRequest extends Request
+{
+  /**
+   * {@inheritDoc}
+   */
+  AbandonRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the request ID of the request to be abandoned.
+   *
+   * @return The request ID of the request to be abandoned.
+   */
+  int getRequestID();
+
+
+
+  /**
+   * Sets the request ID of the request to be abandoned.
+   *
+   * @param id
+   *          The request ID of the request to be abandoned.
+   * @return This abandon request.
+   * @throws UnsupportedOperationException
+   *           If this abandon request does not permit the request ID to be set.
+   */
+  AbandonRequest setRequestID(int id) throws UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequestImpl.java
new file mode 100644
index 0000000..66c44ec
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbandonRequestImpl.java
@@ -0,0 +1,115 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+/**
+ * Abandon request implementation.
+ */
+final class AbandonRequestImpl extends AbstractRequestImpl<AbandonRequest>
+    implements AbandonRequest
+{
+
+  private int requestID;
+
+
+
+  /**
+   * Creates a new abandon request using the provided message ID.
+   *
+   * @param requestID
+   *          The message ID of the request to be abandoned.
+   */
+  AbandonRequestImpl(final int requestID)
+  {
+    this.requestID = requestID;
+  }
+
+
+
+  /**
+   * Creates a new abandon request that is an exact copy of the provided
+   * request.
+   *
+   * @param abandonRequest
+   *          The abandon request to be copied.
+   * @throws NullPointerException
+   *           If {@code abandonRequest} was {@code null} .
+   */
+  AbandonRequestImpl(final AbandonRequest abandonRequest)
+  {
+    super(abandonRequest);
+    this.requestID = abandonRequest.getRequestID();
+  }
+
+
+
+  public int getRequestID()
+  {
+    return requestID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AbandonRequest setRequestID(final int id)
+      throws UnsupportedOperationException
+  {
+    this.requestID = id;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AbandonRequest(requestID=");
+    builder.append(getRequestID());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  AbandonRequest getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractBindRequest.java
new file mode 100644
index 0000000..ef9b856
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractBindRequest.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+/**
+ * An abstract Bind request which can be used as the basis for implementing new
+ * authentication methods.
+ *
+ * @param <R>
+ *          The type of Bind request.
+ */
+abstract class AbstractBindRequest<R extends BindRequest> extends
+    AbstractRequestImpl<R> implements BindRequest
+{
+
+  /**
+   * Creates a new abstract bind request.
+   */
+  protected AbstractBindRequest()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * Creates a new abstract bind request that is an exact copy of the provided
+   * request.
+   *
+   * @param bindRequest
+   *          The bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code bindRequest} was {@code null} .
+   */
+  protected AbstractBindRequest(BindRequest bindRequest)
+  {
+    super(bindRequest);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract String getName();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @SuppressWarnings("unchecked")
+  final R getThis()
+  {
+    return (R) this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractExtendedRequest.java
new file mode 100644
index 0000000..4099461
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractExtendedRequest.java
@@ -0,0 +1,141 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An abstract Extended request which can be used as the basis for implementing
+ * new Extended operations.
+ *
+ * @param <R>
+ *          The type of extended request.
+ * @param <S>
+ *          The type of result.
+ */
+public abstract class AbstractExtendedRequest<R extends ExtendedRequest<S>,
+                                              S extends ExtendedResult>
+    extends AbstractRequestImpl<R> implements ExtendedRequest<S>
+{
+
+  /**
+   * Creates a new abstract extended request.
+   */
+  protected AbstractExtendedRequest()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * Creates a new extended request that is an exact copy of the provided
+   * request.
+   *
+   * @param extendedRequest
+   *          The extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code extendedRequest} was {@code null} .
+   */
+  protected AbstractExtendedRequest(ExtendedRequest<S> extendedRequest)
+      throws NullPointerException
+  {
+    super(extendedRequest);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract ExtendedResultDecoder<S> getResultDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract boolean hasValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ExtendedRequest(requestName=");
+    builder.append(getOID());
+    if (hasValue())
+    {
+      builder.append(", requestValue=");
+      StaticUtils.toHexPlusAscii(getValue(), builder, 4);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @SuppressWarnings("unchecked")
+  final R getThis()
+  {
+    return (R) this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractRequestImpl.java
new file mode 100644
index 0000000..310b594
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Abstract request implementation.
+ *
+ * @param <R>
+ *          The type of request.
+ */
+abstract class AbstractRequestImpl<R extends Request> implements Request
+{
+  private final List<Control> controls = new LinkedList<Control>();
+
+
+
+  /**
+   * Creates a new abstract request implementation.
+   */
+  AbstractRequestImpl()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * Creates a new abstract request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The request to be copied.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  AbstractRequestImpl(Request request) throws NullPointerException
+  {
+    Validator.ensureNotNull(request);
+    for (Control control : request.getControls())
+    {
+      // Create defensive copy.
+      controls.add(GenericControl.newControl(control));
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final R addControl(final Control control) throws NullPointerException
+  {
+    Validator.ensureNotNull(control);
+    controls.add(control);
+    return getThis();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final <C extends Control> C getControl(
+      final ControlDecoder<C> decoder, final DecodeOptions options)
+      throws DecodeException
+  {
+    Validator.ensureNotNull(decoder, options);
+
+    // Avoid creating an iterator if possible.
+    if (controls.isEmpty())
+    {
+      return null;
+    }
+
+    for (final Control control : controls)
+    {
+      if (control.getOID().equals(decoder.getOID()))
+      {
+        return decoder.decodeControl(control, options);
+      }
+    }
+
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final List<Control> getControls()
+  {
+    return controls;
+  }
+
+
+
+  @Override
+  public abstract String toString();
+
+
+
+  abstract R getThis();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractSASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractSASLBindRequest.java
new file mode 100644
index 0000000..f054b70
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractSASLBindRequest.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.TYPE_AUTHENTICATION_SASL;
+
+
+
+/**
+ * An abstract SASL Bind request which can be used as the basis for implementing
+ * new SASL authentication methods.
+ *
+ * @param <R>
+ *          The type of SASL Bind request.
+ */
+abstract class AbstractSASLBindRequest<R extends SASLBindRequest> extends
+    AbstractBindRequest<R> implements SASLBindRequest
+{
+
+  AbstractSASLBindRequest()
+  {
+
+  }
+
+
+
+  AbstractSASLBindRequest(SASLBindRequest saslBindRequest)
+  {
+    super(saslBindRequest);
+  }
+
+
+
+  public final byte getAuthenticationType()
+  {
+    return TYPE_AUTHENTICATION_SASL;
+  }
+
+
+
+  @Override
+  public final String getName()
+  {
+    return "".intern();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableBindRequest.java
new file mode 100644
index 0000000..b512a3a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableBindRequest.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ErrorResultException;
+
+/**
+ * An abstract unmodifiable Bind request which can be used as the basis for
+ * implementing new unmodifiable authentication methods.
+ *
+ * @param <R>
+ *          The type of Bind request.
+ */
+abstract class AbstractUnmodifiableBindRequest<R extends BindRequest> extends
+    AbstractUnmodifiableRequest<R> implements BindRequest {
+
+  AbstractUnmodifiableBindRequest(R impl) {
+    super(impl);
+  }
+
+  public BindClient createBindClient(String serverName)
+      throws ErrorResultException {
+    return impl.createBindClient(serverName);
+  }
+
+  public byte getAuthenticationType() {
+    return impl.getAuthenticationType();
+  }
+
+  public String getName() {
+    return impl.getName();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java
new file mode 100644
index 0000000..94445d4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableExtendedRequest.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+/**
+ * An abstract unmodifiable Extended request which can be used as the basis for
+ * implementing new unmodifiable Extended operations.
+ *
+ * @param <R>
+ *          The type of extended request.
+ * @param <S>
+ *          The type of result.
+ */
+abstract class
+    AbstractUnmodifiableExtendedRequest<R extends ExtendedRequest<S>,
+                                        S extends ExtendedResult>
+    extends AbstractUnmodifiableRequest<R>
+    implements ExtendedRequest<S>
+{
+  AbstractUnmodifiableExtendedRequest(R impl) {
+    super(impl);
+  }
+
+  public final String getOID() {
+    return impl.getOID();
+  }
+
+  public final ExtendedResultDecoder<S> getResultDecoder() {
+    return impl.getResultDecoder();
+  }
+
+  public final ByteString getValue() {
+    return impl.getValue();
+  }
+
+  public final boolean hasValue() {
+    return impl.hasValue();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
new file mode 100644
index 0000000..128b2c9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableRequest.java
@@ -0,0 +1,173 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.Collections;
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
+
+import com.sun.opends.sdk.util.Collections2;
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Functions;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Unmodifiable request implementation.
+ *
+ * @param <R>
+ *          The type of request.
+ */
+abstract class AbstractUnmodifiableRequest<R extends Request> implements
+    Request
+{
+
+  protected final R impl;
+
+
+
+  /**
+   * Creates a new unmodifiable request implementation.
+   *
+   * @param impl
+   *          The underlying request implementation to be made unmodifiable.
+   */
+  AbstractUnmodifiableRequest(final R impl)
+  {
+    this.impl = impl;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final R addControl(final Control control)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final <C extends Control> C getControl(
+      final ControlDecoder<C> decoder, final DecodeOptions options)
+      throws NullPointerException, DecodeException
+  {
+    Validator.ensureNotNull(decoder, options);
+
+    final List<Control> controls = impl.getControls();
+
+    // Avoid creating an iterator if possible.
+    if (controls.isEmpty())
+    {
+      return null;
+    }
+
+    for (final Control control : controls)
+    {
+      if (control.getOID().equals(decoder.getOID()))
+      {
+        // Got a match. Return a defensive copy only if necessary.
+        final C decodedControl = decoder.decodeControl(control, options);
+
+        if (decodedControl != control)
+        {
+          // This was not the original control so return it immediately.
+          return decodedControl;
+        }
+        else if (decodedControl instanceof GenericControl)
+        {
+          // Generic controls are immutable, so return it immediately.
+          return decodedControl;
+        }
+        else
+        {
+          // Re-decode to get defensive copy.
+          final GenericControl genericControl = GenericControl
+              .newControl(control);
+          return decoder.decodeControl(genericControl, options);
+        }
+      }
+    }
+
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final List<Control> getControls()
+  {
+    // We need to make all controls unmodifiable as well, which implies making
+    // defensive copies where necessary.
+    final Function<Control, Control, Void> function = new Function<Control, Control, Void>()
+    {
+
+      @Override
+      public Control apply(final Control value, final Void p)
+      {
+        // Return defensive copy.
+        return GenericControl.newControl(value);
+      }
+
+    };
+
+    final List<Control> unmodifiableControls = Collections2.transformedList(
+        impl.getControls(), function, Functions.<Control> identityFunction());
+    return Collections.unmodifiableList(unmodifiableControls);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final String toString()
+  {
+    return impl.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java
new file mode 100644
index 0000000..56f9945
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AbstractUnmodifiableSASLBindRequest.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+/**
+ * An abstract unmodifiable SASL Bind request which can be used as the basis for
+ * implementing new unmodifiable SASL authentication methods.
+ *
+ * @param <R>
+ *          The type of SASL Bind request.
+ */
+abstract class AbstractUnmodifiableSASLBindRequest
+    <R extends SASLBindRequest> extends
+    AbstractUnmodifiableBindRequest<R> implements SASLBindRequest
+{
+
+  AbstractUnmodifiableSASLBindRequest(R impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getSASLMechanism() {
+    return impl.getSASLMechanism();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequest.java
new file mode 100644
index 0000000..13ef11c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequest.java
@@ -0,0 +1,243 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.Collection;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.ldif.ChangeRecord;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+
+
+/**
+ * The Add operation allows a client to request the addition of an entry into
+ * the Directory.
+ * <p>
+ * The RDN attribute(s) may or may not be included in the Add request.
+ * NO-USER-MODIFICATION attributes such as the {@code createTimestamp} or
+ * {@code creatorsName} attributes must not be included, since the server
+ * maintains these automatically.
+ */
+public interface AddRequest extends Request, ChangeRecord, Entry
+{
+  /**
+   * {@inheritDoc}
+   */
+  <R, P> R accept(ChangeRecordVisitor<R, P> v, P p);
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean addAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean addAttribute(Attribute attribute,
+      Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AddRequest addAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AddRequest addControl(Control control) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AddRequest clearAttributes() throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean containsAttribute(Attribute attribute,
+      Collection<ByteString> missingValues) throws NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean containsAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Iterable<Attribute> getAllAttributes();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Iterable<Attribute> getAllAttributes(AttributeDescription attributeDescription)
+      throws NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Iterable<Attribute> getAllAttributes(String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Attribute getAttribute(AttributeDescription attributeDescription)
+      throws NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Attribute getAttribute(String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  int getAttributeCount();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  DN getName();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean removeAttribute(Attribute attribute,
+      Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean removeAttribute(AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AddRequest removeAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean replaceAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AddRequest replaceAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AddRequest setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AddRequest setName(String dn) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequestImpl.java
new file mode 100644
index 0000000..8115fcf
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AddRequestImpl.java
@@ -0,0 +1,371 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.Collection;
+
+import org.opends.sdk.*;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+
+
+/**
+ * Add request implementation.
+ */
+final class AddRequestImpl extends AbstractRequestImpl<AddRequest> implements
+    AddRequest
+{
+
+  private final Entry entry;
+
+
+
+  /**
+   * Creates a new add request backed by the provided entry. Modifications made
+   * to {@code entry} will be reflected in the returned add request. The
+   * returned add request supports updates to its list of controls, as well as
+   * updates to the name and attributes if the underlying entry allows.
+   *
+   * @param entry
+   *          The entry to be added.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  AddRequestImpl(final Entry entry) throws NullPointerException
+  {
+    this.entry = entry;
+  }
+
+
+
+  /**
+   * Creates a new add request that is an exact copy of the provided
+   * request.
+   *
+   * @param addRequest
+   *          The add request to be copied.
+   * @throws NullPointerException
+   *           If {@code addRequest} was {@code null} .
+   */
+  AddRequestImpl(final AddRequest addRequest) throws NullPointerException
+  {
+    super(addRequest);
+    this.entry = LinkedHashMapEntry.deepCopyOfEntry(addRequest);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
+  {
+    return v.visitChangeRecord(p, this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean addAttribute(final Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.addAttribute(attribute);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean addAttribute(final Attribute attribute,
+      final Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.addAttribute(attribute, duplicateValues);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AddRequest addAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    entry.addAttribute(attributeDescription, values);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AddRequest clearAttributes() throws UnsupportedOperationException
+  {
+    entry.clearAttributes();
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean containsAttribute(final Attribute attribute,
+      final Collection<ByteString> missingValues) throws NullPointerException
+  {
+    return entry.containsAttribute(attribute, missingValues);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean containsAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    return entry.containsAttribute(attributeDescription, values);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes()
+  {
+    return entry.getAllAttributes();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes(
+      final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    return entry.getAllAttributes(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return entry.getAllAttributes(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Attribute getAttribute(final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    return entry.getAttribute(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Attribute getAttribute(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return entry.getAttribute(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getAttributeCount()
+  {
+    return entry.getAttributeCount();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getName()
+  {
+    return entry.getName();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean removeAttribute(final Attribute attribute,
+      final Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.removeAttribute(attribute, missingValues);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean removeAttribute(final AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.removeAttribute(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AddRequest removeAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    entry.removeAttribute(attributeDescription, values);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean replaceAttribute(final Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.replaceAttribute(attribute);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AddRequest replaceAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    entry.replaceAttribute(attributeDescription, values);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AddRequest setName(final DN dn) throws UnsupportedOperationException,
+      NullPointerException
+  {
+    entry.setName(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AddRequest setName(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    entry.setName(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AddRequest(name=");
+    builder.append(getName());
+    builder.append(", attributes=");
+    builder.append(getAllAttributes());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  AddRequest getThis()
+  {
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return entry.hashCode();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object object)
+  {
+    return entry.equals(object);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequest.java
new file mode 100644
index 0000000..122ae18
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequest.java
@@ -0,0 +1,155 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The anonymous SASL bind request as defined in RFC 4505. This SASL mechanism
+ * allows a client to authenticate to the server without requiring the user to
+ * establish or otherwise disclose their identity to the server. That is, this
+ * mechanism provides an anonymous login method. This mechanism does not provide
+ * a security layer.
+ * <p>
+ * Clients should provide trace information, which has no semantic value, and
+ * can be used by administrators in order to identify the user. It should take
+ * one of two forms: an Internet email address, or an opaque string that does
+ * not contain the '@' (U+0040) character and that can be interpreted by the
+ * system administrator of the client's domain. For privacy reasons, an Internet
+ * email address or other information identifying the user should only be used
+ * with permission from the user.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4505">RFC 4505 - Anonymous Simple
+ *      Authentication and Security Layer (SASL) Mechanism </a>
+ */
+public interface AnonymousSASLBindRequest extends SASLBindRequest
+{
+
+  /**
+   * The name of the SASL mechanism that does not provide any authentication but
+   * rather uses anonymous access.
+   */
+  public static final String SASL_MECHANISM_NAME = "ANONYMOUS";
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  AnonymousSASLBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this SASL bind request
+   * as defined by the LDAP protocol, which is always {@code 0xA3}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as,
+   * which is always the empty string for SASL authentication.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  String getName();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getSASLMechanism();
+
+
+
+  /**
+   * Returns the trace information, which has no semantic value, and can be used
+   * by administrators in order to identify the user.
+   *
+   * @return The trace information, which has no semantic value, and can be used
+   *         by administrators in order to identify the user.
+   */
+  String getTraceString();
+
+
+
+  /**
+   * Sets the trace information, which has no semantic value, and can be used by
+   * administrators in order to identify the user.
+   *
+   * @param traceString
+   *          The trace information, which has no semantic value, and can be
+   *          used by administrators in order to identify the user.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this anonymous SASL request does not permit the trace
+   *           information to be set.
+   * @throws NullPointerException
+   *           If {@code traceString} was {@code null}.
+   */
+  AnonymousSASLBindRequest setTraceString(String traceString)
+      throws UnsupportedOperationException, NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java
new file mode 100644
index 0000000..913e226
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/AnonymousSASLBindRequestImpl.java
@@ -0,0 +1,147 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Anonymous SASL bind request implementation.
+ */
+final class AnonymousSASLBindRequestImpl extends
+    AbstractSASLBindRequest<AnonymousSASLBindRequest> implements
+    AnonymousSASLBindRequest
+{
+  private final static class Client extends SASLBindClientImpl
+  {
+    private Client(final AnonymousSASLBindRequestImpl initialBindRequest,
+        final String serverName)
+    {
+      super(initialBindRequest);
+      setNextSASLCredentials(ByteString.valueOf(initialBindRequest
+          .getTraceString()));
+    }
+  }
+
+
+
+  private String traceString;
+
+
+
+  AnonymousSASLBindRequestImpl(final String traceString)
+  {
+    Validator.ensureNotNull(traceString);
+    this.traceString = traceString;
+  }
+
+
+
+  /**
+   * Creates a new anonymous SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param anonymousSASLBindRequest
+   *          The anonymous SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code anonymousSASLBindRequest} was {@code null} .
+   */
+  AnonymousSASLBindRequestImpl(
+      final AnonymousSASLBindRequest anonymousSASLBindRequest)
+  {
+    super(anonymousSASLBindRequest);
+    this.traceString = anonymousSASLBindRequest.getTraceString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public BindClient createBindClient(final String serverName)
+  {
+    return new Client(this, serverName);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getSASLMechanism()
+  {
+    return SASL_MECHANISM_NAME;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getTraceString()
+  {
+    return traceString;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AnonymousSASLBindRequest setTraceString(final String traceString)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(traceString);
+    this.traceString = traceString;
+    return this;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("AnonymousSASLBindRequest(bindDN=");
+    builder.append(getName());
+    builder.append(", authentication=SASL");
+    builder.append(", saslMechanism=");
+    builder.append(getSASLMechanism());
+    builder.append(", traceString=");
+    builder.append(traceString);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClient.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClient.java
new file mode 100644
index 0000000..5738678
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClient.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ConnectionSecurityLayer;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.responses.BindResult;
+
+
+
+/**
+ * An authentication client which can be used to bind to a server. Specifically,
+ * a bind client manages the state associated with multi-stage authentication
+ * attempts and responds to any challenges returned by the server.
+ */
+public interface BindClient
+{
+  /**
+   * Disposes of any system resources or security-sensitive information that
+   * this bind client might be using. Invoking this method invalidates this
+   * instance.
+   */
+  void dispose();
+
+
+
+  /**
+   * Evaluates the provided bind result and returns {@code true} if
+   * authentication has completed successfully, or {@code false} if additional
+   * authentication steps are required (for example during a multi-stage SASL
+   * authentication attempt).
+   * <p>
+   * If additional steps are required then implementations must update their
+   * internal state based on information contained in the bind result (for
+   * example, using the server provided SASL credentials).
+   *
+   * @param result
+   *          The bind result to be evaluated.
+   * @return {@code true} if authentication has completed successfully, of
+   *         {@code false} if additional steps are required.
+   * @throws ErrorResultException
+   *           If the evaluation failed for some reason and authentication
+   *           cannot continue.
+   */
+  boolean evaluateResult(BindResult result) throws ErrorResultException;
+
+
+
+  /**
+   * Returns a connection security layer, but only if this bind client has
+   * negotiated integrity and/or privacy protection for the underlying
+   * connection. This method should only be called once authentication has
+   * completed.
+   *
+   * @return A connection security layer, or {@code null} if none was
+   *         negotiated.
+   */
+  ConnectionSecurityLayer getConnectionSecurityLayer();
+
+
+
+  /**
+   * Returns the next bind request which should be used for the next stage of
+   * authentication. Initially, this will be a copy of the original bind request
+   * used to create this bind client.
+   *
+   * @return The next bind request which should be used for the next stage of
+   *         authentication.
+   */
+  GenericBindRequest nextBindRequest();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClientImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClientImpl.java
new file mode 100644
index 0000000..b88ccc0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindClientImpl.java
@@ -0,0 +1,151 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ConnectionSecurityLayer;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.responses.BindResult;
+
+
+
+/**
+ * Bind client implementation.
+ */
+class BindClientImpl implements BindClient, ConnectionSecurityLayer
+{
+  private final GenericBindRequest nextBindRequest;
+
+
+
+  /**
+   * Creates a new abstract bind client. The next bind request will be a copy of
+   * the provided initial bind request which should be updated in subsequent
+   * bind requests forming part of this authentication.
+   *
+   * @param initialBindRequest
+   *          The initial bind request.
+   */
+  BindClientImpl(final BindRequest initialBindRequest)
+  {
+    this.nextBindRequest = new GenericBindRequestImpl(initialBindRequest
+        .getName(), initialBindRequest.getAuthenticationType(), ByteString
+        .empty(), this);
+    for (final Control control : initialBindRequest.getControls())
+    {
+      this.nextBindRequest.addControl(control);
+    }
+  }
+
+
+
+  /**
+   * Default implementation does nothing.
+   */
+  public void dispose()
+  {
+    // Do nothing.
+  }
+
+
+
+  /**
+   * Default implementation does nothing and always returns {@code true}.
+   */
+  public boolean evaluateResult(final BindResult result)
+      throws ErrorResultException
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Default implementation always returns {@code null}.
+   */
+  public ConnectionSecurityLayer getConnectionSecurityLayer()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * Returns the next bind request.
+   */
+  public final GenericBindRequest nextBindRequest()
+  {
+    return nextBindRequest;
+  }
+
+
+
+  /**
+   * Default implementation just returns the copy of the bytes.
+   */
+  public byte[] unwrap(final byte[] incoming, final int offset, final int len)
+      throws ErrorResultException
+  {
+    final byte[] copy = new byte[len];
+    System.arraycopy(incoming, offset, copy, 0, len);
+    return copy;
+  }
+
+
+
+  /**
+   * Default implementation just returns the copy of the bytes.
+   */
+  public byte[] wrap(final byte[] outgoing, final int offset, final int len)
+      throws ErrorResultException
+  {
+    final byte[] copy = new byte[len];
+    System.arraycopy(outgoing, offset, copy, 0, len);
+    return copy;
+  }
+
+
+
+  /**
+   * Sets the authentication value to be used in the next bind request.
+   *
+   * @param authenticationValue
+   *          The authentication value to be used in the next bind request.
+   * @return A reference to this bind client.
+   */
+  final BindClient setNextAuthenticationValue(
+      final ByteString authenticationValue)
+  {
+    nextBindRequest.setAuthenticationValue(authenticationValue);
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindRequest.java
new file mode 100644
index 0000000..5d38914
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/BindRequest.java
@@ -0,0 +1,114 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The Bind operation allows authentication information to be exchanged between
+ * the client and server. The Bind operation should be thought of as the
+ * "authenticate" operation.
+ */
+public interface BindRequest extends Request
+{
+  /**
+   * {@inheritDoc}
+   */
+  BindRequest addControl(Control control) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Creates a new bind client which can be used to perform the authentication
+   * process. This method is called by protocol implementations and is not
+   * intended for use by applications.
+   *
+   * @param serverName
+   *          The non-null fully-qualified host name of the server to
+   *          authenticate to.
+   * @return The new bind client.
+   * @throws ErrorResultException
+   *           If an error occurred while creating the bind client context.
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this generic bind
+   * request as defined by the LDAP protocol. Note that value {@code 0x80} is
+   * reserved for simple authentication and {@code 0xA3} is reserved for SASL
+   * authentication.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as.
+   * The name may be empty (but never {@code null}) when used for of anonymous
+   * binds, or when using SASL authentication. The server shall not dereference
+   * any aliases in locating the named object.
+   * <p>
+   * The LDAP protocol defines the Bind name to be a distinguished name, however
+   * some LDAP implementations have relaxed this constraint and allow other
+   * identities to be used, such as the user's email address.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  String getName();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java
new file mode 100644
index 0000000..a466c92
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequest.java
@@ -0,0 +1,201 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The CRAM-MD5 SASL bind request as defined in draft-ietf-sasl-crammd5. This
+ * SASL mechanism allows a client to perform a simple challenge-response
+ * authentication method, using a keyed MD5 digest. This mechanism does not
+ * provide a security layer.
+ * <p>
+ * The CRAM-MD5 mechanism is intended to have limited use on the Internet. The
+ * mechanism offers inadequate protection against common attacks against
+ * application-level protocols and is prone to interoperability problems.
+ * <p>
+ * The authentication identity is specified using an authorization ID, or
+ * {@code authzId}, as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see <a
+ *      href="http://tools.ietf.org/html/draft-ietf-sasl-crammd5">draft-ietf-sasl-crammd5
+ *      - The CRAM-MD5 SASL Mechanism </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public interface CRAMMD5SASLBindRequest extends SASLBindRequest
+{
+
+  /**
+   * The name of the SASL mechanism based on CRAM-MD5 authentication.
+   */
+  public static final String SASL_MECHANISM_NAME = "CRAM-MD5";
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  CRAMMD5SASLBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication ID of the user. The authentication ID usually
+   * has the form "dn:" immediately followed by the distinguished name of the
+   * user, or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authentication ID of the user.
+   */
+  String getAuthenticationID();
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this SASL bind request
+   * as defined by the LDAP protocol, which is always {@code 0xA3}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as,
+   * which is always the empty string for SASL authentication.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  String getName();
+
+
+
+  /**
+   * Returns the password of the user that the client wishes to bind as.
+   *
+   * @return The password of the user that the client wishes to bind as.
+   */
+  ByteString getPassword();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getSASLMechanism();
+
+
+
+  /**
+   * Sets the authentication ID of the user. The authentication ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user.
+   * @return This bind request
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authentication ID to be
+   *           set..
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authenticationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   * @throws NullPointerException
+   *           If {@code authenticationID} was {@code null}.
+   */
+  CRAMMD5SASLBindRequest setAuthenticationID(String authenticationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as, which
+   *          may be empty.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  CRAMMD5SASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as. The
+   * password will be converted to a UTF-8 octet string.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  CRAMMD5SASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java
new file mode 100644
index 0000000..afd03da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestImpl.java
@@ -0,0 +1,287 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.Responses;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * CRAM-MD5 SASL bind request implementation.
+ */
+final class CRAMMD5SASLBindRequestImpl extends
+    AbstractSASLBindRequest<CRAMMD5SASLBindRequest> implements
+    CRAMMD5SASLBindRequest
+{
+  private final static class Client extends SASLBindClientImpl
+  {
+    private final SaslClient saslClient;
+    private final String authenticationID;
+    private final ByteString password;
+
+
+
+    private Client(final CRAMMD5SASLBindRequestImpl initialBindRequest,
+        final String serverName) throws ErrorResultException
+    {
+      super(initialBindRequest);
+
+      this.authenticationID = initialBindRequest.getAuthenticationID();
+      this.password = initialBindRequest.getPassword();
+
+      try
+      {
+        saslClient = Sasl.createSaslClient(
+            new String[] { SASL_MECHANISM_NAME }, null, SASL_DEFAULT_PROTOCOL,
+            serverName, null, this);
+        if (saslClient.hasInitialResponse())
+        {
+          setNextSASLCredentials(saslClient.evaluateChallenge(new byte[0]));
+        }
+        else
+        {
+          setNextSASLCredentials((ByteString) null);
+        }
+      }
+      catch (final SaslException e)
+      {
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e));
+      }
+    }
+
+
+
+    @Override
+    public void dispose()
+    {
+      try
+      {
+        saslClient.dispose();
+      }
+      catch (final SaslException ignored)
+      {
+        // Ignore the SASL exception.
+      }
+    }
+
+
+
+    @Override
+    public boolean evaluateResult(final BindResult result)
+        throws ErrorResultException
+    {
+      try
+      {
+        setNextSASLCredentials(saslClient.evaluateChallenge(result
+            .getServerSASLCredentials() == null ? new byte[0] :
+            result.getServerSASLCredentials().toByteArray()));
+        return saslClient.isComplete();
+      }
+      catch (final SaslException e)
+      {
+        // FIXME: I18N need to have a better error message.
+        // FIXME: Is this the best result code?
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
+            "An error occurred during multi-stage authentication")
+            .setCause(e));
+      }
+    }
+
+
+
+    @Override
+    void handle(final NameCallback callback)
+        throws UnsupportedCallbackException
+    {
+      callback.setName(authenticationID);
+    }
+
+
+
+    @Override
+    void handle(final PasswordCallback callback)
+        throws UnsupportedCallbackException
+    {
+      callback.setPassword(password.toString().toCharArray());
+    }
+  }
+
+
+
+  private String authenticationID;
+
+  private ByteString password;
+
+
+
+  CRAMMD5SASLBindRequestImpl(final String authenticationID,
+      final ByteString password)
+  {
+    Validator.ensureNotNull(authenticationID, password);
+    this.authenticationID = authenticationID;
+    this.password = password;
+  }
+
+
+
+  /**
+   * Creates a new CRAM MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param cramMD5SASLBindRequest
+   *          The CRAM MD5 SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code cramMD5SASLBindRequest} was {@code null} .
+   */
+  CRAMMD5SASLBindRequestImpl(
+      final CRAMMD5SASLBindRequest cramMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    super(cramMD5SASLBindRequest);
+    this.authenticationID = cramMD5SASLBindRequest.getAuthenticationID();
+    this.password = cramMD5SASLBindRequest.getPassword();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public BindClient createBindClient(final String serverName)
+      throws ErrorResultException
+  {
+    return new Client(this, serverName);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getAuthenticationID()
+  {
+    return authenticationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getPassword()
+  {
+    return password;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getSASLMechanism()
+  {
+    return SASL_MECHANISM_NAME;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CRAMMD5SASLBindRequest setAuthenticationID(
+      final String authenticationID) throws NullPointerException
+  {
+    Validator.ensureNotNull(authenticationID);
+    this.authenticationID = authenticationID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CRAMMD5SASLBindRequest setPassword(final ByteString password)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = password;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CRAMMD5SASLBindRequest setPassword(final char[] password)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = ByteString.valueOf(password);
+    return this;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("CRAMMD5SASLBindRequest(bindDN=");
+    builder.append(getName());
+    builder.append(", authentication=SASL");
+    builder.append(", saslMechanism=");
+    builder.append(getSASLMechanism());
+    builder.append(", authenticationID=");
+    builder.append(authenticationID);
+    builder.append(", password=");
+    builder.append(password);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequest.java
new file mode 100644
index 0000000..e8468a2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequest.java
@@ -0,0 +1,143 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+
+
+/**
+ * The cancel extended request as defined in RFC 3909. This operation is similar
+ * to the abandon operation, except that it has a response and also requires the
+ * abandoned operation to return a response indicating it was canceled. This
+ * operation should be used instead of the abandon operation when the client
+ * needs an indication of the outcome. This operation may be used to cancel both
+ * interrogation and update operations.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc3909">RFC 3909 - Lightweight
+ *      Directory Access Protocol (LDAP) Cancel Operation </a>
+ */
+public interface CancelExtendedRequest extends ExtendedRequest<ExtendedResult>
+{
+
+  /**
+   * The OID for the cancel extended operation request.
+   */
+  public static final String OID = "1.3.6.1.1.8";
+
+  /**
+   * A decoder which can be used to decode cancel extended operation requests.
+   */
+  public static final ExtendedRequestDecoder<CancelExtendedRequest,
+                                             ExtendedResult> DECODER =
+    new CancelExtendedRequestImpl.RequestDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  CancelExtendedRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * Returns the request ID of the request to be abandoned.
+   *
+   * @return The request ID of the request to be abandoned.
+   */
+  int getRequestID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResultDecoder<ExtendedResult> getResultDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * Sets the request ID of the request to be abandoned.
+   *
+   * @param id
+   *          The request ID of the request to be abandoned.
+   * @return This abandon request.
+   * @throws UnsupportedOperationException
+   *           If this abandon request does not permit the request ID to be set.
+   */
+  CancelExtendedRequest setRequestID(int id)
+      throws UnsupportedOperationException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequestImpl.java
new file mode 100644
index 0000000..11cbd15
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CancelExtendedRequestImpl.java
@@ -0,0 +1,249 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_EXTOP_CANCEL_CANNOT_DECODE_REQUEST_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_EXTOP_CANCEL_NO_REQUEST_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.responses.AbstractExtendedResultDecoder;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+import org.opends.sdk.responses.Responses;
+
+
+
+/**
+ * Cancel extended request implementation.
+ */
+final class CancelExtendedRequestImpl extends
+    AbstractExtendedRequest<CancelExtendedRequest, ExtendedResult> implements
+    CancelExtendedRequest
+{
+  static final class RequestDecoder implements
+      ExtendedRequestDecoder<CancelExtendedRequest, ExtendedResult>
+  {
+    public CancelExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      final ByteString requestValue = request.getValue();
+      if ((requestValue == null) || (requestValue.length() <= 0))
+      {
+        throw DecodeException.error(ERR_EXTOP_CANCEL_NO_REQUEST_VALUE.get());
+      }
+
+      try
+      {
+        final ASN1Reader reader = ASN1.getReader(requestValue);
+        reader.readStartSequence();
+        final int idToCancel = (int) reader.readInteger();
+        reader.readEndSequence();
+
+        final CancelExtendedRequest newRequest = new CancelExtendedRequestImpl(
+            idToCancel);
+
+        for (final Control control : request.getControls())
+        {
+          newRequest.addControl(control);
+        }
+
+        return newRequest;
+      }
+      catch (final IOException e)
+      {
+        final LocalizableMessage message = ERR_EXTOP_CANCEL_CANNOT_DECODE_REQUEST_VALUE
+            .get(getExceptionMessage(e));
+        throw DecodeException.error(message, e);
+      }
+    }
+  }
+
+
+
+  private static final class ResultDecoder extends
+      AbstractExtendedResultDecoder<ExtendedResult>
+  {
+    public ExtendedResult newExtendedErrorResult(final ResultCode resultCode,
+        final String matchedDN, final String diagnosticMessage)
+    {
+      return Responses.newGenericExtendedResult(resultCode).setMatchedDN(
+          matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public ExtendedResult decodeExtendedResult(final ExtendedResult result,
+        final DecodeOptions options) throws DecodeException
+    {
+      // TODO: Should we check to make sure OID and value is null?
+      return result;
+    }
+  }
+
+
+
+  private int requestID;
+
+  // No need to expose this.
+  private static final ExtendedResultDecoder<ExtendedResult> RESULT_DECODER = new ResultDecoder();
+
+
+
+  // Instantiation via factory.
+  CancelExtendedRequestImpl(final int requestID)
+  {
+    this.requestID = requestID;
+  }
+
+
+
+  /**
+   * Creates a new cancel extended request that is an exact copy of the provided
+   * request.
+   *
+   * @param cancelExtendedRequest
+   *          The cancel extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code cancelExtendedRequest} was {@code null} .
+   */
+  CancelExtendedRequestImpl(final CancelExtendedRequest cancelExtendedRequest)
+      throws NullPointerException
+  {
+    super(cancelExtendedRequest);
+    this.requestID = cancelExtendedRequest.getRequestID();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getRequestID()
+  {
+    return requestID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<ExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder(6);
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+
+    try
+    {
+      writer.writeStartSequence();
+      writer.writeInteger(requestID);
+      writer.writeEndSequence();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+
+    return buffer.toByteString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CancelExtendedRequest setRequestID(final int id)
+  {
+    this.requestID = id;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("CancelExtendedRequest(requestName=");
+    builder.append(getOID());
+    builder.append(", requestID=");
+    builder.append(requestID);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequest.java
new file mode 100644
index 0000000..c99b49a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequest.java
@@ -0,0 +1,222 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The Compare operation allows a client to compare an assertion value with the
+ * values of a particular attribute in a particular entry in the Directory.
+ * <p>
+ * Note that some directory systems may establish access controls that permit
+ * the values of certain attributes (such as {@code userPassword} ) to be
+ * compared but not interrogated by other means.
+ */
+public interface CompareRequest extends Request
+{
+  /**
+   * {@inheritDoc}
+   */
+  CompareRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Returns the assertion value to be compared.
+   *
+   * @return The assertion value.
+   */
+  ByteString getAssertionValue();
+
+
+
+  /**
+   * Returns the assertion value to be compared decoded as a UTF-8 string.
+   *
+   * @return The assertion value decoded as a UTF-8 string.
+   */
+  String getAssertionValueAsString();
+
+
+
+  /**
+   * Returns the name of the attribute to be compared.
+   *
+   * @return The name of the attribute.
+   */
+  AttributeDescription getAttributeDescription();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the distinguished name of the entry to be compared. The server
+   * shall not dereference any aliases in locating the entry to be compared.
+   *
+   * @return The distinguished name of the entry.
+   */
+  DN getName();
+
+
+
+  /**
+   * Sets the assertion value to be compared.
+   *
+   * @param value
+   *          The assertion value to be compared.
+   * @return This compare request.
+   * @throws UnsupportedOperationException
+   *           If this compare request does not permit the assertion value to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code value} was {@code null}.
+   */
+  CompareRequest setAssertionValue(ByteString value)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the assertion value to be compared.
+   * <p>
+   * If the assertion value is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param value
+   *          The assertion value to be compared.
+   * @return This compare request.
+   * @throws UnsupportedOperationException
+   *           If this compare request does not permit the assertion value to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code value} was {@code null}.
+   */
+  CompareRequest setAssertionValue(Object value)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the name of the attribute to be compared.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be compared.
+   * @return This compare request.
+   * @throws UnsupportedOperationException
+   *           If this compare request does not permit the attribute description
+   *           to be set.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  CompareRequest setAttributeDescription(
+      AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the name of the attribute to be compared.
+   *
+   * @param attributeDescription
+   *          The name of the attribute to be compared.
+   * @return This compare request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           default schema.
+   * @throws UnsupportedOperationException
+   *           If this compare request does not permit the attribute description
+   *           to be set.
+   * @throws NullPointerException
+   *           If {@code attributeDescription} was {@code null}.
+   */
+  CompareRequest setAttributeDescription(String attributeDescription)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be compared. The server shall
+   * not dereference any aliases in locating the entry to be compared.
+   *
+   * @param dn
+   *          The distinguished name of the entry to be compared.
+   * @return This compare request.
+   * @throws UnsupportedOperationException
+   *           If this compare request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  CompareRequest setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be compared. The server shall
+   * not dereference any aliases in locating the entry to be compared.
+   *
+   * @param dn
+   *          The distinguished name of the entry to be compared.
+   * @return This compare request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this compare request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  CompareRequest setName(String dn) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequestImpl.java
new file mode 100644
index 0000000..d9bb0b2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/CompareRequestImpl.java
@@ -0,0 +1,251 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.AttributeDescription;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Compare request implementation.
+ */
+final class CompareRequestImpl extends AbstractRequestImpl<CompareRequest>
+    implements CompareRequest
+{
+
+  private AttributeDescription attributeDescription;
+
+  private ByteString assertionValue;
+
+  private DN name;
+
+
+
+  /**
+   * Creates a new compare request using the provided distinguished name,
+   * attribute name, and assertion value.
+   *
+   * @param name
+   *          The distinguished name of the entry to be compared.
+   * @param attributeDescription
+   *          The name of the attribute to be compared.
+   * @param assertionValue
+   *          The assertion value to be compared.
+   * @throws NullPointerException
+   *           If {@code name}, {@code attributeDescription}, or {@code
+   *           assertionValue} was {@code null}.
+   */
+  CompareRequestImpl(final DN name,
+      final AttributeDescription attributeDescription,
+      final ByteString assertionValue) throws NullPointerException
+  {
+    this.name = name;
+    this.attributeDescription = attributeDescription;
+    this.assertionValue = assertionValue;
+  }
+
+
+
+  /**
+   * Creates a new compare request that is an exact copy of the provided
+   * request.
+   *
+   * @param compareRequest
+   *          The compare request to be copied.
+   * @throws NullPointerException
+   *           If {@code compareRequest} was {@code null} .
+   */
+  CompareRequestImpl(final CompareRequest compareRequest)
+      throws NullPointerException
+  {
+    super(compareRequest);
+    this.name = compareRequest.getName();
+    this.attributeDescription = compareRequest.getAttributeDescription();
+    this.assertionValue = compareRequest.getAssertionValue();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getAssertionValue()
+  {
+    return assertionValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getAssertionValueAsString()
+  {
+    return assertionValue.toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public AttributeDescription getAttributeDescription()
+  {
+    return attributeDescription;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareRequest setAssertionValue(final ByteString value)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(value);
+    this.assertionValue = value;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareRequest setAssertionValue(final Object value)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(value);
+    this.assertionValue = ByteString.valueOf(value);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareRequest setAttributeDescription(
+      final AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription);
+    this.attributeDescription = attributeDescription;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareRequest setAttributeDescription(
+      final String attributeDescription)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(attributeDescription);
+    this.attributeDescription = AttributeDescription
+        .valueOf(attributeDescription);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareRequest setName(final DN dn)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = dn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public CompareRequest setName(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = DN.valueOf(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("CompareRequest(name=");
+    builder.append(getName());
+    builder.append(", attributeDescription=");
+    builder.append(getAttributeDescription());
+    builder.append(", assertionValue=");
+    builder.append(getAssertionValueAsString());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  CompareRequest getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequest.java
new file mode 100644
index 0000000..74aa974
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequest.java
@@ -0,0 +1,131 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DN;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.ldif.ChangeRecord;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+
+
+/**
+ * The Delete operation allows a client to request the removal of an entry from
+ * the Directory.
+ * <p>
+ * Only leaf entries (those with no subordinate entries) can be deleted with
+ * this operation. However, addition of the {@code SubtreeDeleteControl} permits
+ * whole sub-trees to be deleted using a single Delete request.
+ */
+public interface DeleteRequest extends Request, ChangeRecord
+{
+  /**
+   * {@inheritDoc}
+   */
+  <R, P> R accept(ChangeRecordVisitor<R, P> v, P p);
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  DeleteRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the distinguished name of the entry to be deleted. The server shall
+   * not dereference any aliases in locating the entry to be deleted.
+   *
+   * @return The distinguished name of the entry.
+   */
+  DN getName();
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be deleted. The server shall
+   * not dereference any aliases in locating the entry to be deleted.
+   *
+   * @param dn
+   *          The distinguished name of the entry to be deleted.
+   * @return This delete request.
+   * @throws UnsupportedOperationException
+   *           If this delete request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  DeleteRequest setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be deleted. The server shall
+   * not dereference any aliases in locating the entry to be deleted.
+   *
+   * @param dn
+   *          The distinguished name of the entry to be deleted.
+   * @return This delete request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this delete request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  DeleteRequest setName(String dn) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequestImpl.java
new file mode 100644
index 0000000..11d3842
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DeleteRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Delete request implementation.
+ */
+final class DeleteRequestImpl extends AbstractRequestImpl<DeleteRequest>
+    implements DeleteRequest
+{
+  private DN name;
+
+
+
+  /**
+   * Creates a new delete request using the provided distinguished name.
+   *
+   * @param name
+   *          The distinguished name of the entry to be deleted.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  DeleteRequestImpl(final DN name) throws NullPointerException
+  {
+    this.name = name;
+  }
+
+
+
+  /**
+   * Creates a new delete request that is an exact copy of the provided
+   * request.
+   *
+   * @param deleteRequest
+   *          The add request to be copied.
+   * @throws NullPointerException
+   *           If {@code addRequest} was {@code null} .
+   */
+  DeleteRequestImpl(final DeleteRequest deleteRequest)
+      throws NullPointerException
+  {
+    super(deleteRequest);
+    this.name = deleteRequest.getName();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
+  {
+    return v.visitChangeRecord(p, this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DeleteRequest setName(final DN dn)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = dn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DeleteRequest setName(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = DN.valueOf(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("DeleteRequest(name=");
+    builder.append(getName());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  DeleteRequest getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequest.java
new file mode 100644
index 0000000..eea5692
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequest.java
@@ -0,0 +1,546 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+import java.util.Map;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The DIGEST-MD5 SASL bind request as defined in RFC 2831. This SASL mechanism
+ * allows a client to perform a challenge-response authentication method,
+ * similar to HTTP Digest Access Authentication. This mechanism can be used to
+ * negotiate integrity and/or privacy protection for the underlying connection.
+ * <p>
+ * Compared to CRAM-MD5, DIGEST-MD5 prevents chosen plain-text attacks, and
+ * permits the use of third party authentication servers, mutual authentication,
+ * and optimized re-authentication if a client has recently authenticated to a
+ * server.
+ * <p>
+ * The authentication and optional authorization identity is specified using an
+ * authorization ID, or {@code authzId}, as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc2831">RFC 2831 - Using Digest
+ *      Authentication as a SASL Mechanism </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public interface DigestMD5SASLBindRequest extends SASLBindRequest
+{
+
+  /**
+   * The name of the SASL mechanism based on DIGEST-MD5 authentication.
+   */
+  public static final String SASL_MECHANISM_NAME = "DIGEST-MD5";
+
+  /**
+   * Indicates that the client will accept authentication only. More
+   * specifically, the underlying connection will not be protected using
+   * integrity protection or encryption, unless previously established using
+   * SSL/TLS. This is the default if no QOP option is present in the bind
+   * request.
+   */
+  public static final String QOP_AUTH = "auth";
+
+  /**
+   * Indicates that the client will accept authentication with connection
+   * integrity protection. More specifically, the underlying connection will not
+   * be encrypted, unless previously established using SSL/TLS.
+   */
+  public static final String QOP_AUTH_INT = "auth-int";
+
+  /**
+   * Indicates that the client will accept authentication with connection
+   * integrity protection and encryption.
+   */
+  public static final String QOP_AUTH_CONF = "auth-conf";
+
+  /**
+   * Indicates that the client will accept connection encryption using the high
+   * strength triple-DES cipher.
+   */
+  public static final String CIPHER_3DES = "3des";
+
+  /**
+   * Indicates that the client will accept connection encryption using the high
+   * strength 128-bit RC4 cipher.
+   */
+  public static final String CIPHER_RC4_128 = "rc4";
+
+  /**
+   * Indicates that the client will accept connection encryption using the
+   * medium strength DES cipher.
+   */
+  public static final String CIPHER_DES = "des";
+
+  /**
+   * Indicates that the client will accept connection encryption using the
+   * medium strength 56-bit RC4 cipher.
+   */
+  public static final String CIPHER_RC4_56 = "rc4-56";
+
+  /**
+   * Indicates that the client will accept connection encryption using the low
+   * strength 40-bit RC4 cipher.
+   */
+  public static final String CIPHER_RC4_40 = "rc4-40";
+
+  /**
+   * Indicates that the client will accept connection encryption using the
+   * strongest supported cipher, as long as the cipher is considered to be high
+   * strength.
+   */
+  public static final String CIPHER_HIGH = "high";
+
+  /**
+   * Indicates that the client will accept connection encryption using the
+   * strongest supported cipher, as long as the cipher is considered to be high
+   * or medium strength.
+   */
+  public static final String CIPHER_MEDIUM = "medium";
+
+  /**
+   * Indicates that the client will accept connection encryption using the
+   * strongest supported cipher, even if the strongest cipher is considered to
+   * be medium or low strength.
+   */
+  public static final String CIPHER_LOW = "low";
+
+
+
+  /**
+   * Adds the provided additional authentication parameter to the list of
+   * parameters to be passed to the underlying mechanism implementation. This
+   * method is provided in order to allow for future extensions.
+   *
+   * @param name
+   *          The name of the additional authentication parameter.
+   * @param value
+   *          The value of the additional authentication parameter.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit additional authentication
+   *           parameters to be added.
+   * @throws NullPointerException
+   *           If {@code name} or {@code value} was {@code null}.
+   */
+  DigestMD5SASLBindRequest addAdditionalAuthParam(String name, String value)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  DigestMD5SASLBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Adds the provided quality of protection (QOP) values to the ordered list of
+   * QOP values that the client is willing to accept. The order of the list
+   * specifies the preference order, high to low. Authentication will fail if no
+   * QOP values are recognized or accepted by the server.
+   * <p>
+   * By default the client will accept {@link #QOP_AUTH AUTH}.
+   *
+   * @param qopValues
+   *          The quality of protection values that the client is willing to
+   *          accept.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit QOP values to be added.
+   * @throws NullPointerException
+   *           If {@code qopValues} was {@code null}.
+   * @see #QOP_AUTH
+   * @see #QOP_AUTH_INT
+   * @see #QOP_AUTH_CONF
+   */
+  DigestMD5SASLBindRequest addQOP(String... qopValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns a map containing the provided additional authentication parameters
+   * to be passed to the underlying mechanism implementation. This method is
+   * provided in order to allow for future extensions.
+   *
+   * @return A map containing the provided additional authentication parameters
+   *         to be passed to the underlying mechanism implementation.
+   */
+  Map<String, String> getAdditionalAuthParams();
+
+
+
+  /**
+   * Returns the authentication ID of the user. The authentication ID usually
+   * has the form "dn:" immediately followed by the distinguished name of the
+   * user, or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authentication ID of the user.
+   */
+  String getAuthenticationID();
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this SASL bind request
+   * as defined by the LDAP protocol, which is always {@code 0xA3}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  @Override
+  byte getAuthenticationType();
+
+
+
+  /**
+   * Returns the optional authorization ID of the user which represents an
+   * alternate authorization identity which should be used for subsequent
+   * operations performed on the connection. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authorization ID of the user, which may be {@code null}.
+   */
+  String getAuthorizationID();
+
+
+
+  /**
+   * Returns the cipher name or strength that the client is willing to use when
+   * connection encryption quality of protection, {@link #QOP_AUTH_CONF
+   * AUTH-CONF}, is requested.
+   * <p>
+   * By default the client will accept connection encryption using the strongest
+   * supported cipher, even if the strongest cipher is considered to be medium
+   * or low strength. This is equivalent to {@link #CIPHER_LOW}.
+   *
+   * @return The cipher that the client is willing to use if connection
+   *         encryption QOP is negotiated. May be {@code null}, indicating that
+   *         the default cipher should be used.
+   */
+  String getCipher();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the maximum size of the receive buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * send buffer size. The default size is 65536.
+   *
+   * @return The maximum size of the receive buffer in bytes.
+   */
+  int getMaxReceiveBufferSize();
+
+
+
+  /**
+   * Returns the maximum size of the send buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * receive buffer size. The default size is 65536.
+   *
+   * @return The maximum size of the send buffer in bytes.
+   */
+  int getMaxSendBufferSize();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as,
+   * which is always the empty string for SASL authentication.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  @Override
+  String getName();
+
+
+
+  /**
+   * Returns the password of the user that the client wishes to bind as.
+   *
+   * @return The password of the user that the client wishes to bind as.
+   */
+  ByteString getPassword();
+
+
+
+  /**
+   * Returns the ordered list of quality of protection (QOP) values that the
+   * client is willing to accept. The order of the list specifies the preference
+   * order, high to low. Authentication will fail if no QOP values are
+   * recognized or accepted by the server.
+   * <p>
+   * By default the client will accept {@link #QOP_AUTH AUTH}.
+   *
+   * @return The list of quality of protection values that the client is willing
+   *         to accept. The returned list may be empty indicating that the
+   *         default QOP will be accepted.
+   */
+  List<String> getQOPs();
+
+
+
+  /**
+   * Returns the optional realm containing the user's account.
+   *
+   * @return The name of the realm containing the user's account, which may be
+   *         {@code null}.
+   */
+  String getRealm();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  String getSASLMechanism();
+
+
+
+  /**
+   * Returns {@code true} if the server must authenticate to the client. The
+   * default is {@code false}.
+   *
+   * @return {@code true} if the server must authenticate to the client.
+   */
+  boolean isServerAuth();
+
+
+
+  /**
+   * Sets the authentication ID of the user. The authentication ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user.
+   * @return This bind request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authenticationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authentication ID to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code authenticationID} was {@code null}.
+   */
+  DigestMD5SASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the optional authorization ID of the user which represents an
+   * alternate authorization identity which should be used for subsequent
+   * operations performed on the connection. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authorizationID
+   *          The authorization ID of the user, which may be {@code null}.
+   * @return This bind request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authorization ID to be
+   *           set.
+   */
+  DigestMD5SASLBindRequest setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the cipher name or strength that the client is willing to use when
+   * connection encryption quality of protection, {@link #QOP_AUTH_CONF
+   * AUTH-CONF}, is requested.
+   * <p>
+   * By default the client will accept connection encryption using the strongest
+   * supported cipher, even if the strongest cipher is considered to be medium
+   * or low strength. This is equivalent to {@link #CIPHER_LOW}.
+   *
+   * @param cipher
+   *          The cipher that the client is willing to use if connection
+   *          encryption QOP is negotiated. May be {@code null}, indicating that
+   *          the default cipher should be used.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the cipher name or strength
+   *           to be set.
+   * @see #QOP_AUTH_CONF
+   * @see #CIPHER_3DES
+   * @see #CIPHER_RC4_128
+   * @see #CIPHER_DES
+   * @see #CIPHER_RC4_56
+   * @see #CIPHER_RC4_40
+   * @see #CIPHER_HIGH
+   * @see #CIPHER_MEDIUM
+   * @see #CIPHER_LOW
+   */
+  DigestMD5SASLBindRequest setCipher(String cipher)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the maximum size of the receive buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * send buffer size. The default size is 65536.
+   *
+   * @param size
+   *          The maximum size of the receive buffer in bytes.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the buffer size to be set.
+   */
+  DigestMD5SASLBindRequest setMaxReceiveBufferSize(int size)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the maximum size of the send buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * receive buffer size. The default size is 65536.
+   *
+   * @param size
+   *          The maximum size of the send buffer in bytes.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the buffer size to be set.
+   */
+  DigestMD5SASLBindRequest setMaxSendBufferSize(int size)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as, which
+   *          may be empty.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  DigestMD5SASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as. The
+   * password will be converted to a UTF-8 octet string.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  DigestMD5SASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the optional realm containing the user's account.
+   *
+   * @param realm
+   *          The name of the realm containing the user's account, which may be
+   *          {@code null}.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the realm to be set.
+   * @throws NullPointerException
+   *           If {@code realm} was {@code null}.
+   */
+  DigestMD5SASLBindRequest setRealm(String realm)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Specifies whether or not the server must authenticate to the client. The
+   * default is {@code false}.
+   *
+   * @param serverAuth
+   *          {@code true} if the server must authenticate to the client or
+   *          {@code false} otherwise.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit server auth to be set.
+   */
+  DigestMD5SASLBindRequest setServerAuth(boolean serverAuth)
+      throws UnsupportedOperationException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java
new file mode 100644
index 0000000..8873c6b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/DigestMD5SASLBindRequestImpl.java
@@ -0,0 +1,656 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_SASL_PROTOCOL_ERROR;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+import static com.sun.opends.sdk.util.StaticUtils.joinCollection;
+
+import java.util.*;
+
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.RealmCallback;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.Responses;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Digest-MD5 SASL bind request implementation.
+ */
+final class DigestMD5SASLBindRequestImpl extends
+    AbstractSASLBindRequest<DigestMD5SASLBindRequest> implements
+    DigestMD5SASLBindRequest
+{
+  private final static class Client extends SASLBindClientImpl
+  {
+    private final SaslClient saslClient;
+    private final String authenticationID;
+    private final ByteString password;
+    private final String realm;
+
+
+
+    private Client(final DigestMD5SASLBindRequestImpl initialBindRequest,
+        final String serverName) throws ErrorResultException
+    {
+      super(initialBindRequest);
+
+      this.authenticationID = initialBindRequest.getAuthenticationID();
+      this.password = initialBindRequest.getPassword();
+      this.realm = initialBindRequest.getRealm();
+
+      // Create property map containing all the parameters.
+      final Map<String, String> props = new HashMap<String, String>();
+
+      final List<String> qopValues = initialBindRequest.getQOPs();
+      if (!qopValues.isEmpty())
+      {
+        props.put(Sasl.QOP, joinCollection(qopValues, ","));
+      }
+
+      final String cipher = initialBindRequest.getCipher();
+      if (cipher != null)
+      {
+        if (cipher.equalsIgnoreCase(CIPHER_LOW))
+        {
+          props.put(Sasl.STRENGTH, "high,medium,low");
+        }
+        else if (cipher.equalsIgnoreCase(CIPHER_MEDIUM))
+        {
+          props.put(Sasl.STRENGTH, "high,medium");
+        }
+        else if (cipher.equalsIgnoreCase(CIPHER_HIGH))
+        {
+          props.put(Sasl.STRENGTH, "high");
+        }
+        else
+        {
+          // Default strength allows all ciphers, so specifying a single cipher
+          // cannot be incompatible with the strength.
+          props.put("com.sun.security.sasl.digest.cipher", cipher);
+        }
+      }
+
+      final Boolean serverAuth = initialBindRequest.isServerAuth();
+      if (serverAuth != null)
+      {
+        props.put(Sasl.SERVER_AUTH, String.valueOf(serverAuth));
+      }
+
+      Integer size = initialBindRequest.getMaxReceiveBufferSize();
+      if (size != null)
+      {
+        props.put(Sasl.MAX_BUFFER, String.valueOf(size));
+      }
+
+      size = initialBindRequest.getMaxSendBufferSize();
+      if (size != null)
+      {
+        props.put("javax.security.sasl.sendmaxbuffer", String.valueOf(size));
+      }
+
+      for (final Map.Entry<String, String> e : initialBindRequest
+          .getAdditionalAuthParams().entrySet())
+      {
+        props.put(e.getKey(), e.getValue());
+      }
+
+      // Now create the client.
+      try
+      {
+        saslClient = Sasl.createSaslClient(
+            new String[] { SASL_MECHANISM_NAME },
+            initialBindRequest.getAuthorizationID(), SASL_DEFAULT_PROTOCOL,
+            serverName, props, this);
+        if (saslClient.hasInitialResponse())
+        {
+          setNextSASLCredentials(saslClient.evaluateChallenge(new byte[0]));
+        }
+        else
+        {
+          setNextSASLCredentials((ByteString) null);
+        }
+      }
+      catch (final SaslException e)
+      {
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e));
+      }
+    }
+
+
+
+    @Override
+    public void dispose()
+    {
+      try
+      {
+        saslClient.dispose();
+      }
+      catch (final SaslException ignored)
+      {
+        // Ignore the SASL exception.
+      }
+    }
+
+
+
+    @Override
+    public boolean evaluateResult(final BindResult result)
+        throws ErrorResultException
+    {
+      try
+      {
+        setNextSASLCredentials(saslClient.evaluateChallenge(result
+            .getServerSASLCredentials() == null ? new byte[0] : result
+            .getServerSASLCredentials().toByteArray()));
+        return saslClient.isComplete();
+      }
+      catch (final SaslException e)
+      {
+        // FIXME: I18N need to have a better error message.
+        // FIXME: Is this the best result code?
+        throw ErrorResultException.wrap(Responses
+            .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+            .setDiagnosticMessage(
+                "An error occurred during multi-stage authentication")
+            .setCause(e));
+      }
+    }
+
+
+
+    @Override
+    public ConnectionSecurityLayer getConnectionSecurityLayer()
+    {
+      final String qop = (String) saslClient.getNegotiatedProperty(Sasl.QOP);
+      if (qop.equalsIgnoreCase("auth-int") || qop.equalsIgnoreCase("auth-conf"))
+      {
+        return this;
+      }
+      else
+      {
+        return null;
+      }
+    }
+
+
+
+    @Override
+    public byte[] unwrap(final byte[] incoming, final int offset, final int len)
+        throws ErrorResultException
+    {
+      try
+      {
+        return saslClient.unwrap(incoming, offset, len);
+      }
+      catch (final SaslException e)
+      {
+        final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get(
+            SASL_MECHANISM_NAME, getExceptionMessage(e));
+        throw ErrorResultException.wrap(Responses
+            .newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR)
+            .setDiagnosticMessage(msg.toString()).setCause(e));
+      }
+    }
+
+
+
+    @Override
+    public byte[] wrap(final byte[] outgoing, final int offset, final int len)
+        throws ErrorResultException
+    {
+      try
+      {
+        return saslClient.wrap(outgoing, offset, len);
+      }
+      catch (final SaslException e)
+      {
+        final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get(
+            SASL_MECHANISM_NAME, getExceptionMessage(e));
+        throw ErrorResultException.wrap(Responses
+            .newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR)
+            .setDiagnosticMessage(msg.toString()).setCause(e));
+      }
+    }
+
+
+
+    @Override
+    void handle(final NameCallback callback)
+        throws UnsupportedCallbackException
+    {
+      callback.setName(authenticationID);
+    }
+
+
+
+    @Override
+    void handle(final PasswordCallback callback)
+        throws UnsupportedCallbackException
+    {
+      callback.setPassword(password.toString().toCharArray());
+    }
+
+
+
+    @Override
+    void handle(final RealmCallback callback)
+        throws UnsupportedCallbackException
+    {
+      if (realm == null)
+      {
+        callback.setText(callback.getDefaultText());
+      }
+      else
+      {
+        callback.setText(realm);
+      }
+    }
+
+  }
+
+
+
+  private final Map<String, String> additionalAuthParams = new LinkedHashMap<String, String>();
+  private final List<String> qopValues = new LinkedList<String>();
+  private String cipher = null;
+
+  // Don't use primitives for these so that we can distinguish between default
+  // settings (null) and values set by the caller.
+  private Boolean serverAuth = null;
+  private Integer maxReceiveBufferSize = null;
+  private Integer maxSendBufferSize = null;
+
+  private String authenticationID;
+  private String authorizationID = null;
+  private ByteString password;
+  private String realm = null;
+
+
+
+  DigestMD5SASLBindRequestImpl(final String authenticationID,
+      final ByteString password)
+  {
+    Validator.ensureNotNull(authenticationID, password);
+    this.authenticationID = authenticationID;
+    this.password = password;
+  }
+
+
+
+  /**
+   * Creates a new digest MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param digestMD5SASLBindRequest
+   *          The digest MD5 SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code digestMD5SASLBindRequest} was {@code null} .
+   */
+  DigestMD5SASLBindRequestImpl(
+      final DigestMD5SASLBindRequest digestMD5SASLBindRequest)
+      throws NullPointerException
+  {
+    super(digestMD5SASLBindRequest);
+    this.additionalAuthParams.putAll(
+        digestMD5SASLBindRequest.getAdditionalAuthParams());
+    this.qopValues.addAll(digestMD5SASLBindRequest.getQOPs());
+    this.cipher = digestMD5SASLBindRequest.getCipher();
+
+    this.serverAuth = digestMD5SASLBindRequest.isServerAuth();
+    this.maxReceiveBufferSize =
+        digestMD5SASLBindRequest.getMaxReceiveBufferSize();
+    this.maxSendBufferSize = digestMD5SASLBindRequest.getMaxSendBufferSize();
+
+    this.authenticationID = digestMD5SASLBindRequest.getAuthenticationID();
+    this.authorizationID = digestMD5SASLBindRequest.getAuthorizationID();
+    this.password = digestMD5SASLBindRequest.getPassword();
+    this.realm = digestMD5SASLBindRequest.getRealm();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest addAdditionalAuthParam(final String name,
+      final String value) throws UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(name, value);
+    additionalAuthParams.put(name, value);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest addQOP(final String... qopValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    for (final String qopValue : qopValues)
+    {
+      this.qopValues.add(Validator.ensureNotNull(qopValue));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public BindClient createBindClient(final String serverName)
+      throws ErrorResultException
+  {
+    return new Client(this, serverName);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Map<String, String> getAdditionalAuthParams()
+  {
+    return additionalAuthParams;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getAuthenticationID()
+  {
+    return authenticationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getCipher()
+  {
+    return cipher;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int getMaxReceiveBufferSize()
+  {
+    return maxReceiveBufferSize == null ? 65536 : maxReceiveBufferSize;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int getMaxSendBufferSize()
+  {
+    return maxSendBufferSize == null ? 65536 : maxSendBufferSize;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getPassword()
+  {
+    return password;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public List<String> getQOPs()
+  {
+    return qopValues;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getRealm()
+  {
+    return realm;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getSASLMechanism()
+  {
+    return SASL_MECHANISM_NAME;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isServerAuth()
+  {
+    return serverAuth == null ? false : serverAuth;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setAuthenticationID(
+      final String authenticationID) throws NullPointerException
+  {
+    Validator.ensureNotNull(authenticationID);
+    this.authenticationID = authenticationID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setAuthorizationID(
+      final String authorizationID)
+  {
+    this.authorizationID = authorizationID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setCipher(final String cipher)
+      throws UnsupportedOperationException
+  {
+    this.cipher = cipher;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setMaxReceiveBufferSize(final int size)
+      throws UnsupportedOperationException
+  {
+    maxReceiveBufferSize = size;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setMaxSendBufferSize(final int size)
+      throws UnsupportedOperationException
+  {
+    maxSendBufferSize = size;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setPassword(final ByteString password)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = password;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setPassword(final char[] password)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = ByteString.valueOf(password);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setRealm(final String realm)
+  {
+    this.realm = realm;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public DigestMD5SASLBindRequest setServerAuth(final boolean serverAuth)
+      throws UnsupportedOperationException
+  {
+    this.serverAuth = serverAuth;
+    return this;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("DigestMD5SASLBindRequest(bindDN=");
+    builder.append(getName());
+    builder.append(", authentication=SASL");
+    builder.append(", saslMechanism=");
+    builder.append(getSASLMechanism());
+    builder.append(", authenticationID=");
+    builder.append(authenticationID);
+    builder.append(", authorizationID=");
+    builder.append(authorizationID);
+    builder.append(", realm=");
+    builder.append(realm);
+    builder.append(", password=");
+    builder.append(password);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequest.java
new file mode 100644
index 0000000..f1ee84c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+
+
+/**
+ * The Extended operation allows additional operations to be defined for
+ * services not already available in the protocol; for example, to implement an
+ * operation which installs transport layer security (see
+ * {@link StartTLSExtendedRequest}).
+ *
+ * @param <S>
+ *          The type of result.
+ */
+public interface ExtendedRequest<S extends ExtendedResult> extends Request
+{
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedRequest<S> addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the numeric OID associated with this extended request.
+   *
+   * @return The numeric OID associated with this extended request.
+   */
+  String getOID();
+
+
+
+  /**
+   * Returns a decoder which can be used to decoded responses to this extended
+   * request.
+   *
+   * @return A decoder which can be used to decoded responses to this extended
+   *         request.
+   */
+  ExtendedResultDecoder<S> getResultDecoder();
+
+
+
+  /**
+   * Returns the value, if any, associated with this extended request. Its
+   * format is defined by the specification of this extended request.
+   *
+   * @return The value associated with this extended request, or {@code null} if
+   *         there is no value.
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * Returns {@code true} if this extended request has a value. In some
+   * circumstances it may be useful to determine if a extended request has a
+   * value, without actually calculating the value and incurring any performance
+   * costs.
+   *
+   * @return {@code true} if this extended request has a value, or {@code false}
+   *         if there is no value.
+   */
+  boolean hasValue();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequestDecoder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequestDecoder.java
new file mode 100644
index 0000000..104915f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExtendedRequestDecoder.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.responses.ExtendedResult;
+
+
+
+/**
+ * A factory interface for decoding a generic extended request as an extended
+ * request of specific type.
+ *
+ * @param <R>
+ *          The type of extended request.
+ * @param <S>
+ *          The type of result.
+ */
+public interface ExtendedRequestDecoder<R extends ExtendedRequest<S>, S extends ExtendedResult>
+{
+  /**
+   * Decodes the provided extended operation request as an {@code
+   * ExtendedRequest} of type {@code R}.
+   *
+   * @param request
+   *          The extended operation request to be decoded.
+   * @param options
+   *          The set of decode options which should be used when decoding the
+   *          extended operation request.
+   * @return The decoded extended operation request.
+   * @throws DecodeException
+   *           If the provided extended operation request could not be decoded.
+   *           For example, if the request name was wrong, or if the request
+   *           value was invalid.
+   */
+  R decodeExtendedRequest(ExtendedRequest<?> request, DecodeOptions options)
+      throws DecodeException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequest.java
new file mode 100644
index 0000000..ab1a2bc
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequest.java
@@ -0,0 +1,163 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The External SASL bind request as defined in RFC 4422. This SASL mechanism
+ * allows a client to request the server to use credentials established by means
+ * external to the mechanism to authenticate the client. The external means may
+ * be, for instance, SSL or TLS.
+ * <p>
+ * A client may either request that its authorization identity be automatically
+ * derived from its authentication credentials exchanged at a lower security
+ * layer, or it may explicitly provide a desired authorization identity.
+ * <p>
+ * The optional authorization identity is specified using an authorization ID,
+ * or {@code authzId}, as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4422">RFC 4422 - Simple
+ *      Authentication and Security Layer (SASL) </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public interface ExternalSASLBindRequest extends SASLBindRequest
+{
+
+  /**
+   * The name of the SASL mechanism based on external authentication.
+   */
+  public static final String SASL_MECHANISM_NAME = "EXTERNAL";
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExternalSASLBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this SASL bind request
+   * as defined by the LDAP protocol, which is always {@code 0xA3}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * Returns the optional desired authorization ID of the user, or {@code null}
+   * if the authorization ID should derived from authentication credentials
+   * exchanged at a lower security layer. The authorization ID usually has the
+   * form "dn:" immediately followed by the distinguished name of the user, or
+   * "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The desired authorization ID of the user, which may be {@code null}
+   *         .
+   */
+  String getAuthorizationID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as,
+   * which is always the empty string for SASL authentication.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  String getName();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getSASLMechanism();
+
+
+
+  /**
+   * Sets the optional desired authorization ID of the user, or {@code null} if
+   * the authorization ID should derived from authentication credentials
+   * exchanged at a lower security layer. The authorization ID usually has the
+   * form "dn:" immediately followed by the distinguished name of the user, or
+   * "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authorizationID
+   *          The desired authorization ID of the user, which may be {@code
+   *          null}.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this external SASL request does not permit the authorization
+   *           ID to be set.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   */
+  ExternalSASLBindRequest setAuthorizationID(String authorizationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java
new file mode 100644
index 0000000..361d10a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ExternalSASLBindRequestImpl.java
@@ -0,0 +1,214 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.Responses;
+
+
+
+/**
+ * External SASL bind request implementation.
+ */
+final class ExternalSASLBindRequestImpl extends
+    AbstractSASLBindRequest<ExternalSASLBindRequest> implements
+    ExternalSASLBindRequest
+{
+  private final static class Client extends SASLBindClientImpl
+  {
+    private final SaslClient saslClient;
+
+
+
+    private Client(final ExternalSASLBindRequestImpl initialBindRequest,
+        final String serverName) throws ErrorResultException
+    {
+      super(initialBindRequest);
+
+      try
+      {
+        saslClient = Sasl.createSaslClient(
+            new String[] { SASL_MECHANISM_NAME }, initialBindRequest
+                .getAuthorizationID(), SASL_DEFAULT_PROTOCOL, serverName, null,
+            this);
+        if (saslClient.hasInitialResponse())
+        {
+          setNextSASLCredentials(saslClient.evaluateChallenge(new byte[0]));
+        }
+        else
+        {
+          setNextSASLCredentials((ByteString) null);
+        }
+      }
+      catch (final SaslException e)
+      {
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e));
+      }
+    }
+
+
+
+    @Override
+    public void dispose()
+    {
+      try
+      {
+        saslClient.dispose();
+      }
+      catch (final SaslException ignored)
+      {
+        // Ignore the SASL exception.
+      }
+    }
+
+
+
+    @Override
+    public boolean evaluateResult(final BindResult result)
+        throws ErrorResultException
+    {
+      try
+      {
+        setNextSASLCredentials(saslClient.evaluateChallenge(result
+            .getServerSASLCredentials() == null ? new byte[0] :
+            result.getServerSASLCredentials().toByteArray()));
+        return saslClient.isComplete();
+      }
+      catch (final SaslException e)
+      {
+        // FIXME: I18N need to have a better error message.
+        // FIXME: Is this the best result code?
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
+            "An error occurred during multi-stage authentication")
+            .setCause(e));
+      }
+    }
+  }
+
+
+
+  private String authorizationID = null;
+
+
+
+  ExternalSASLBindRequestImpl()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * Creates a new external SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param externalSASLBindRequest
+   *          The external SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code externalSASLBindRequest} was {@code null} .
+   */
+  ExternalSASLBindRequestImpl(
+      final ExternalSASLBindRequest externalSASLBindRequest)
+      throws NullPointerException
+  {
+    super(externalSASLBindRequest);
+    this.authorizationID = externalSASLBindRequest.getAuthorizationID();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public BindClient createBindClient(final String serverName)
+      throws ErrorResultException
+  {
+    return new Client(this, serverName);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getSASLMechanism()
+  {
+    return SASL_MECHANISM_NAME;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ExternalSASLBindRequest setAuthorizationID(final String authorizationID)
+  {
+    this.authorizationID = authorizationID;
+    return this;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ExternalSASLBindRequest(bindDN=");
+    builder.append(getName());
+    builder.append(", authentication=SASL");
+    builder.append(", saslMechanism=");
+    builder.append(getSASLMechanism());
+    builder.append(", authorizationID=");
+    builder.append(authorizationID);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequest.java
new file mode 100644
index 0000000..a121cd0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequest.java
@@ -0,0 +1,517 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The GSSAPI SASL bind request as defined in RFC 2831. This SASL mechanism
+ * allows a client to use the Generic Security Service Application Program
+ * Interface (GSS-API) Kerberos V5 to authenticate to the server. This mechanism
+ * can be used to negotiate integrity and/or privacy protection for the
+ * underlying connection.
+ * <p>
+ * The optional authorization identity is specified using an authorization ID,
+ * or {@code authzId}, as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4752">RFC 4752 - The Kerberos V5
+ *      ("GSSAPI") Simple Authentication and Security Layer (SASL) Mechanism
+ *      </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public interface GSSAPISASLBindRequest extends SASLBindRequest
+{
+
+  /**
+   * The name of the SASL mechanism based on GSS-API authentication.
+   */
+  public static final String SASL_MECHANISM_NAME = "GSSAPI";
+
+  /**
+   * Indicates that the client will accept authentication only. More
+   * specifically, the underlying connection will not be protected using
+   * integrity protection or encryption, unless previously established using
+   * SSL/TLS. This is the default if no QOP option is present in the bind
+   * request.
+   */
+  public static final String QOP_AUTH = "auth";
+
+  /**
+   * Indicates that the client will accept authentication with connection
+   * integrity protection. More specifically, the underlying connection will not
+   * be encrypted, unless previously established using SSL/TLS.
+   */
+  public static final String QOP_AUTH_INT = "auth-int";
+
+  /**
+   * Indicates that the client will accept authentication with connection
+   * integrity protection and encryption.
+   */
+  public static final String QOP_AUTH_CONF = "auth-conf";
+
+
+
+  /**
+   * Adds the provided additional authentication parameter to the list of
+   * parameters to be passed to the underlying mechanism implementation. This
+   * method is provided in order to allow for future extensions.
+   *
+   * @param name
+   *          The name of the additional authentication parameter.
+   * @param value
+   *          The value of the additional authentication parameter.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit additional authentication
+   *           parameters to be added.
+   * @throws NullPointerException
+   *           If {@code name} or {@code value} was {@code null}.
+   */
+  GSSAPISASLBindRequest addAdditionalAuthParam(String name, String value)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Returns a map containing the provided additional authentication parameters
+   * to be passed to the underlying mechanism implementation. This method is
+   * provided in order to allow for future extensions.
+   *
+   * @return A map containing the provided additional authentication parameters
+   *         to be passed to the underlying mechanism implementation.
+   */
+  Map<String, String> getAdditionalAuthParams();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  GSSAPISASLBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Adds the provided quality of protection (QOP) values to the ordered list of
+   * QOP values that the client is willing to accept. The order of the list
+   * specifies the preference order, high to low. Authentication will fail if no
+   * QOP values are recognized or accepted by the server.
+   * <p>
+   * By default the client will accept {@link #QOP_AUTH AUTH}.
+   *
+   * @param qopValues
+   *          The quality of protection values that the client is willing to
+   *          accept.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit QOP values to be added.
+   * @throws NullPointerException
+   *           If {@code qopValues} was {@code null}.
+   * @see #QOP_AUTH
+   * @see #QOP_AUTH_INT
+   * @see #QOP_AUTH_CONF
+   */
+  GSSAPISASLBindRequest addQOP(String... qopValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication ID of the user, which should be the user's
+   * Kerberos principal. The authentication ID usually has the form "dn:"
+   * immediately followed by the distinguished name of the user, or "u:"
+   * followed by a user ID string, but other forms are permitted.
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @return The authentication ID of the user.
+   */
+  String getAuthenticationID();
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this SASL bind request
+   * as defined by the LDAP protocol, which is always {@code 0xA3}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  @Override
+  byte getAuthenticationType();
+
+
+
+  /**
+   * Returns the optional authorization ID of the user which represents an
+   * alternate authorization identity which should be used for subsequent
+   * operations performed on the connection. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authorization ID of the user, which may be {@code null}.
+   */
+  String getAuthorizationID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the optional address of the Kerberos KDC (Key Distribution Center).
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @return The address of the Kerberos KDC (Key Distribution Center), which
+   *         may be {@code null}.
+   */
+  String getKDCAddress();
+
+
+
+  /**
+   * Returns the maximum size of the receive buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * send buffer size. The default size is 65536.
+   *
+   * @return The maximum size of the receive buffer in bytes.
+   */
+  int getMaxReceiveBufferSize();
+
+
+
+  /**
+   * Returns the maximum size of the send buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * receive buffer size. The default size is 65536.
+   *
+   * @return The maximum size of the send buffer in bytes.
+   */
+  int getMaxSendBufferSize();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as,
+   * which is always the empty string for SASL authentication.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  @Override
+  String getName();
+
+
+
+  /**
+   * Returns the password of the user that the client wishes to bind as.
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @return The password of the user that the client wishes to bind as.
+   */
+  ByteString getPassword();
+
+
+
+  /**
+   * Returns the ordered list of quality of protection (QOP) values that the
+   * client is willing to accept. The order of the list specifies the preference
+   * order, high to low. Authentication will fail if no QOP values are
+   * recognized or accepted by the server.
+   * <p>
+   * By default the client will accept {@link #QOP_AUTH AUTH}.
+   *
+   * @return The list of quality of protection values that the client is willing
+   *         to accept. The returned list may be empty indicating that the
+   *         default QOP will be accepted.
+   */
+  List<String> getQOPs();
+
+
+
+  /**
+   * Returns the optional realm containing the user's account.
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @return The name of the realm containing the user's account, which may be
+   *         {@code null}.
+   */
+  String getRealm();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  String getSASLMechanism();
+
+
+
+  /**
+   * Returns the Kerberos subject of the user to be authenticated.
+   * <p>
+   * <b>NOTE</b>: if a {@code Subject} is specified then the authentication ID,
+   * KDC address, password, and realm, will be ignored.
+   *
+   * @return The Kerberos subject of the user to be authenticated.
+   */
+  Subject getSubject();
+
+
+
+  /**
+   * Returns {@code true} if the server must authenticate to the client. The
+   * default is {@code false}.
+   *
+   * @return {@code true} if the server must authenticate to the client.
+   */
+  boolean isServerAuth();
+
+
+
+  /**
+   * Sets the authentication ID of the user, which should be the user's Kerberos
+   * principal. The authentication ID usually has the form "dn:" immediately
+   * followed by the distinguished name of the user, or "u:" followed by a user
+   * ID string, but other forms are permitted.
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user.
+   * @return This bind request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authenticationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   * @throws NullPointerException
+   *           If {@code authenticationID} was {@code null}.
+   */
+  GSSAPISASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * Sets the optional authorization ID of the user which represents an
+   * alternate authorization identity which should be used for subsequent
+   * operations performed on the connection. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authorizationID
+   *          The authorization ID of the user, which may be {@code null}.
+   * @return This bind request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   */
+  GSSAPISASLBindRequest setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException;
+
+
+
+  /**
+   * Sets the optional address of the Kerberos KDC (Key Distribution Center).
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @param address
+   *          The address of the Kerberos KDC (Key Distribution Center), which
+   *          may be {@code null}.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the KDC address to be set.
+   * @throws NullPointerException
+   *           If {@code address} was {@code null}.
+   */
+  GSSAPISASLBindRequest setKDCAddress(String address)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the maximum size of the receive buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * send buffer size. The default size is 65536.
+   *
+   * @param size
+   *          The maximum size of the receive buffer in bytes.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the buffer size to be set.
+   */
+  GSSAPISASLBindRequest setMaxReceiveBufferSize(int size)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the maximum size of the send buffer in bytes. The actual maximum
+   * number of bytes will be the minimum of this number and the peer's maximum
+   * receive buffer size. The default size is 65536.
+   *
+   * @param size
+   *          The maximum size of the send buffer in bytes.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the buffer size to be set.
+   */
+  GSSAPISASLBindRequest setMaxSendBufferSize(int size)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as.
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as, which
+   *          may be empty.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  GSSAPISASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as. The
+   * password will be converted to a UTF-8 octet string.
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  GSSAPISASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the optional realm containing the user's account.
+   * <p>
+   * <b>NOTE</b>: this will not be used if a {@code Subject} is specified.
+   *
+   * @param realm
+   *          The name of the realm containing the user's account, which may be
+   *          {@code null}.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the realm to be set.
+   * @throws NullPointerException
+   *           If {@code realm} was {@code null}.
+   */
+  GSSAPISASLBindRequest setRealm(String realm)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Specifies whether or not the server must authenticate to the client. The
+   * default is {@code false}.
+   *
+   * @param serverAuth
+   *          {@code true} if the server must authenticate to the client or
+   *          {@code false} otherwise.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit server auth to be set.
+   */
+  GSSAPISASLBindRequest setServerAuth(boolean serverAuth)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the Kerberos subject of the user to be authenticated.
+   * <p>
+   * <b>NOTE</b>: if a {@code Subject} is specified then the authentication ID,
+   * KDC address, password, and realm, will be ignored.
+   *
+   * @param subject
+   *          The Kerberos subject of the user to be authenticated.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the Kerberos subject to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code subject} was {@code null}.
+   */
+  GSSAPISASLBindRequest setSubject(Subject subject)
+      throws UnsupportedOperationException, NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java
new file mode 100644
index 0000000..d139e2d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GSSAPISASLBindRequestImpl.java
@@ -0,0 +1,784 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_LDAPAUTH_GSSAPI_LOCAL_AUTHENTICATION_FAILED;
+import static com.sun.opends.sdk.messages.Messages.ERR_SASL_CONTEXT_CREATE_ERROR;
+import static com.sun.opends.sdk.messages.Messages.ERR_SASL_PROTOCOL_ERROR;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+import static com.sun.opends.sdk.util.StaticUtils.joinCollection;
+
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.*;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.Responses;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+import com.sun.security.auth.callback.TextCallbackHandler;
+import com.sun.security.auth.module.Krb5LoginModule;
+
+
+
+/**
+ * GSSAPI SASL bind request implementation.
+ */
+final class GSSAPISASLBindRequestImpl extends
+    AbstractSASLBindRequest<GSSAPISASLBindRequest> implements
+    GSSAPISASLBindRequest
+{
+  private final static class Client extends SASLBindClientImpl
+  {
+    private static Subject kerberos5Login(final String authenticationID,
+        final ByteString password, final String realm, final String kdc)
+        throws ErrorResultException
+    {
+      if (authenticationID == null)
+      {
+        // FIXME: I18N need to have a better error message.
+        // FIXME: Is this the best result code?
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
+            "No authentication ID specified for GSSAPI SASL authentication"));
+      }
+
+      if (password == null)
+      {
+        // FIXME: I18N need to have a better error message.
+        // FIXME: Is this the best result code?
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
+            "No password specified for GSSAPI SASL authentication"));
+      }
+
+      final Map<String, Object> state = new HashMap<String, Object>();
+      state.put("javax.security.auth.login.name", authenticationID);
+      state.put("javax.security.auth.login.password", password.toString()
+          .toCharArray());
+      state.put("javax.security.auth.useSubjectCredsOnly", "true");
+      state.put("java.security.krb5.realm", realm);
+      state.put("java.security.krb5.kdc", kdc);
+
+      final Map<String, Object> options = new HashMap<String, Object>();
+      options.put("tryFirstPass", "true");
+      options.put("useTicketCache", "true");
+      options.put("doNotPrompt", "true");
+      options.put("storePass", "false");
+      options.put("forwardable", "true");
+
+      final Subject subject = new Subject();
+      final Krb5LoginModule login = new Krb5LoginModule();
+      login.initialize(subject, new TextCallbackHandler(), state, options);
+      try
+      {
+        if (login.login())
+        {
+          login.commit();
+        }
+      }
+      catch (final LoginException e)
+      {
+        // FIXME: Is this the best result code?
+        final LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_LOCAL_AUTHENTICATION_FAILED
+            .get(StaticUtils.getExceptionMessage(e));
+        throw ErrorResultException.wrap(Responses
+            .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+            .setDiagnosticMessage(message.toString()).setCause(e));
+      }
+      return subject;
+    }
+
+
+
+    private final SaslClient saslClient;
+    private final String authorizationID;
+    private final Subject subject;
+
+    private BindResult lastResult;
+
+    private final PrivilegedExceptionAction<Boolean> evaluateAction =
+      new PrivilegedExceptionAction<Boolean>()
+    {
+      @Override
+      public Boolean run() throws ErrorResultException
+      {
+        try
+        {
+          setNextSASLCredentials(saslClient.evaluateChallenge(lastResult
+              .getServerSASLCredentials() == null ? new byte[0] : lastResult
+              .getServerSASLCredentials().toByteArray()));
+          return saslClient.isComplete();
+        }
+        catch (final SaslException e)
+        {
+          // FIXME: I18N need to have a better error message.
+          // FIXME: Is this the best result code?
+          throw ErrorResultException.wrap(Responses
+              .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+              .setDiagnosticMessage(
+                  "An error occurred during multi-stage authentication")
+              .setCause(e));
+        }
+      }
+    };
+
+
+
+    private Client(final GSSAPISASLBindRequestImpl initialBindRequest,
+        final String serverName) throws ErrorResultException
+    {
+      super(initialBindRequest);
+
+      this.authorizationID = initialBindRequest.getAuthorizationID();
+      if (initialBindRequest.getSubject() != null)
+      {
+        this.subject = initialBindRequest.getSubject();
+      }
+      else
+      {
+        this.subject = kerberos5Login(initialBindRequest.getAuthenticationID(),
+            initialBindRequest.getPassword(), initialBindRequest.getRealm(),
+            initialBindRequest.getKDCAddress());
+      }
+
+      try
+      {
+        this.saslClient = Subject.doAs(subject,
+            new PrivilegedExceptionAction<SaslClient>()
+            {
+              @Override
+              public SaslClient run() throws ErrorResultException
+              {
+                // Create property map containing all the parameters.
+                final Map<String, String> props = new HashMap<String, String>();
+
+                final List<String> qopValues = initialBindRequest.getQOPs();
+                if (!qopValues.isEmpty())
+                {
+                  props.put(Sasl.QOP, joinCollection(qopValues, ","));
+                }
+
+                final Boolean serverAuth = initialBindRequest.isServerAuth();
+                if (serverAuth != null)
+                {
+                  props.put(Sasl.SERVER_AUTH, String.valueOf(serverAuth));
+                }
+
+                Integer size = initialBindRequest.getMaxReceiveBufferSize();
+                if (size != null)
+                {
+                  props.put(Sasl.MAX_BUFFER, String.valueOf(size));
+                }
+
+                size = initialBindRequest.getMaxSendBufferSize();
+                if (size != null)
+                {
+                  props.put("javax.security.sasl.sendmaxbuffer",
+                      String.valueOf(size));
+                }
+
+                for (final Map.Entry<String, String> e : initialBindRequest
+                    .getAdditionalAuthParams().entrySet())
+                {
+                  props.put(e.getKey(), e.getValue());
+                }
+
+                try
+                {
+                  final SaslClient saslClient = Sasl.createSaslClient(
+                      new String[] { SASL_MECHANISM_NAME }, authorizationID,
+                      SASL_DEFAULT_PROTOCOL, serverName, props, Client.this);
+                  if (saslClient.hasInitialResponse())
+                  {
+                    setNextSASLCredentials(saslClient
+                        .evaluateChallenge(new byte[0]));
+                  }
+                  else
+                  {
+                    setNextSASLCredentials((ByteString) null);
+                  }
+                  return saslClient;
+                }
+                catch (final SaslException e)
+                {
+                  throw ErrorResultException.wrap(Responses.newResult(
+                      ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e));
+                }
+              }
+            });
+      }
+      catch (final PrivilegedActionException e)
+      {
+        if (e.getCause() instanceof ErrorResultException)
+        {
+          throw (ErrorResultException) e.getCause();
+        }
+        else
+        {
+          // This should not happen. Must be a bug.
+          final LocalizableMessage msg = ERR_SASL_CONTEXT_CREATE_ERROR.get(
+              SASL_MECHANISM_NAME, getExceptionMessage(e));
+          throw ErrorResultException.wrap(Responses
+              .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+              .setDiagnosticMessage(msg.toString()).setCause(e));
+        }
+      }
+    }
+
+
+
+    @Override
+    public void dispose()
+    {
+      try
+      {
+        saslClient.dispose();
+      }
+      catch (final SaslException ignored)
+      {
+        // Ignore the SASL exception.
+      }
+    }
+
+
+
+    @Override
+    public boolean evaluateResult(final BindResult result)
+        throws ErrorResultException
+    {
+      this.lastResult = result;
+      try
+      {
+        return Subject.doAs(subject, evaluateAction);
+      }
+      catch (final PrivilegedActionException e)
+      {
+        if (e.getCause() instanceof ErrorResultException)
+        {
+          throw (ErrorResultException) e.getCause();
+        }
+        else
+        {
+          // This should not happen. Must be a bug.
+          final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get(
+              SASL_MECHANISM_NAME, getExceptionMessage(e));
+          throw ErrorResultException.wrap(Responses
+              .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+              .setDiagnosticMessage(msg.toString()).setCause(e));
+        }
+      }
+    }
+
+
+
+    @Override
+    public ConnectionSecurityLayer getConnectionSecurityLayer()
+    {
+      final String qop = (String) saslClient.getNegotiatedProperty(Sasl.QOP);
+      if (qop.equalsIgnoreCase("auth-int") || qop.equalsIgnoreCase("auth-conf"))
+      {
+        return this;
+      }
+      else
+      {
+        return null;
+      }
+    }
+
+
+
+    @Override
+    public byte[] unwrap(final byte[] incoming, final int offset, final int len)
+        throws ErrorResultException
+    {
+      try
+      {
+        return saslClient.unwrap(incoming, offset, len);
+      }
+      catch (final SaslException e)
+      {
+        final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get(
+            SASL_MECHANISM_NAME, getExceptionMessage(e));
+        throw ErrorResultException.wrap(Responses
+            .newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR)
+            .setDiagnosticMessage(msg.toString()).setCause(e));
+      }
+    }
+
+
+
+    @Override
+    public byte[] wrap(final byte[] outgoing, final int offset, final int len)
+        throws ErrorResultException
+    {
+      try
+      {
+        return saslClient.wrap(outgoing, offset, len);
+      }
+      catch (final SaslException e)
+      {
+        final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get(
+            SASL_MECHANISM_NAME, getExceptionMessage(e));
+        throw ErrorResultException.wrap(Responses
+            .newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR)
+            .setDiagnosticMessage(msg.toString()).setCause(e));
+      }
+    }
+
+  }
+
+
+
+  // If null then authenticationID and password must be present.
+  private Subject subject = null;
+
+  // Ignored if subject is non-null.
+  private String authenticationID = null;
+  private ByteString password = null;
+  private String realm = null;
+
+  private String kdcAddress = null;
+
+  // Optional authorization ID.
+  private String authorizationID = null;
+
+  private final Map<String, String> additionalAuthParams = new LinkedHashMap<String, String>();
+  private final List<String> qopValues = new LinkedList<String>();
+
+  // Don't use primitives for these so that we can distinguish between default
+  // settings (null) and values set by the caller.
+  private Boolean serverAuth = null;
+  private Integer maxReceiveBufferSize = null;
+  private Integer maxSendBufferSize = null;
+
+
+
+  GSSAPISASLBindRequestImpl(final String authenticationID,
+      final ByteString password)
+  {
+    Validator.ensureNotNull(authenticationID, password);
+    this.authenticationID = authenticationID;
+    this.password = password;
+  }
+
+
+
+  /**
+   * Creates a new GSSAPI SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param gssapiSASLBindRequest
+   *          The GSSAPI SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code gssAPISASLBindRequest} was {@code null}.
+   */
+  GSSAPISASLBindRequestImpl(
+      final GSSAPISASLBindRequest gssapiSASLBindRequest)
+      throws NullPointerException
+  {
+    super(gssapiSASLBindRequest);
+    this.subject = gssapiSASLBindRequest.getSubject();
+
+    this.authenticationID = gssapiSASLBindRequest.getAuthenticationID();
+    this.password = gssapiSASLBindRequest.getPassword();
+    this.realm = gssapiSASLBindRequest.getRealm();
+
+    this.kdcAddress = gssapiSASLBindRequest.getKDCAddress();
+
+    this.authorizationID = gssapiSASLBindRequest.getAuthorizationID();
+
+    this.additionalAuthParams.putAll(
+        gssapiSASLBindRequest.getAdditionalAuthParams());
+    this.qopValues.addAll(gssapiSASLBindRequest.getQOPs());
+
+    this.serverAuth = gssapiSASLBindRequest.isServerAuth();
+    this.maxReceiveBufferSize = gssapiSASLBindRequest.getMaxReceiveBufferSize();
+    this.maxSendBufferSize = gssapiSASLBindRequest.getMaxSendBufferSize();
+  }
+
+
+
+  GSSAPISASLBindRequestImpl(final Subject subject)
+  {
+    Validator.ensureNotNull(subject);
+    this.subject = subject;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest addAdditionalAuthParam(final String name,
+      final String value) throws UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(name, value);
+    additionalAuthParams.put(name, value);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest addQOP(final String... qopValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    for (final String qopValue : qopValues)
+    {
+      this.qopValues.add(Validator.ensureNotNull(qopValue));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public BindClient createBindClient(final String serverName)
+      throws ErrorResultException
+  {
+    return new Client(this, serverName);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Map<String, String> getAdditionalAuthParams()
+  {
+    return additionalAuthParams;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getAuthenticationID()
+  {
+    return authenticationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getKDCAddress()
+  {
+    return kdcAddress;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int getMaxReceiveBufferSize()
+  {
+    return maxReceiveBufferSize == null ? 65536 : maxReceiveBufferSize;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int getMaxSendBufferSize()
+  {
+    return maxSendBufferSize == null ? 65536 : maxSendBufferSize;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getPassword()
+  {
+    return password;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public List<String> getQOPs()
+  {
+    return qopValues;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getRealm()
+  {
+    return realm;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getSASLMechanism()
+  {
+    return SASL_MECHANISM_NAME;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Subject getSubject()
+  {
+    return subject;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isServerAuth()
+  {
+    return serverAuth == null ? false : serverAuth;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setAuthenticationID(final String authenticationID)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(authenticationID);
+    this.authenticationID = authenticationID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setAuthorizationID(final String authorizationID)
+  {
+    this.authorizationID = authorizationID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setKDCAddress(final String address)
+  {
+    this.kdcAddress = address;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setMaxReceiveBufferSize(final int size)
+      throws UnsupportedOperationException
+  {
+    maxReceiveBufferSize = size;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setMaxSendBufferSize(final int size)
+      throws UnsupportedOperationException
+  {
+    maxSendBufferSize = size;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setPassword(final ByteString password)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = password;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setPassword(final char[] password)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = ByteString.valueOf(password);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setRealm(final String realm)
+  {
+    this.realm = realm;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setServerAuth(final boolean serverAuth)
+      throws UnsupportedOperationException
+  {
+    this.serverAuth = serverAuth;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public GSSAPISASLBindRequest setSubject(final Subject subject)
+      throws NullPointerException
+  {
+    this.subject = subject;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GSSAPISASLBindRequest(bindDN=");
+    builder.append(getName());
+    builder.append(", authentication=SASL");
+    builder.append(", saslMechanism=");
+    builder.append(getSASLMechanism());
+    if (subject != null)
+    {
+      builder.append(", subject=");
+      builder.append(subject);
+    }
+    else
+    {
+      builder.append(", authenticationID=");
+      builder.append(authenticationID);
+      builder.append(", authorizationID=");
+      builder.append(authorizationID);
+      builder.append(", realm=");
+      builder.append(realm);
+      builder.append(", password=");
+      builder.append(password);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequest.java
new file mode 100644
index 0000000..1776617
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequest.java
@@ -0,0 +1,163 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A generic Bind request which should be used for unsupported authentication
+ * methods. Servers that do not support a choice supplied by a client return a
+ * Bind response with the result code set to
+ * {@link ResultCode#AUTH_METHOD_NOT_SUPPORTED}.
+ */
+public interface GenericBindRequest extends BindRequest
+{
+  /**
+   * {@inheritDoc}
+   */
+  GenericBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * Returns the authentication information for this bind request. The content
+   * is defined by the authentication mechanism.
+   *
+   * @return The authentication information.
+   */
+  ByteString getAuthenticationValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getName();
+
+
+
+  /**
+   * Sets the authentication mechanism identifier for this generic bind request.
+   * Note that value {@code 0} is reserved for simple authentication, {@code 1}
+   * and {@code 2} are reserved but unused, and {@code 3} is reserved for SASL
+   * authentication.
+   *
+   * @param type
+   *          The authentication mechanism identifier for this generic bind
+   *          request.
+   * @return This generic bind request.
+   * @throws UnsupportedOperationException
+   *           If this generic bind request does not permit the authentication
+   *           type to be set.
+   */
+  GenericBindRequest setAuthenticationType(byte type)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the authentication information for this generic bind request in a form
+   * defined by the authentication mechanism.
+   *
+   * @param bytes
+   *          The authentication information for this generic bind request in a
+   *          form defined by the authentication mechanism.
+   * @return This generic bind request.
+   * @throws UnsupportedOperationException
+   *           If this generic bind request does not permit the authentication
+   *           bytes to be set.
+   * @throws NullPointerException
+   *           If {@code bytes} was {@code null}.
+   */
+  GenericBindRequest setAuthenticationValue(ByteString bytes)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the name of the Directory object that the client wishes to bind as.
+   * The name may be empty (but never {@code null} when used for of anonymous
+   * binds, or when using SASL authentication. The server shall not dereference
+   * any aliases in locating the named object.
+   * <p>
+   * The LDAP protocol defines the Bind name to be a distinguished name, however
+   * some LDAP implementations have relaxed this constraint and allow other
+   * identities to be used, such as the user's email address.
+   *
+   * @param name
+   *          The name of the Directory object that the client wishes to bind
+   *          as.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the distinguished name to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  GenericBindRequest setName(String name) throws UnsupportedOperationException,
+      NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequestImpl.java
new file mode 100644
index 0000000..88b4936
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericBindRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ErrorResultException;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Generic bind request implementation.
+ */
+final class GenericBindRequestImpl extends
+    AbstractBindRequest<GenericBindRequest> implements GenericBindRequest
+{
+  private final BindClient bindClient;
+
+  private String name;
+
+  private ByteString authenticationValue;
+
+  private byte authenticationType;
+
+
+
+  /**
+   * Creates a new generic bind request using a generic bind client.
+   */
+  GenericBindRequestImpl(final String name, final byte authenticationType,
+      final ByteString authenticationValue)
+  {
+    this.name = name;
+    this.authenticationType = authenticationType;
+    this.authenticationValue = authenticationValue;
+    this.bindClient = null; // Create a new bind client each time.
+  }
+
+
+
+  /**
+   * Creates a new generic bind request using the provided bind client.
+   * <p>
+   * This is intended for use by other bind client implementations in this
+   * package.
+   */
+  GenericBindRequestImpl(final String name, final byte authenticationType,
+      final ByteString authenticationValue, final BindClient bindClient)
+  {
+    this.name = name;
+    this.authenticationType = authenticationType;
+    this.authenticationValue = authenticationValue;
+    this.bindClient = bindClient; // Always return same bind client.
+  }
+
+
+
+  /**
+   * Creates a new generic bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param genericBindRequest
+   *          The generic bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code genericBindRequest} was {@code null} .
+   */
+  GenericBindRequestImpl(
+      final GenericBindRequest genericBindRequest)
+      throws NullPointerException
+  {
+    super(genericBindRequest);
+    this.name = genericBindRequest.getName();
+    this.authenticationType = genericBindRequest.getAuthenticationType();
+    this.authenticationValue = genericBindRequest.getAuthenticationValue();
+    this.bindClient = null; // Create a new bind client each time.
+  }
+
+
+
+  public BindClient createBindClient(final String serverName)
+      throws ErrorResultException
+  {
+    if (bindClient == null)
+    {
+      return new BindClientImpl(this)
+          .setNextAuthenticationValue(authenticationValue);
+    }
+    else
+    {
+      return bindClient;
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public byte getAuthenticationType()
+  {
+    return authenticationType;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getAuthenticationValue()
+  {
+    return authenticationValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericBindRequest setAuthenticationType(final byte type)
+      throws UnsupportedOperationException
+  {
+    this.authenticationType = type;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericBindRequest setAuthenticationValue(final ByteString bytes)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(bytes);
+    this.authenticationValue = bytes;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericBindRequest setName(final String name)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(name);
+    this.name = name;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GenericBindRequest(name=");
+    builder.append(getName());
+    builder.append(", authenticationType=");
+    builder.append(getAuthenticationType());
+    builder.append(", authenticationValue=");
+    builder.append(getAuthenticationValue());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequest.java
new file mode 100644
index 0000000..46388d3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequest.java
@@ -0,0 +1,147 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+import org.opends.sdk.responses.GenericExtendedResult;
+
+
+
+/**
+ * A generic Extended request which should be used for unsupported extended
+ * operations. Servers list the names of Extended requests they recognize in the
+ * {@code supportedExtension} attribute in the root DSE. Where the name is not
+ * recognized, the server returns
+ * {@link org.opends.sdk.ResultCode#PROTOCOL_ERROR} (the server may return this
+ * error in other cases).
+ */
+public interface GenericExtendedRequest extends
+    ExtendedRequest<GenericExtendedResult>
+{
+  /**
+   * A decoder which can be used to decode generic extended operation requests.
+   */
+  public static final ExtendedRequestDecoder<GenericExtendedRequest,
+                                             GenericExtendedResult> DECODER =
+    new GenericExtendedRequestImpl.RequestDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  GenericExtendedRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResultDecoder<GenericExtendedResult> getResultDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * Sets the numeric OID associated with this extended request.
+   *
+   * @param oid
+   *          The numeric OID associated with this extended request.
+   * @return This generic extended request.
+   * @throws UnsupportedOperationException
+   *           If this generic extended request does not permit the request name
+   *           to be set.
+   * @throws NullPointerException
+   *           If {@code oid} was {@code null}.
+   */
+  GenericExtendedRequest setOID(String oid)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the value, if any, associated with this extended request. Its format
+   * is defined by the specification of this extended request.
+   *
+   * @param bytes
+   *          The value associated with this extended request, or {@code null}
+   *          if there is no value.
+   * @return This generic extended request.
+   * @throws UnsupportedOperationException
+   *           If this generic extended request does not permit the request
+   *           value to be set.
+   */
+  GenericExtendedRequest setValue(ByteString bytes)
+      throws UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequestImpl.java
new file mode 100644
index 0000000..135c4d5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/GenericExtendedRequestImpl.java
@@ -0,0 +1,256 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.responses.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Generic extended request implementation.
+ */
+final class GenericExtendedRequestImpl extends
+    AbstractExtendedRequest<GenericExtendedRequest, GenericExtendedResult>
+    implements GenericExtendedRequest
+{
+
+  static final class RequestDecoder implements
+      ExtendedRequestDecoder<GenericExtendedRequest, GenericExtendedResult>
+  {
+    public GenericExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      if (request instanceof GenericExtendedRequest)
+      {
+        return (GenericExtendedRequest) request;
+      }
+      else
+      {
+        final GenericExtendedRequest newRequest = new GenericExtendedRequestImpl(
+            request.getOID(), request.getValue());
+
+        for (final Control control : request.getControls())
+        {
+          newRequest.addControl(control);
+        }
+
+        return newRequest;
+      }
+    }
+  }
+
+
+
+  private static final class GenericExtendedResultDecoder extends
+      AbstractExtendedResultDecoder<GenericExtendedResult>
+  {
+
+    public GenericExtendedResult newExtendedErrorResult(
+        final ResultCode resultCode, final String matchedDN,
+        final String diagnosticMessage)
+    {
+      return Responses.newGenericExtendedResult(resultCode).setMatchedDN(
+          matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public GenericExtendedResult decodeExtendedResult(
+        final ExtendedResult result, final DecodeOptions options)
+        throws DecodeException
+    {
+      if (result instanceof GenericExtendedResult)
+      {
+        return (GenericExtendedResult) result;
+      }
+      else
+      {
+        final GenericExtendedResult newResult = Responses
+            .newGenericExtendedResult(result.getResultCode()).setMatchedDN(
+                result.getMatchedDN()).setDiagnosticMessage(
+                result.getDiagnosticMessage()).setOID(result.getOID())
+            .setValue(result.getValue());
+        for (final Control control : result.getControls())
+        {
+          newResult.addControl(control);
+        }
+        return newResult;
+      }
+    }
+  }
+
+
+
+  private static final GenericExtendedResultDecoder RESULT_DECODER =
+    new GenericExtendedResultDecoder();
+
+  private ByteString requestValue = ByteString.empty();
+
+  private String requestName;
+
+
+
+  /**
+   * Creates a new generic extended request using the provided name and optional
+   * value.
+   *
+   * @param requestName
+   *          The dotted-decimal representation of the unique OID corresponding
+   *          to this extended request.
+   * @param requestValue
+   *          The content of this generic extended request in a form defined by
+   *          the extended operation, or {@code null} if there is no content.
+   * @throws NullPointerException
+   *           If {@code requestName} was {@code null}.
+   */
+  GenericExtendedRequestImpl(final String requestName,
+      final ByteString requestValue) throws NullPointerException
+  {
+    this.requestName = requestName;
+    this.requestValue = requestValue;
+  }
+
+
+
+  /**
+   * Creates a new generic extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param genericExtendedRequest
+   *          The generic extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code extendedRequest} was {@code null} .
+   */
+  protected GenericExtendedRequestImpl(
+      GenericExtendedRequest genericExtendedRequest)
+      throws NullPointerException
+  {
+    super(genericExtendedRequest);
+    this.requestName = genericExtendedRequest.getOID();
+    this.requestValue = genericExtendedRequest.getValue();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return requestName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<GenericExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return requestValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return requestValue != null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericExtendedRequest setOID(final String oid)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(oid);
+    this.requestName = oid;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericExtendedRequest setValue(final ByteString bytes)
+      throws UnsupportedOperationException
+  {
+    this.requestValue = bytes;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GenericExtendedRequest(requestName=");
+    builder.append(getOID());
+    if (hasValue())
+    {
+      builder.append(", requestValue=");
+      StaticUtils.toHexPlusAscii(getValue(), builder, 4);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequest.java
new file mode 100644
index 0000000..6b1a89b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequest.java
@@ -0,0 +1,263 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.ldif.ChangeRecord;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+
+
+/**
+ * The Modify DN operation allows a client to change the Relative Distinguished
+ * Name (RDN) of an entry in the Directory and/or to move a subtree of entries
+ * to a new location in the Directory.
+ */
+public interface ModifyDNRequest extends Request, ChangeRecord
+{
+  /**
+   * {@inheritDoc}
+   */
+  <R, P> R accept(ChangeRecordVisitor<R, P> v, P p);
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ModifyDNRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the distinguished name of the entry to be renamed. This entry may
+   * or may not have subordinate entries. The server shall not dereference any
+   * aliases in locating the entry to be renamed.
+   *
+   * @return The distinguished name of the entry.
+   */
+  DN getName();
+
+
+
+  /**
+   * Returns the new RDN of the entry to be renamed. The value of the old RDN is
+   * supplied when moving the entry to a new superior without changing its RDN.
+   * Attribute values of the new RDN not matching any attribute value of the
+   * entry are added to the entry, and an appropriate error is returned if this
+   * fails.
+   *
+   * @return The new RDN of the entry.
+   */
+  RDN getNewRDN();
+
+
+
+  /**
+   * Returns the distinguished name of an existing entry that will become the
+   * immediate superior (parent) of the entry to be renamed. The server shall
+   * not dereference any aliases in locating the new superior entry.
+   *
+   * @return The distinguished name of the new superior entry, or {@code null}
+   *         if the entry is to remain under the same parent entry.
+   */
+  DN getNewSuperior();
+
+
+
+  /**
+   * Indicates whether the old RDN attribute values are to be retained as
+   * attributes of the entry or deleted from the entry.
+   *
+   * @return {@code true} if the old RDN attribute values are to be deleted from
+   *         the entry, or {@code false} if they are to be retained.
+   */
+  boolean isDeleteOldRDN();
+
+
+
+  /**
+   * Specifies whether the old RDN attribute values are to be retained as
+   * attributes of the entry or deleted from the entry.
+   *
+   * @param deleteOldRDN
+   *          {@code true} if the old RDN attribute values are to be deleted
+   *          from the entry, or {@code false} if they are to be retained.
+   * @return This modify DN request.
+   * @throws UnsupportedOperationException
+   *           If this modify DN request does not permit the delete old RDN
+   *           parameter to be set.
+   */
+  ModifyDNRequest setDeleteOldRDN(boolean deleteOldRDN)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be renamed. This entry may or
+   * may not have subordinate entries. The server shall not dereference any
+   * aliases in locating the entry to be renamed.
+   *
+   * @param dn
+   *          The distinguished name of the entry to be renamed.
+   * @return This modify DN request.
+   * @throws UnsupportedOperationException
+   *           If this modify DN request does not permit the distinguished name
+   *           to be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  ModifyDNRequest setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be renamed. This entry may or
+   * may not have subordinate entries. The server shall not dereference any
+   * aliases in locating the entry to be renamed.
+   *
+   * @param dn
+   *          The distinguished name of the entry to be renamed.
+   * @return This modify DN request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this modify DN request does not permit the distinguished name
+   *           to be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  ModifyDNRequest setName(String dn) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the new RDN of the entry to be renamed. The value of the old RDN is
+   * supplied when moving the entry to a new superior without changing its RDN.
+   * Attribute values of the new RDN not matching any attribute value of the
+   * entry are added to the entry, and an appropriate error is returned if this
+   * fails.
+   *
+   * @param rdn
+   *          The new RDN of the entry to be renamed.
+   * @return This modify DN request.
+   * @throws UnsupportedOperationException
+   *           If this modify DN request does not permit the new RDN to be set.
+   * @throws NullPointerException
+   *           If {@code rdn} was {@code null}.
+   */
+  ModifyDNRequest setNewRDN(RDN rdn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the new RDN of the entry to be renamed. The value of the old RDN is
+   * supplied when moving the entry to a new superior without changing its RDN.
+   * Attribute values of the new RDN not matching any attribute value of the
+   * entry are added to the entry, and an appropriate error is returned if this
+   * fails.
+   *
+   * @param rdn
+   *          The new RDN of the entry to be renamed.
+   * @return This modify DN request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code rdn} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this modify DN request does not permit the new RDN to be set.
+   * @throws NullPointerException
+   *           If {@code rdn} was {@code null}.
+   */
+  ModifyDNRequest setNewRDN(String rdn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of an existing entry that will become the
+   * immediate superior (parent) of the entry to be renamed. The server shall
+   * not dereference any aliases in locating the new superior entry.
+   *
+   * @param dn
+   *          The distinguished name of an existing entry that will become the
+   *          immediate superior (parent) of the entry to be renamed, may be
+   *          {@code null}.
+   * @return This modify DN request.
+   * @throws UnsupportedOperationException
+   *           If this modify DN request does not permit the new superior to be
+   *           set.
+   */
+  ModifyDNRequest setNewSuperior(DN dn) throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the distinguished name of an existing entry that will become the
+   * immediate superior (parent) of the entry to be renamed. The server shall
+   * not dereference any aliases in locating the new superior entry.
+   *
+   * @param dn
+   *          The distinguished name of an existing entry that will become the
+   *          immediate superior (parent) of the entry to be renamed, may be
+   *          {@code null}.
+   * @return This modify DN request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this modify DN request does not permit the new superior to be
+   *           set.
+   */
+  ModifyDNRequest setNewSuperior(String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequestImpl.java
new file mode 100644
index 0000000..7794f29
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyDNRequestImpl.java
@@ -0,0 +1,267 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.RDN;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Modify DN request implementation.
+ */
+final class ModifyDNRequestImpl extends AbstractRequestImpl<ModifyDNRequest>
+    implements ModifyDNRequest
+{
+  private DN name;
+
+  private DN newSuperior = null;
+
+  private RDN newRDN;
+
+  private boolean deleteOldRDN = false;
+
+
+
+  /**
+   * Creates a new modify DN request using the provided distinguished name and
+   * new RDN.
+   *
+   * @param name
+   *          The distinguished name of the entry to be renamed.
+   * @param newRDN
+   *          The new RDN of the entry.
+   * @throws NullPointerException
+   *           If {@code name} or {@code newRDN} was {@code null}.
+   */
+  ModifyDNRequestImpl(final DN name, final RDN newRDN)
+      throws NullPointerException
+  {
+    this.name = name;
+    this.newRDN = newRDN;
+  }
+
+
+
+  /**
+   * Creates a new modify DN request that is an exact copy of the provided
+   * request.
+   *
+   * @param modifyDNRequest
+   *          The modify DN request to be copied.
+   * @throws NullPointerException
+   *           If {@code modifyDNRequest} was {@code null} .
+   */
+  ModifyDNRequestImpl(final ModifyDNRequest modifyDNRequest)
+      throws NullPointerException
+  {
+    super(modifyDNRequest);
+    this.name = modifyDNRequest.getName();
+    this.newSuperior = modifyDNRequest.getNewSuperior();
+    this.newRDN = modifyDNRequest.getNewRDN();
+    this.deleteOldRDN = modifyDNRequest.isDeleteOldRDN();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
+  {
+    return v.visitChangeRecord(p, this);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public RDN getNewRDN()
+  {
+    return newRDN;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getNewSuperior()
+  {
+    return newSuperior;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isDeleteOldRDN()
+  {
+    return deleteOldRDN;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyDNRequestImpl setDeleteOldRDN(final boolean deleteOldRDN)
+      throws UnsupportedOperationException
+  {
+    this.deleteOldRDN = deleteOldRDN;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyDNRequest setName(final DN dn)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = dn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyDNRequest setName(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = DN.valueOf(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyDNRequest setNewRDN(final RDN rdn)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(rdn);
+    this.newRDN = rdn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyDNRequest setNewRDN(final String rdn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(rdn);
+    this.newRDN = RDN.valueOf(rdn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyDNRequest setNewSuperior(final DN dn)
+      throws UnsupportedOperationException
+  {
+    this.newSuperior = dn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyDNRequest setNewSuperior(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException
+  {
+    this.newSuperior = (dn != null) ? DN.valueOf(dn) : null;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ModifyDNRequest(name=");
+    builder.append(getName());
+    builder.append(", newRDN=");
+    builder.append(getNewRDN());
+    builder.append(", deleteOldRDN=");
+    builder.append(isDeleteOldRDN());
+    builder.append(", newSuperior=");
+    builder.append(String.valueOf(getNewSuperior()));
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  ModifyDNRequest getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequest.java
new file mode 100644
index 0000000..e5e719d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.ldif.ChangeRecord;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+
+
+/**
+ * The Modify operation allows a client to request that a modification of an
+ * entry be performed on its behalf by a server.
+ */
+public interface ModifyRequest extends Request, ChangeRecord
+{
+  /**
+   * {@inheritDoc}
+   */
+  <R, P> R accept(ChangeRecordVisitor<R, P> v, P p);
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ModifyRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Appends the provided modification to the list of modifications included
+   * with this modify request.
+   *
+   * @param modification
+   *          The modification to be performed.
+   * @return This modify request.
+   * @throws UnsupportedOperationException
+   *           If this modify request does not permit modifications to be added.
+   * @throws NullPointerException
+   *           If {@code modification} was {@code null}.
+   */
+  ModifyRequest addModification(Modification modification)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Appends the provided modification to the list of modifications included
+   * with this modify request.
+   * <p>
+   * If the attribute value is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param type
+   *          The type of modification to be performed.
+   * @param attributeDescription
+   *          The name of the attribute to be modified.
+   * @param values
+   *          The attribute values to be modified.
+   * @return This modify request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code attributeDescription} could not be decoded using the
+   *           default schema.
+   * @throws UnsupportedOperationException
+   *           If this modify request does not permit modifications to be added.
+   * @throws NullPointerException
+   *           If {@code type}, {@code attributeDescription}, or {@code value}
+   *           was {@code null}.
+   */
+  ModifyRequest addModification(ModificationType type,
+      String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns a {@code List} containing the modifications included with this
+   * modify request. The returned {@code List} may be modified if permitted by
+   * this modify request.
+   *
+   * @return A {@code List} containing the modifications.
+   */
+  List<Modification> getModifications();
+
+
+
+  /**
+   * Returns the distinguished name of the entry to be modified. The server
+   * shall not perform any alias dereferencing in determining the object to be
+   * modified.
+   *
+   * @return The distinguished name of the entry to be modified.
+   */
+  DN getName();
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be modified. The server shall
+   * not perform any alias dereferencing in determining the object to be
+   * modified.
+   *
+   * @param dn
+   *          The the distinguished name of the entry to be modified.
+   * @return This modify request.
+   * @throws UnsupportedOperationException
+   *           If this modify request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  ModifyRequest setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of the entry to be modified. The server shall
+   * not perform any alias dereferencing in determining the object to be
+   * modified.
+   *
+   * @param dn
+   *          The the distinguished name of the entry to be modified.
+   * @return This modify request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this modify request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  ModifyRequest setName(String dn) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequestImpl.java
new file mode 100644
index 0000000..0577a5c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/ModifyRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Modify request implementation.
+ */
+final class ModifyRequestImpl extends AbstractRequestImpl<ModifyRequest>
+    implements ModifyRequest
+{
+  private final List<Modification> changes = new LinkedList<Modification>();
+
+  private DN name;
+
+
+
+  /**
+   * Creates a new modify request using the provided distinguished name.
+   *
+   * @param name
+   *          The distinguished name of the entry to be modified.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  ModifyRequestImpl(final DN name) throws NullPointerException
+  {
+    this.name = name;
+  }
+
+
+
+  /**
+   * Creates a new modify request that is an exact copy of the provided
+   * request.
+   *
+   * @param modifyRequest
+   *          The modify request to be copied.
+   * @throws NullPointerException
+   *           If {@code modifyRequest} was {@code null} .
+   */
+  ModifyRequestImpl(final ModifyRequest modifyRequest)
+      throws NullPointerException
+  {
+    super(modifyRequest);
+    this.name = modifyRequest.getName();
+
+    // Deep copy.
+    for (Modification modification : modifyRequest.getModifications())
+    {
+      ModificationType type = modification.getModificationType();
+      Attribute attribute = new LinkedAttribute(modification.getAttribute());
+      Modification copy = new Modification(type, attribute);
+      this.changes.add(copy);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public <R, P> R accept(final ChangeRecordVisitor<R, P> v, final P p)
+  {
+    return v.visitChangeRecord(p, this);
+  }
+
+
+
+  public ModifyRequest addChange(final ModificationType type,
+      final String attributeDescription, final Object firstValue,
+      final Object... remainingValues)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyRequest addModification(final Modification change)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(change);
+    changes.add(change);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyRequest addModification(final ModificationType type,
+      final String attributeDescription, final Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(type, attributeDescription, values);
+    changes.add(new Modification(type, new LinkedAttribute(
+        attributeDescription, values)));
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public List<Modification> getModifications()
+  {
+    return changes;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyRequest setName(final DN dn)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = dn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ModifyRequest setName(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+    this.name = DN.valueOf(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ModifyRequest(dn=");
+    builder.append(getName());
+    builder.append(", changes=");
+    builder.append(getModifications());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  ModifyRequest getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequest.java
new file mode 100644
index 0000000..a08ac19
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequest.java
@@ -0,0 +1,276 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+import org.opends.sdk.responses.PasswordModifyExtendedResult;
+
+
+
+/**
+ * The password modify extended request as defined in RFC 3062. This operation
+ * allows directory clients to update user passwords. The user may or may not be
+ * associated with a directory entry. The user may or may not be represented as
+ * an LDAP DN. The user's password may or may not be stored in the directory. In
+ * addition, it includes support for requiring the user's current password as
+ * well as for generating a new password if none was provided.
+ *
+ * @see PasswordModifyExtendedResult
+ * @see <a href="http://tools.ietf.org/html/rfc3909">RFC 3062 - LDAP Password
+ *      Modify Extended Operation </a>
+ */
+public interface PasswordModifyExtendedRequest extends
+    ExtendedRequest<PasswordModifyExtendedResult>
+{
+
+  /**
+   * The OID for the password modify extended operation request.
+   */
+  public static final String OID = "1.3.6.1.4.1.4203.1.11.1";
+
+  /**
+   * A decoder which can be used to decode password modify extended operation
+   * requests.
+   */
+  public static final ExtendedRequestDecoder<PasswordModifyExtendedRequest,
+                                             PasswordModifyExtendedResult>
+    DECODER = new PasswordModifyExtendedRequestImpl.RequestDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  PasswordModifyExtendedRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the desired password for the user, or {@code null} if a new
+   * password should be generated.
+   *
+   * @return The desired password for the user, or {@code null} if a new
+   *         password should be generated.
+   */
+  ByteString getNewPassword();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * Returns the current password for the user, if known.
+   *
+   * @return The current password for the user, or {@code null} if the password
+   *         is not known.
+   */
+  ByteString getOldPassword();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResultDecoder<PasswordModifyExtendedResult> getResultDecoder();
+
+
+
+  /**
+   * Returns the identity of the user whose password is to be modified, or
+   * {@code null} if the request should be applied to the user currently
+   * associated with the session. The returned identity may or may not be a
+   * distinguished name.
+   *
+   * @return The identity of the user whose password is to be modified, or
+   *         {@code null} if the request should be applied to the user currently
+   *         associated with the session.
+   */
+  ByteString getUserIdentity();
+
+
+
+  /**
+   * Returns the identity of the user whose password is to be modified decoded
+   * as a UTF-8 string, or {@code null} if the request should be applied to the
+   * user currently associated with the session. The returned identity may or
+   * may not be a distinguished name.
+   *
+   * @return The identity of the user whose password is to be modified decoded
+   *         as a UTF-8 string, or {@code null} if the request should be applied
+   *         to the user currently associated with the session.
+   */
+  String getUserIdentityAsString();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * Sets the desired password for the user.
+   *
+   * @param newPassword
+   *          The desired password for the user, or {@code null} if a new
+   *          password should be generated.
+   * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the new
+   *           password to be set.
+   */
+  PasswordModifyExtendedRequest setNewPassword(ByteString newPassword)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the desired password for the user. The password will be converted to a
+   * UTF-8 octet string.
+   *
+   * @param newPassword
+   *          The desired password for the user, or {@code null} if a new
+   *          password should be generated.
+   * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the new
+   *           password to be set.
+   */
+  PasswordModifyExtendedRequest setNewPassword(char[] newPassword)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the current password for the user.
+   *
+   * @param oldPassword
+   *          The current password for the user, or {@code null} if the password
+   *          is not known.
+   * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the old
+   *           password to be set.
+   */
+  PasswordModifyExtendedRequest setOldPassword(ByteString oldPassword)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the current password for the user. The password will be converted to a
+   * UTF-8 octet string.
+   *
+   * @param oldPassword
+   *          The current password for the user, or {@code null} if the password
+   *          is not known.
+   * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the old
+   *           password to be set.
+   */
+  PasswordModifyExtendedRequest setOldPassword(char[] oldPassword)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the identity of the user whose password is to be modified. The
+   * identity may or may not be a distinguished name.
+   *
+   * @param userIdentity
+   *          The identity of the user whose password is to be modified, or
+   *          {@code null} if the request should be applied to the user
+   *          currently associated with the session.
+   * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the user
+   *           identity to be set.
+   */
+  PasswordModifyExtendedRequest setUserIdentity(ByteString userIdentity)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the identity of the user whose password is to be modified. The
+   * identity may or may not be a distinguished name. The identity will be
+   * converted to a UTF-8 octet string.
+   *
+   * @param userIdentity
+   *          The identity of the user whose password is to be modified, or
+   *          {@code null} if the request should be applied to the user
+   *          currently associated with the session.
+   * @return This password modify request.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended request does not permit the user
+   *           identity to be set.
+   */
+  PasswordModifyExtendedRequest setUserIdentity(String userIdentity)
+      throws UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java
new file mode 100644
index 0000000..add4b05
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PasswordModifyExtendedRequestImpl.java
@@ -0,0 +1,435 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST;
+import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
+
+import java.io.IOException;
+
+import org.opends.sdk.*;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.responses.*;
+
+
+
+/**
+ * Password modify extended request implementation.
+ */
+final class PasswordModifyExtendedRequestImpl
+    extends
+    AbstractExtendedRequest<PasswordModifyExtendedRequest, PasswordModifyExtendedResult>
+    implements PasswordModifyExtendedRequest
+{
+  static final class RequestDecoder
+      implements
+      ExtendedRequestDecoder<PasswordModifyExtendedRequest, PasswordModifyExtendedResult>
+  {
+    public PasswordModifyExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      final PasswordModifyExtendedRequest newRequest = new PasswordModifyExtendedRequestImpl();
+      if (request.getValue() != null)
+      {
+        try
+        {
+          final ASN1Reader reader = ASN1.getReader(request.getValue());
+          reader.readStartSequence();
+          if (reader.hasNextElement()
+              && (reader.peekType() == TYPE_PASSWORD_MODIFY_USER_ID))
+          {
+            newRequest.setUserIdentity(reader.readOctetStringAsString());
+          }
+          if (reader.hasNextElement()
+              && (reader.peekType() == TYPE_PASSWORD_MODIFY_OLD_PASSWORD))
+          {
+            newRequest.setOldPassword(reader.readOctetString());
+          }
+          if (reader.hasNextElement()
+              && (reader.peekType() == TYPE_PASSWORD_MODIFY_NEW_PASSWORD))
+          {
+            newRequest.setNewPassword(reader.readOctetString());
+          }
+          reader.readEndSequence();
+        }
+        catch (final IOException e)
+        {
+          final LocalizableMessage message = ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST
+              .get(getExceptionMessage(e));
+          throw DecodeException.error(message, e);
+        }
+      }
+
+      for (final Control control : request.getControls())
+      {
+        newRequest.addControl(control);
+      }
+
+      return newRequest;
+    }
+  }
+
+
+
+  private static final class ResultDecoder extends
+      AbstractExtendedResultDecoder<PasswordModifyExtendedResult>
+  {
+    public PasswordModifyExtendedResult newExtendedErrorResult(
+        final ResultCode resultCode, final String matchedDN,
+        final String diagnosticMessage)
+    {
+      return Responses.newPasswordModifyExtendedResult(resultCode)
+          .setMatchedDN(matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public PasswordModifyExtendedResult decodeExtendedResult(
+        final ExtendedResult result, final DecodeOptions options)
+        throws DecodeException
+    {
+      if (result instanceof PasswordModifyExtendedResult)
+      {
+        return (PasswordModifyExtendedResult) result;
+      }
+      else
+      {
+        final ResultCode resultCode = result.getResultCode();
+
+        final PasswordModifyExtendedResult newResult = Responses
+            .newPasswordModifyExtendedResult(resultCode).setMatchedDN(
+                result.getMatchedDN()).setDiagnosticMessage(
+                result.getDiagnosticMessage());
+
+        // TODO: Should we check to make sure OID is null?
+        final ByteString responseValue = result.getValue();
+        if (resultCode == ResultCode.SUCCESS && responseValue != null)
+        {
+          try
+          {
+            final ASN1Reader asn1Reader = ASN1.getReader(responseValue);
+            asn1Reader.readStartSequence();
+            if (asn1Reader.peekType() == TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD)
+            {
+              newResult.setGeneratedPassword(asn1Reader.readOctetString());
+            }
+            asn1Reader.readEndSequence();
+          }
+          catch (final IOException e)
+          {
+            final LocalizableMessage message = ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST
+                .get(getExceptionMessage(e));
+            throw DecodeException.error(message, e);
+          }
+        }
+
+        for (final Control control : result.getControls())
+        {
+          newResult.addControl(control);
+        }
+
+        return newResult;
+      }
+    }
+  }
+
+
+
+  /**
+   * The ASN.1 element type that will be used to encode the userIdentity
+   * component in a password modify extended request.
+   */
+  private static final byte TYPE_PASSWORD_MODIFY_USER_ID = (byte) 0x80;
+
+  /**
+   * The ASN.1 element type that will be used to encode the oldPasswd component
+   * in a password modify extended request.
+   */
+  private static final byte TYPE_PASSWORD_MODIFY_OLD_PASSWORD = (byte) 0x81;
+
+  /**
+   * The ASN.1 element type that will be used to encode the newPasswd component
+   * in a password modify extended request.
+   */
+  private static final byte TYPE_PASSWORD_MODIFY_NEW_PASSWORD = (byte) 0x82;
+
+  /**
+   * The ASN.1 element type that will be used to encode the genPasswd component
+   * in a password modify extended response.
+   */
+  private static final byte TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD = (byte) 0x80;
+
+  private ByteString userIdentity = null;
+
+  private ByteString oldPassword = null;
+
+  private ByteString newPassword = null;
+
+  private static final ExtendedResultDecoder<PasswordModifyExtendedResult>
+    RESULT_DECODER = new ResultDecoder();
+
+
+
+  // Instantiation via factory.
+  PasswordModifyExtendedRequestImpl()
+  {
+
+  }
+
+
+
+  /**
+   * Creates a new password modify extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param passwordModifyExtendedRequest
+   *          The password modify extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code passwordModifyExtendedRequest} was {@code null} .
+   */
+  PasswordModifyExtendedRequestImpl(
+      final PasswordModifyExtendedRequest passwordModifyExtendedRequest)
+      throws NullPointerException
+  {
+    super(passwordModifyExtendedRequest);
+    this.userIdentity = passwordModifyExtendedRequest.getUserIdentity();
+    this.oldPassword = passwordModifyExtendedRequest.getOldPassword();
+    this.newPassword = passwordModifyExtendedRequest.getNewPassword();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getNewPassword()
+  {
+    return newPassword;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getOldPassword()
+  {
+    return oldPassword;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<PasswordModifyExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getUserIdentity()
+  {
+    return userIdentity;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getUserIdentityAsString()
+  {
+    return userIdentity != null ? userIdentity.toString() : null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    final ByteStringBuilder buffer = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(buffer);
+
+    try
+    {
+      writer.writeStartSequence();
+      if (userIdentity != null)
+      {
+        writer.writeOctetString(TYPE_PASSWORD_MODIFY_USER_ID, userIdentity);
+      }
+      if (oldPassword != null)
+      {
+        writer.writeOctetString(TYPE_PASSWORD_MODIFY_OLD_PASSWORD, oldPassword);
+      }
+      if (newPassword != null)
+      {
+        writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD, newPassword);
+      }
+      writer.writeEndSequence();
+    }
+    catch (final IOException ioe)
+    {
+      // This should never happen unless there is a bug somewhere.
+      throw new RuntimeException(ioe);
+    }
+
+    return buffer.toByteString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedRequest setNewPassword(
+      final ByteString newPassword)
+  {
+    this.newPassword = newPassword;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedRequest setNewPassword(final char[] newPassword)
+  {
+    this.newPassword = (newPassword != null) ? ByteString.valueOf(newPassword)
+        : null;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedRequest setOldPassword(
+      final ByteString oldPassword)
+  {
+    this.oldPassword = oldPassword;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedRequest setOldPassword(final char[] oldPassword)
+  {
+    this.oldPassword = (oldPassword != null) ? ByteString.valueOf(oldPassword)
+        : null;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedRequest setUserIdentity(
+      final ByteString userIdentity)
+  {
+    this.userIdentity = userIdentity;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedRequest setUserIdentity(final String userIdentity)
+  {
+    this.userIdentity = (userIdentity != null) ? ByteString
+        .valueOf(userIdentity) : null;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordModifyExtendedRequest(requestName=");
+    builder.append(getOID());
+    builder.append(", userIdentity=");
+    builder.append(userIdentity);
+    builder.append(", oldPassword=");
+    builder.append(oldPassword);
+    builder.append(", newPassword=");
+    builder.append(newPassword);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequest.java
new file mode 100644
index 0000000..f49994c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequest.java
@@ -0,0 +1,229 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The Plain SASL bind request as defined in RFC 4616. This SASL mechanism
+ * allows a client to authenticate to the server with an authentication ID and
+ * password. This mechanism does not provide a security layer.
+ * <p>
+ * The authentication and optional authorization identity is specified using an
+ * authorization ID, or {@code authzId}, as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4616">RFC 4616 - The PLAIN Simple
+ *      Authentication and Security Layer (SASL) Mechanism </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public interface PlainSASLBindRequest extends SASLBindRequest
+{
+
+  /**
+   * The name of the SASL mechanism based on PLAIN authentication.
+   */
+  public static final String SASL_MECHANISM_NAME = "PLAIN";
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  PlainSASLBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication ID of the user. The authentication ID usually
+   * has the form "dn:" immediately followed by the distinguished name of the
+   * user, or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authentication ID of the user.
+   */
+  String getAuthenticationID();
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this SASL bind request
+   * as defined by the LDAP protocol, which is always {@code 0xA3}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * Returns the optional authorization ID of the user which represents an
+   * alternate authorization identity which should be used for subsequent
+   * operations performed on the connection. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authorization ID of the user, which may be {@code null}.
+   */
+  String getAuthorizationID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as,
+   * which is always the empty string for SASL authentication.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  String getName();
+
+
+
+  /**
+   * Returns the password of the user that the client wishes to bind as.
+   *
+   * @return The password of the user that the client wishes to bind as.
+   */
+  ByteString getPassword();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getSASLMechanism();
+
+
+
+  /**
+   * Sets the authentication ID of the user. The authentication ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authentication ID to be
+   *           set.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authenticationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   * @throws NullPointerException
+   *           If {@code authenticationID} was {@code null}.
+   */
+  PlainSASLBindRequest setAuthenticationID(String authenticationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the optional authorization ID of the user which represents an
+   * alternate authorization identity which should be used for subsequent
+   * operations performed on the connection. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authorizationID
+   *          The authorization ID of the user, which may be {@code null}.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the authorization ID to be
+   *           set.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   */
+  PlainSASLBindRequest setAuthorizationID(String authorizationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as, which
+   *          may be empty.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  PlainSASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the password of the user that the client wishes to bind as. The
+   * password will be converted to a UTF-8 octet string.
+   *
+   * @param password
+   *          The password of the user that the client wishes to bind as.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the password to be set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  PlainSASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequestImpl.java
new file mode 100644
index 0000000..f5ebe93
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/PlainSASLBindRequestImpl.java
@@ -0,0 +1,275 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.Responses;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Plain SASL bind request implementation.
+ */
+final class PlainSASLBindRequestImpl extends
+    AbstractSASLBindRequest<PlainSASLBindRequest> implements
+    PlainSASLBindRequest
+{
+  private final static class Client extends SASLBindClientImpl
+  {
+    private final SaslClient saslClient;
+    private final String authenticationID;
+    private final ByteString password;
+
+
+
+    private Client(final PlainSASLBindRequestImpl initialBindRequest,
+        final String serverName) throws ErrorResultException
+    {
+      super(initialBindRequest);
+
+      this.authenticationID = initialBindRequest.getAuthenticationID();
+      this.password = initialBindRequest.getPassword();
+
+      try
+      {
+        saslClient = Sasl.createSaslClient(
+            new String[] { SASL_MECHANISM_NAME }, initialBindRequest
+                .getAuthorizationID(), SASL_DEFAULT_PROTOCOL, serverName, null,
+            this);
+
+        if (saslClient.hasInitialResponse())
+        {
+          setNextSASLCredentials(saslClient.evaluateChallenge(new byte[0]));
+        }
+        else
+        {
+          setNextSASLCredentials((ByteString) null);
+        }
+      }
+      catch (final SaslException e)
+      {
+        throw ErrorResultException.wrap(Responses.newResult(
+            ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e));
+      }
+    }
+
+
+
+    @Override
+    public void dispose()
+    {
+      try
+      {
+        saslClient.dispose();
+      }
+      catch (final SaslException ignored)
+      {
+        // Ignore the SASL exception.
+      }
+    }
+
+
+
+    @Override
+    public boolean evaluateResult(final BindResult result)
+    {
+      return saslClient.isComplete();
+    }
+
+
+
+    @Override
+    void handle(final NameCallback callback)
+        throws UnsupportedCallbackException
+    {
+      callback.setName(authenticationID);
+    }
+
+
+
+    @Override
+    void handle(final PasswordCallback callback)
+        throws UnsupportedCallbackException
+    {
+      callback.setPassword(password.toString().toCharArray());
+    }
+  }
+
+
+
+  private String authenticationID;
+  private String authorizationID;
+
+  private ByteString password;
+
+
+
+  PlainSASLBindRequestImpl(final String authenticationID,
+      final ByteString password)
+  {
+    Validator.ensureNotNull(authenticationID, password);
+    this.authenticationID = authenticationID;
+    this.password = password;
+  }
+
+
+
+  /**
+   * Creates a new plain SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param plainSASLBindRequest
+   *          The plain SASL bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code plainSASLBindRequest} was {@code null} .
+   */
+  PlainSASLBindRequestImpl(
+      final PlainSASLBindRequest plainSASLBindRequest)
+      throws NullPointerException
+  {
+    super(plainSASLBindRequest);
+    this.authenticationID = plainSASLBindRequest.getAuthenticationID();
+    this.authorizationID = plainSASLBindRequest.getAuthorizationID();
+    this.password = plainSASLBindRequest.getPassword();
+  }
+
+
+
+  public BindClient createBindClient(final String serverName)
+      throws ErrorResultException
+  {
+    return new Client(this, serverName);
+  }
+
+
+
+  public String getAuthenticationID()
+  {
+    return authenticationID;
+  }
+
+
+
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+
+
+  public ByteString getPassword()
+  {
+    return password;
+  }
+
+
+
+  public String getSASLMechanism()
+  {
+    return SASL_MECHANISM_NAME;
+  }
+
+
+
+  public PlainSASLBindRequest setAuthenticationID(final String authenticationID)
+  {
+    Validator.ensureNotNull(authenticationID);
+    this.authenticationID = authenticationID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PlainSASLBindRequest setAuthorizationID(final String authorizationID)
+  {
+    this.authorizationID = authorizationID;
+    return this;
+  }
+
+
+
+  public PlainSASLBindRequest setPassword(final ByteString password)
+  {
+    Validator.ensureNotNull(password);
+    this.password = password;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PlainSASLBindRequest setPassword(final char[] password)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = ByteString.valueOf(password);
+    return this;
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PlainSASLBindRequest(bindDN=");
+    builder.append(getName());
+    builder.append(", authentication=SASL");
+    builder.append(", saslMechanism=");
+    builder.append(getSASLMechanism());
+    builder.append(", authenticationID=");
+    builder.append(authenticationID);
+    builder.append(", authorizationID=");
+    builder.append(authorizationID);
+    builder.append(", password=");
+    builder.append(password);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Request.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Request.java
new file mode 100644
index 0000000..8243a26
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Request.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The base class of all Requests provides methods for querying and manipulating
+ * the set of Controls included with a Request.
+ */
+public interface Request
+{
+
+  /**
+   * Adds the provided control to this request.
+   *
+   * @param control
+   *          The control to be added to this request.
+   * @return This request.
+   * @throws UnsupportedOperationException
+   *           If this request does not permit controls to be added.
+   * @throws NullPointerException
+   *           If {@code control} was {@code null}.
+   */
+  Request addControl(Control control) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Decodes and returns the first control in this request having an OID
+   * corresponding to the provided control decoder.
+   *
+   * @param <C>
+   *          The type of control to be decoded and returned.
+   * @param decoder
+   *          The control decoder.
+   * @param options
+   *          The set of decode options which should be used when decoding the
+   *          control.
+   * @return The decoded control, or {@code null} if the control is not included
+   *         with this request.
+   * @throws DecodeException
+   *           If the control could not be decoded because it was malformed in
+   *           some way (e.g. the control value was missing, or its content
+   *           could not be decoded).
+   * @throws NullPointerException
+   *           If {@code decoder} or {@code options} was {@code null}.
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws DecodeException, NullPointerException;
+
+
+
+  /**
+   * Returns a {@code List} containing the controls included with this request.
+   * The returned {@code List} may be modified if permitted by this request.
+   *
+   * @return A {@code List} containing the controls.
+   */
+  List<Control> getControls();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Requests.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Requests.java
new file mode 100644
index 0000000..47b2249
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/Requests.java
@@ -0,0 +1,1710 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import javax.net.ssl.SSLContext;
+import javax.security.auth.Subject;
+
+import org.opends.sdk.*;
+import org.opends.sdk.ldif.ChangeRecord;
+import org.opends.sdk.ldif.LDIFChangeRecordReader;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class contains various methods for creating and manipulating requests.
+ * <p>
+ * All copy constructors of the form {@code copyOfXXXRequest} perform deep
+ * copies of their request parameter. More specifically, any controls,
+ * modifications, and attributes contained within the response will be
+ * duplicated.
+ * <p>
+ * Similarly, all unmodifiable views of request returned by methods of the form
+ * {@code unmodifiableXXXRequest} return deep unmodifiable views of their
+ * request parameter. More specifically, any controls, modifications, and
+ * attributes contained within the returned request will be unmodifiable.
+ */
+public final class Requests
+{
+
+  // TODO: search request from LDAP URL.
+
+  // TODO: update request from persistent search result.
+
+  // TODO: synchronized requests?
+
+  /**
+   * Creates a new abandon request using the provided message ID.
+   *
+   * @param requestID
+   *          The request ID of the request to be abandoned.
+   * @return The new abandon request.
+   */
+  public static AbandonRequest newAbandonRequest(final int requestID)
+  {
+    return new AbandonRequestImpl(requestID);
+  }
+
+
+
+  /**
+   * Creates a new add request using the provided distinguished name.
+   *
+   * @param name
+   *          The distinguished name of the entry to be added.
+   * @return The new add request.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static AddRequest newAddRequest(final DN name)
+      throws NullPointerException
+  {
+    final Entry entry = new LinkedHashMapEntry().setName(name);
+    return new AddRequestImpl(entry);
+  }
+
+
+
+  /**
+   * Creates a new add request backed by the provided entry. Modifications made
+   * to {@code entry} will be reflected in the returned add request. The
+   * returned add request supports updates to its list of controls, as well as
+   * updates to the name and attributes if the underlying entry allows.
+   *
+   * @param entry
+   *          The entry to be added.
+   * @return The new add request.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  public static AddRequest newAddRequest(final Entry entry)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(entry);
+    return new AddRequestImpl(entry);
+  }
+
+
+
+  /**
+   * Creates a new add request using the provided distinguished name decoded
+   * using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the entry to be added.
+   * @return The new add request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static AddRequest newAddRequest(final String name)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    final Entry entry = new LinkedHashMapEntry().setName(name);
+    return new AddRequestImpl(entry);
+  }
+
+
+
+  /**
+   * Creates a new add request using the provided lines of LDIF decoded using
+   * the default schema.
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing an LDIF add change record or an LDIF
+   *          entry record.
+   * @return The new add request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  public static AddRequest newAddRequest(final String... ldifLines)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    // LDIF change record reader is tolerant to missing change types.
+    final ChangeRecord record = LDIFChangeRecordReader
+        .valueOfLDIFChangeRecord(ldifLines);
+
+    if (record instanceof AddRequest)
+    {
+      return (AddRequest) record;
+    }
+    else
+    {
+      // Wrong change type.
+      final LocalizableMessage message = WARN_READ_LDIF_RECORD_CHANGE_RECORD_WRONG_TYPE
+          .get("add");
+      throw new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  /**
+   * Creates a new anonymous SASL bind request having the provided trace string.
+   *
+   * @param traceString
+   *          The trace information, which has no semantic value, and can be
+   *          used by administrators in order to identify the user.
+   * @return The new anonymous SASL bind request.
+   * @throws NullPointerException
+   *           If {@code traceString} was {@code null}.
+   */
+  public static AnonymousSASLBindRequest newAnonymousSASLBindRequest(
+      final String traceString) throws NullPointerException
+  {
+    return new AnonymousSASLBindRequestImpl(traceString);
+  }
+
+
+
+  /**
+   * Creates a new cancel extended request using the provided message ID.
+   *
+   * @param requestID
+   *          The request ID of the request to be abandoned.
+   * @return The new cancel extended request.
+   */
+  public static CancelExtendedRequest newCancelExtendedRequest(
+      final int requestID)
+  {
+    return new CancelExtendedRequestImpl(requestID);
+  }
+
+
+
+  /**
+   * Creates a new change record (an add, delete, modify, or modify DN request)
+   * using the provided lines of LDIF decoded using the default schema.
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing an LDIF change record or an LDIF entry
+   *          record.
+   * @return The new change record.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  public static ChangeRecord newChangeRecord(final String... ldifLines)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    // LDIF change record reader is tolerant to missing change types.
+    return LDIFChangeRecordReader.valueOfLDIFChangeRecord(ldifLines);
+  }
+
+
+
+  /**
+   * Creates a new compare request using the provided distinguished name,
+   * attribute name, and assertion value.
+   *
+   * @param name
+   *          The distinguished name of the entry to be compared.
+   * @param attributeDescription
+   *          The name of the attribute to be compared.
+   * @param assertionValue
+   *          The assertion value to be compared.
+   * @return The new compare request.
+   * @throws NullPointerException
+   *           If {@code name}, {@code attributeDescription}, or
+   *           {@code assertionValue} was {@code null}.
+   */
+  public static CompareRequest newCompareRequest(final DN name,
+      final AttributeDescription attributeDescription,
+      final ByteString assertionValue) throws NullPointerException
+  {
+    Validator.ensureNotNull(name, attributeDescription, assertionValue);
+    return new CompareRequestImpl(name, attributeDescription, assertionValue);
+  }
+
+
+
+  /**
+   * Creates a new compare request using the provided distinguished name,
+   * attribute name, and assertion value decoded using the default schema.
+   * <p>
+   * If the assertion value is not an instance of {@code ByteString} then it
+   * will be converted using the {@link ByteString#valueOf(Object)} method.
+   *
+   * @param name
+   *          The distinguished name of the entry to be compared.
+   * @param attributeDescription
+   *          The name of the attribute to be compared.
+   * @param assertionValue
+   *          The assertion value to be compared.
+   * @return The new compare request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} or {@code attributeDescription} could not be
+   *           decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code name}, {@code attributeDescription}, or
+   *           {@code assertionValue} was {@code null}.
+   */
+  public static CompareRequest newCompareRequest(final String name,
+      final String attributeDescription, final Object assertionValue)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(name, attributeDescription, assertionValue);
+    return new CompareRequestImpl(DN.valueOf(name),
+        AttributeDescription.valueOf(attributeDescription),
+        ByteString.valueOf(assertionValue));
+  }
+
+
+
+  /**
+   * Creates a new CRAM-MD5 SASL bind request having the provided authentication
+   * ID and password.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user. The authentication ID usually
+   *          has the form "dn:" immediately followed by the distinguished name
+   *          of the user, or "u:" followed by a user ID string, but other forms
+   *          are permitted.
+   * @param password
+   *          The password of the user that the client wishes to bind as. The
+   *          password will be converted to a UTF-8 octet string.
+   * @return The new CRAM-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static CRAMMD5SASLBindRequest newCRAMMD5SASLBindRequest(
+      final String authenticationID, final ByteString password)
+      throws NullPointerException
+  {
+    return new CRAMMD5SASLBindRequestImpl(authenticationID, password);
+  }
+
+
+
+  /**
+   * Creates a new delete request using the provided distinguished name.
+   *
+   * @param name
+   *          The distinguished name of the entry to be deleted.
+   * @return The new delete request.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static DeleteRequest newDeleteRequest(final DN name)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(name);
+    return new DeleteRequestImpl(name);
+  }
+
+
+
+  /**
+   * Creates a new delete request using the provided distinguished name decoded
+   * using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the entry to be deleted.
+   * @return The new delete request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static DeleteRequest newDeleteRequest(final String name)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(name);
+    return new DeleteRequestImpl(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * Creates a new DIGEST-MD5 SASL bind request having the provided
+   * authentication ID and password, but no realm or authorization ID.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user. The authentication ID usually
+   *          has the form "dn:" immediately followed by the distinguished name
+   *          of the user, or "u:" followed by a user ID string, but other forms
+   *          are permitted.
+   * @param password
+   *          The password of the user that the client wishes to bind as. The
+   *          password will be converted to a UTF-8 octet string.
+   * @return The new DIGEST-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static DigestMD5SASLBindRequest newDigestMD5SASLBindRequest(
+      final String authenticationID, final ByteString password)
+      throws NullPointerException
+  {
+    return new DigestMD5SASLBindRequestImpl(authenticationID, password);
+  }
+
+
+
+  /**
+   * Creates a new External SASL bind request with no authorization ID.
+   *
+   * @return The new External SASL bind request.
+   */
+  public static ExternalSASLBindRequest newExternalSASLBindRequest()
+  {
+    return new ExternalSASLBindRequestImpl();
+  }
+
+
+
+  /**
+   * Creates a new generic bind request using an empty distinguished name,
+   * authentication type, and authentication information.
+   *
+   * @param authenticationType
+   *          The authentication mechanism identifier for this generic bind
+   *          request.
+   * @param authenticationValue
+   *          The authentication information for this generic bind request in a
+   *          form defined by the authentication mechanism.
+   * @return The new generic bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationValue} was {@code null}.
+   */
+  public static GenericBindRequest newGenericBindRequest(
+      final byte authenticationType, final ByteString authenticationValue)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(authenticationValue);
+    return new GenericBindRequestImpl("", authenticationType,
+        authenticationValue);
+  }
+
+
+
+  /**
+   * Creates a new generic bind request using the provided name, authentication
+   * type, and authentication information.
+   * <p>
+   * The LDAP protocol defines the Bind name to be a distinguished name, however
+   * some LDAP implementations have relaxed this constraint and allow other
+   * identities to be used, such as the user's email address.
+   *
+   * @param name
+   *          The name of the Directory object that the client wishes to bind as
+   *          (may be empty).
+   * @param authenticationType
+   *          The authentication mechanism identifier for this generic bind
+   *          request.
+   * @param authenticationValue
+   *          The authentication information for this generic bind request in a
+   *          form defined by the authentication mechanism.
+   * @return The new generic bind request.
+   * @throws NullPointerException
+   *           If {@code name} or {@code authenticationValue} was {@code null}.
+   */
+  public static GenericBindRequest newGenericBindRequest(final String name,
+      final byte authenticationType, final ByteString authenticationValue)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(name, authenticationValue);
+    return new GenericBindRequestImpl(name, authenticationType,
+        authenticationValue);
+  }
+
+
+
+  /**
+   * Creates a new generic extended request using the provided name and no
+   * value.
+   *
+   * @param requestName
+   *          The dotted-decimal representation of the unique OID corresponding
+   *          to this extended request.
+   * @return The new generic extended request.
+   * @throws NullPointerException
+   *           If {@code requestName} was {@code null}.
+   */
+  public static GenericExtendedRequest newGenericExtendedRequest(
+      final String requestName) throws NullPointerException
+  {
+    Validator.ensureNotNull(requestName);
+    return new GenericExtendedRequestImpl(requestName, null);
+  }
+
+
+
+  /**
+   * Creates a new generic extended request using the provided name and optional
+   * value.
+   *
+   * @param requestName
+   *          The dotted-decimal representation of the unique OID corresponding
+   *          to this extended request.
+   * @param requestValue
+   *          The content of this generic extended request in a form defined by
+   *          the extended operation, or {@code null} if there is no content.
+   * @return The new generic extended request.
+   * @throws NullPointerException
+   *           If {@code requestName} was {@code null}.
+   */
+  public static GenericExtendedRequest newGenericExtendedRequest(
+      final String requestName, final ByteString requestValue)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(requestName);
+    return new GenericExtendedRequestImpl(requestName, requestValue);
+  }
+
+
+
+  /**
+   * Creates a new GSSAPI SASL bind request having the provided authentication
+   * ID and password, but no realm, KDC address, or authorization ID.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user. The authentication ID usually
+   *          has the form "dn:" immediately followed by the distinguished name
+   *          of the user, or "u:" followed by a user ID string, but other forms
+   *          are permitted.
+   * @param password
+   *          The password of the user that the client wishes to bind as. The
+   *          password will be converted to a UTF-8 octet string.
+   * @return The new GSSAPI SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static GSSAPISASLBindRequest newGSSAPISASLBindRequest(
+      final String authenticationID, final ByteString password)
+      throws NullPointerException
+  {
+    return new GSSAPISASLBindRequestImpl(authenticationID, password);
+  }
+
+
+
+  /**
+   * Creates a new GSSAPI SASL bind request having the provided subject, but no
+   * authorization ID.
+   *
+   * @param subject
+   *          The Kerberos subject of the user to be authenticated.
+   * @return The new GSSAPI SASL bind request.
+   * @throws NullPointerException
+   *           If {@code subject} was {@code null}.
+   */
+  public static GSSAPISASLBindRequest newGSSAPISASLBindRequest(
+      final Subject subject) throws NullPointerException
+  {
+    return new GSSAPISASLBindRequestImpl(subject);
+  }
+
+
+
+  /**
+   * Creates a new modify DN request using the provided distinguished name and
+   * new RDN.
+   *
+   * @param name
+   *          The distinguished name of the entry to be renamed.
+   * @param newRDN
+   *          The new RDN of the entry.
+   * @return The new modify DN request.
+   * @throws NullPointerException
+   *           If {@code name} or {@code newRDN} was {@code null}.
+   */
+  public static ModifyDNRequest newModifyDNRequest(final DN name,
+      final RDN newRDN) throws NullPointerException
+  {
+    Validator.ensureNotNull(name, newRDN);
+    return new ModifyDNRequestImpl(name, newRDN);
+  }
+
+
+
+  /**
+   * Creates a new modify DN request using the provided distinguished name and
+   * new RDN decoded using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the entry to be renamed.
+   * @param newRDN
+   *          The new RDN of the entry.
+   * @return The new modify DN request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} or {@code newRDN} could not be decoded using the
+   *           default schema.
+   * @throws NullPointerException
+   *           If {@code name} or {@code newRDN} was {@code null}.
+   */
+  public static ModifyDNRequest newModifyDNRequest(final String name,
+      final String newRDN) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    Validator.ensureNotNull(name, newRDN);
+    return new ModifyDNRequestImpl(DN.valueOf(name), RDN.valueOf(newRDN));
+  }
+
+
+
+  /**
+   * Creates a new modify request using the provided distinguished name.
+   *
+   * @param name
+   *          The distinguished name of the entry to be modified.
+   * @return The new modify request.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static ModifyRequest newModifyRequest(final DN name)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(name);
+    return new ModifyRequestImpl(name);
+  }
+
+
+
+  /**
+   * Creates a new modify request containing a list of modifications which can
+   * be used to transform {@code fromEntry} into entry {@code toEntry}.
+   * <p>
+   * The modify request is reversible: it will contain only modifications of
+   * type {@link ModificationType#ADD ADD} and {@link ModificationType#DELETE
+   * DELETE}.
+   * <p>
+   * Finally, the modify request will use the distinguished name taken from
+   * {@code fromEntry}. Moreover, this method will not check to see if both
+   * {@code fromEntry} and {@code toEntry} have the same distinguished name.
+   * <p>
+   * This method is equivalent to:
+   *
+   * <pre>
+   * ModifyRequest request = Entries.diffEntries(fromEntry, toEntry);
+   * </pre>
+   *
+   * @param fromEntry
+   *          The source entry.
+   * @param toEntry
+   *          The destination entry.
+   * @return A modify request containing a list of modifications which can be
+   *         used to transform {@code fromEntry} into entry {@code toEntry}.
+   * @throws NullPointerException
+   *           If {@code fromEntry} or {@code toEntry} were {@code null}.
+   * @see Entries#diffEntries(Entry, Entry)
+   */
+  public static final ModifyRequest newModifyRequest(Entry fromEntry,
+      Entry toEntry) throws NullPointerException
+  {
+    return Entries.diffEntries(fromEntry, toEntry);
+  }
+
+
+
+  /**
+   * Creates a new modify request using the provided distinguished name decoded
+   * using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the entry to be modified.
+   * @return The new modify request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static ModifyRequest newModifyRequest(final String name)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(name);
+    return new ModifyRequestImpl(DN.valueOf(name));
+  }
+
+
+
+  /**
+   * Creates a new modify request using the provided lines of LDIF decoded using
+   * the default schema.
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing a single LDIF modify change record.
+   * @return The new modify request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  public static ModifyRequest newModifyRequest(final String... ldifLines)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    // LDIF change record reader is tolerant to missing change types.
+    final ChangeRecord record = LDIFChangeRecordReader
+        .valueOfLDIFChangeRecord(ldifLines);
+
+    if (record instanceof ModifyRequest)
+    {
+      return (ModifyRequest) record;
+    }
+    else
+    {
+      // Wrong change type.
+      final LocalizableMessage message = WARN_READ_LDIF_RECORD_CHANGE_RECORD_WRONG_TYPE
+          .get("modify");
+      throw new LocalizedIllegalArgumentException(message);
+    }
+  }
+
+
+
+  /**
+   * Creates a new password modify extended request, with no user identity, old
+   * password, or new password.
+   *
+   * @return The new password modify extended request.
+   */
+  public static PasswordModifyExtendedRequest newPasswordModifyExtendedRequest()
+  {
+    return new PasswordModifyExtendedRequestImpl();
+  }
+
+
+
+  /**
+   * Creates a new Plain SASL bind request having the provided authentication ID
+   * and password, but no authorization ID.
+   *
+   * @param authenticationID
+   *          The authentication ID of the user. The authentication ID usually
+   *          has the form "dn:" immediately followed by the distinguished name
+   *          of the user, or "u:" followed by a user ID string, but other forms
+   *          are permitted.
+   * @param password
+   *          The password of the user that the client wishes to bind as. The
+   *          password will be converted to a UTF-8 octet string.
+   * @return The new Plain SASL bind request.
+   * @throws NullPointerException
+   *           If {@code authenticationID} or {@code password} was {@code null}.
+   */
+  public static PlainSASLBindRequest newPlainSASLBindRequest(
+      final String authenticationID, final ByteString password)
+      throws NullPointerException
+  {
+    return new PlainSASLBindRequestImpl(authenticationID, password);
+  }
+
+
+
+  /**
+   * Creates a new search request using the provided distinguished name, scope,
+   * and filter, decoded using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed.
+   * @param scope
+   *          The scope of the search.
+   * @param filter
+   *          The filter that defines the conditions that must be fulfilled in
+   *          order for an entry to be returned.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with each entry.
+   * @return The new search request.
+   * @throws NullPointerException
+   *           If the {@code name}, {@code scope}, or {@code filter} were
+   *           {@code null}.
+   */
+  public static SearchRequest newSearchRequest(final DN name,
+      final SearchScope scope, final Filter filter,
+      final String... attributeDescriptions) throws NullPointerException
+  {
+    Validator.ensureNotNull(name, scope, filter);
+    final SearchRequest request = new SearchRequestImpl(name, scope, filter);
+    for (final String attributeDescription : attributeDescriptions)
+    {
+      request.addAttribute(attributeDescription);
+    }
+    return request;
+  }
+
+
+
+  /**
+   * Creates a new search request using the provided distinguished name, scope,
+   * and filter, decoded using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed.
+   * @param scope
+   *          The scope of the search.
+   * @param filter
+   *          The filter that defines the conditions that must be fulfilled in
+   *          order for an entry to be returned.
+   * @param attributeDescriptions
+   *          The names of the attributes to be included with each entry.
+   * @return The new search request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema, or
+   *           if {@code filter} is not a valid LDAP string representation of a
+   *           filter.
+   * @throws NullPointerException
+   *           If the {@code name}, {@code scope}, or {@code filter} were
+   *           {@code null}.
+   */
+  public static SearchRequest newSearchRequest(final String name,
+      final SearchScope scope, final String filter,
+      final String... attributeDescriptions)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(name, scope, filter);
+    final SearchRequest request = new SearchRequestImpl(DN.valueOf(name),
+        scope, Filter.valueOf(filter));
+    for (final String attributeDescription : attributeDescriptions)
+    {
+      request.addAttribute(attributeDescription);
+    }
+    return request;
+  }
+
+
+
+  /**
+   * Creates a new simple bind request having an empty name and password
+   * suitable for anonymous authentication.
+   *
+   * @return The new simple bind request.
+   */
+  public static SimpleBindRequest newSimpleBindRequest()
+  {
+    return new SimpleBindRequestImpl("", ByteString.empty());
+  }
+
+
+
+  /**
+   * Creates a new simple bind request having the provided name and password
+   * suitable for name/password authentication. The name will be decoded using
+   * the default schema.
+   * <p>
+   * The LDAP protocol defines the Bind name to be a distinguished name, however
+   * some LDAP implementations have relaxed this constraint and allow other
+   * identities to be used, such as the user's email address.
+   *
+   * @param name
+   *          The name of the Directory object that the client wishes to bind
+   *          as, which may be empty.
+   * @param password
+   *          The password of the Directory object that the client wishes to
+   *          bind as, which may be empty indicating that an unauthenticated
+   *          bind is to be performed.
+   * @return The new simple bind request.
+   * @throws NullPointerException
+   *           If {@code name} or {@code password} was {@code null}.
+   */
+  public static SimpleBindRequest newSimpleBindRequest(final String name,
+      final char[] password) throws NullPointerException
+  {
+    Validator.ensureNotNull(name, password);
+    return new SimpleBindRequestImpl(name, ByteString.valueOf(password));
+  }
+
+
+
+  /**
+   * Creates a new start TLS extended request which will use the provided SSL
+   * context.
+   *
+   * @param sslContext
+   *          The SSLContext that should be used when installing the TLS layer.
+   * @return The new start TLS extended request.
+   * @throws NullPointerException
+   *           If {@code sslContext} was {@code null}.
+   */
+  public static StartTLSExtendedRequest newStartTLSExtendedRequest(
+      final SSLContext sslContext) throws NullPointerException
+  {
+    return new StartTLSExtendedRequestImpl(sslContext);
+  }
+
+
+
+  /**
+   * Creates a new unbind request.
+   *
+   * @return The new unbind request.
+   */
+  public static UnbindRequest newUnbindRequest()
+  {
+    return new UnbindRequestImpl();
+  }
+
+
+
+  /**
+   * Creates a new Who Am I extended request.
+   *
+   * @return The new Who Am I extended request.
+   */
+  public static WhoAmIExtendedRequest newWhoAmIExtendedRequest()
+  {
+    return new WhoAmIExtendedRequestImpl();
+  }
+
+
+
+  /**
+   * Creates an unmodifiable abandon request of the provided request.
+   *
+   * @param request
+   *          The abandon request to be copied.
+   * @return The new abandon request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}
+   */
+  public static AbandonRequest unmodifiableAbandonRequest(
+      final AbandonRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableAbandonRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableAbandonRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable add request of the provided request.
+   *
+   * @param request
+   *          The add request to be copied.
+   * @return The new add request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static AddRequest unmodifiableAddRequest(final AddRequest request)
+      throws NullPointerException
+  {
+    if (request instanceof UnmodifiableAddRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableAddRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable anonymous SASL bind request of the provided
+   * request.
+   *
+   * @param request
+   *          The anonymous SASL bind request to be copied.
+   * @return The new anonymous SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static AnonymousSASLBindRequest unmodifiableAnonymousSASLBindRequest(
+      final AnonymousSASLBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableAnonymousSASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableAnonymousSASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable cancel extended request of the provided request.
+   *
+   * @param request
+   *          The cancel extended request to be copied.
+   * @return The new cancel extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static CancelExtendedRequest unmodifiableCancelExtendedRequest(
+      final CancelExtendedRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableCancelExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableCancelExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable compare request of the provided request.
+   *
+   * @param request
+   *          The compare request to be copied.
+   * @return The new compare request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static CompareRequest unmodifiableCompareRequest(
+      final CompareRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableCompareRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableCompareRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable CRAM MD5 SASL bind request of the provided request.
+   *
+   * @param request
+   *          The CRAM MD5 SASL bind request to be copied.
+   * @return The new CRAM-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static CRAMMD5SASLBindRequest unmodifiableCRAMMD5SASLBindRequest(
+      final CRAMMD5SASLBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableCRAMMD5SASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableCRAMMD5SASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable delete request of the provided request.
+   *
+   * @param request
+   *          The add request to be copied.
+   * @return The new delete request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static DeleteRequest unmodifiableDeleteRequest(
+      final DeleteRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableDeleteRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableDeleteRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable digest MD5 SASL bind request of the provided
+   * request.
+   *
+   * @param request
+   *          The digest MD5 SASL bind request to be copied.
+   * @return The new DIGEST-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static DigestMD5SASLBindRequest unmodifiableDigestMD5SASLBindRequest(
+      final DigestMD5SASLBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableDigestMD5SASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableDigestMD5SASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable external SASL bind request of the provided request.
+   *
+   * @param request
+   *          The external SASL bind request to be copied.
+   * @return The new External SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static ExternalSASLBindRequest unmodifiableExternalSASLBindRequest(
+      final ExternalSASLBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableExternalSASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableExternalSASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable generic bind request of the provided request.
+   *
+   * @param request
+   *          The generic bind request to be copied.
+   * @return The new generic bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static GenericBindRequest unmodifiableGenericBindRequest(
+      final GenericBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableGenericBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableGenericBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable generic extended request of the provided request.
+   *
+   * @param request
+   *          The generic extended request to be copied.
+   * @return The new generic extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static GenericExtendedRequest unmodifiableGenericExtendedRequest(
+      GenericExtendedRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableGenericExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableGenericExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable GSSAPI SASL bind request of the provided request.
+   *
+   * @param request
+   *          The GSSAPI SASL bind request to be copied.
+   * @return The new GSSAPI SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static GSSAPISASLBindRequest unmodifiableGSSAPISASLBindRequest(
+      final GSSAPISASLBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableGSSAPISASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableGSSAPISASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable modify DN request of the provided request.
+   *
+   * @param request
+   *          The modify DN request to be copied.
+   * @return The new modify DN request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static ModifyDNRequest unmodifiableModifyDNRequest(
+      final ModifyDNRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableModifyDNRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableModifyDNRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable modify request of the provided request.
+   *
+   * @param request
+   *          The modify request to be copied.
+   * @return The new modify request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static ModifyRequest unmodifiableModifyRequest(
+      final ModifyRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableModifyRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableModifyRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable password modify extended request of the provided
+   * request.
+   *
+   * @param request
+   *          The password modify extended request to be copied.
+   * @return The new password modify extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static PasswordModifyExtendedRequest unmodifiablePasswordModifyExtendedRequest(
+      final PasswordModifyExtendedRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiablePasswordModifyExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiablePasswordModifyExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable plain SASL bind request of the provided request.
+   *
+   * @param request
+   *          The plain SASL bind request to be copied.
+   * @return The new Plain SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static PlainSASLBindRequest unmodifiablePlainSASLBindRequest(
+      final PlainSASLBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiablePlainSASLBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiablePlainSASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable search request of the provided request.
+   *
+   * @param request
+   *          The search request to be copied.
+   * @return The new search request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static SearchRequest unmodifiableSearchRequest(
+      final SearchRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableSearchRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableSearchRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable simple bind request of the provided request.
+   *
+   * @param request
+   *          The simple bind request to be copied.
+   * @return The new simple bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static SimpleBindRequest unmodifiableSimpleBindRequest(
+      final SimpleBindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableSimpleBindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableSimpleBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable startTLS extended request of the provided request.
+   *
+   * @param request
+   *          The startTLS extended request to be copied.
+   * @return The new start TLS extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static StartTLSExtendedRequest unmodifiableStartTLSExtendedRequest(
+      final StartTLSExtendedRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableStartTLSExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableStartTLSExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable unbind request of the provided request.
+   *
+   * @param request
+   *          The unbind request to be copied.
+   * @return The new unbind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static UnbindRequest unmodifiableUnbindRequest(
+      final UnbindRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableUnbindRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableUnbindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable new Who Am I extended request of the provided
+   * request.
+   *
+   * @param request
+   *          The who Am I extended request to be copied.
+   * @return The new Who Am I extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static WhoAmIExtendedRequest unmodifiableWhoAmIExtendedRequest(
+      final WhoAmIExtendedRequest request) throws NullPointerException
+  {
+    if (request instanceof UnmodifiableWhoAmIExtendedRequestImpl)
+    {
+      return request;
+    }
+    return new UnmodifiableWhoAmIExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new abandon request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The abandon request to be copied.
+   * @return The new abandon request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}
+   */
+  public static AbandonRequest copyOfAbandonRequest(final AbandonRequest request)
+      throws NullPointerException
+  {
+    return new AbandonRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new add request that is an exact copy of the provided request.
+   *
+   * @param request
+   *          The add request to be copied.
+   * @return The new add request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static AddRequest copyOfAddRequest(final AddRequest request)
+      throws NullPointerException
+  {
+    return new AddRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new anonymous SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The anonymous SASL bind request to be copied.
+   * @return The new anonymous SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static AnonymousSASLBindRequest copyOfAnonymousSASLBindRequest(
+      final AnonymousSASLBindRequest request) throws NullPointerException
+  {
+    return new AnonymousSASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new cancel extended request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The cancel extended request to be copied.
+   * @return The new cancel extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static CancelExtendedRequest copyOfCancelExtendedRequest(
+      final CancelExtendedRequest request) throws NullPointerException
+  {
+    return new CancelExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new compare request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The compare request to be copied.
+   * @return The new compare request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static CompareRequest copyOfCompareRequest(final CompareRequest request)
+      throws NullPointerException
+  {
+    return new CompareRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new CRAM MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The CRAM MD5 SASL bind request to be copied.
+   * @return The new CRAM-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static CRAMMD5SASLBindRequest copyOfCRAMMD5SASLBindRequest(
+      final CRAMMD5SASLBindRequest request) throws NullPointerException
+  {
+    return new CRAMMD5SASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new delete request that is an exact copy of the provided request.
+   *
+   * @param request
+   *          The add request to be copied.
+   * @return The new delete request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static DeleteRequest copyOfDeleteRequest(final DeleteRequest request)
+      throws NullPointerException
+  {
+    return new DeleteRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new digest MD5 SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The digest MD5 SASL bind request to be copied.
+   * @return The new DIGEST-MD5 SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static DigestMD5SASLBindRequest copyOfDigestMD5SASLBindRequest(
+      final DigestMD5SASLBindRequest request) throws NullPointerException
+  {
+    return new DigestMD5SASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new external SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The external SASL bind request to be copied.
+   * @return The new External SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static ExternalSASLBindRequest copyOfExternalSASLBindRequest(
+      final ExternalSASLBindRequest request) throws NullPointerException
+  {
+    return new ExternalSASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new generic bind request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The generic bind request to be copied.
+   * @return The new generic bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static GenericBindRequest copyOfGenericBindRequest(
+      final GenericBindRequest request) throws NullPointerException
+  {
+    return new GenericBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new generic extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The generic extended request to be copied.
+   * @return The new generic extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static GenericExtendedRequest copyOfGenericExtendedRequest(
+      GenericExtendedRequest request) throws NullPointerException
+  {
+    return new GenericExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new GSSAPI SASL bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The GSSAPI SASL bind request to be copied.
+   * @return The new GSSAPI SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null}.
+   */
+  public static GSSAPISASLBindRequest copyOfGSSAPISASLBindRequest(
+      final GSSAPISASLBindRequest request) throws NullPointerException
+  {
+    return new GSSAPISASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new modify DN request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The modify DN request to be copied.
+   * @return The new modify DN request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static ModifyDNRequest copyOfModifyDNRequest(
+      final ModifyDNRequest request) throws NullPointerException
+  {
+    return new ModifyDNRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new modify request that is an exact copy of the provided request.
+   *
+   * @param request
+   *          The modify request to be copied.
+   * @return The new modify request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static ModifyRequest copyOfModifyRequest(final ModifyRequest request)
+      throws NullPointerException
+  {
+    return new ModifyRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new password modify extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The password modify extended request to be copied.
+   * @return The new password modify extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static PasswordModifyExtendedRequest copyOfPasswordModifyExtendedRequest(
+      final PasswordModifyExtendedRequest request) throws NullPointerException
+  {
+    return new PasswordModifyExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new plain SASL bind request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The plain SASL bind request to be copied.
+   * @return The new Plain SASL bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static PlainSASLBindRequest copyOfPlainSASLBindRequest(
+      final PlainSASLBindRequest request) throws NullPointerException
+  {
+    return new PlainSASLBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new search request that is an exact copy of the provided request.
+   *
+   * @param request
+   *          The search request to be copied.
+   * @return The new search request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static SearchRequest copyOfSearchRequest(final SearchRequest request)
+      throws NullPointerException
+  {
+    return new SearchRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new simple bind request that is an exact copy of the provided
+   * request.
+   *
+   * @param request
+   *          The simple bind request to be copied.
+   * @return The new simple bind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static SimpleBindRequest copyOfSimpleBindRequest(
+      final SimpleBindRequest request) throws NullPointerException
+  {
+    return new SimpleBindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new startTLS extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The startTLS extended request to be copied.
+   * @return The new start TLS extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static StartTLSExtendedRequest copyOfStartTLSExtendedRequest(
+      final StartTLSExtendedRequest request) throws NullPointerException
+  {
+    return new StartTLSExtendedRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new unbind request that is an exact copy of the provided request.
+   *
+   * @param request
+   *          The unbind request to be copied.
+   * @return The new unbind request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static UnbindRequest copyOfUnbindRequest(final UnbindRequest request)
+      throws NullPointerException
+  {
+    return new UnbindRequestImpl(request);
+  }
+
+
+
+  /**
+   * Creates a new Who Am I extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param request
+   *          The who Am I extended request to be copied.
+   * @return The new Who Am I extended request.
+   * @throws NullPointerException
+   *           If {@code request} was {@code null} .
+   */
+  public static WhoAmIExtendedRequest copyOfWhoAmIExtendedRequest(
+      final WhoAmIExtendedRequest request) throws NullPointerException
+  {
+    return new WhoAmIExtendedRequestImpl(request);
+  }
+
+
+
+  private Requests()
+  {
+    // Prevent instantiation.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindClientImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindClientImpl.java
new file mode 100644
index 0000000..d45f631
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindClientImpl.java
@@ -0,0 +1,275 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.INFO_SASL_UNSUPPORTED_CALLBACK;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.*;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.RealmCallback;
+import javax.security.sasl.RealmChoiceCallback;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Writer;
+
+
+
+/**
+ * SASL bind client implementation.
+ */
+class SASLBindClientImpl extends BindClientImpl implements CallbackHandler
+{
+  /**
+   * The name of the default protocol used.
+   */
+  static final String SASL_DEFAULT_PROTOCOL = "ldap";
+
+  private final String saslMechanism;
+
+
+
+  /**
+   * Creates a new abstract SASL bind client. The next bind request will be a
+   * copy of the provided initial bind request which should be updated in
+   * subsequent bind requests forming part of this authentication.
+   *
+   * @param initialBindRequest
+   *          The initial bind request.
+   */
+  SASLBindClientImpl(final SASLBindRequest initialBindRequest)
+  {
+    super(initialBindRequest);
+    this.saslMechanism = initialBindRequest.getSASLMechanism();
+  }
+
+
+
+  public final void handle(final Callback[] callbacks) throws IOException,
+      UnsupportedCallbackException
+  {
+    for (final Callback callback : callbacks)
+    {
+      if (callback instanceof NameCallback)
+      {
+        handle((NameCallback) callback);
+      }
+      else if (callback instanceof PasswordCallback)
+      {
+        handle((PasswordCallback) callback);
+      }
+      else if (callback instanceof AuthorizeCallback)
+      {
+        handle((AuthorizeCallback) callback);
+      }
+      else if (callback instanceof RealmCallback)
+      {
+        handle((RealmCallback) callback);
+      }
+      else if (callback instanceof RealmChoiceCallback)
+      {
+        handle((RealmChoiceCallback) callback);
+      }
+      else if (callback instanceof ChoiceCallback)
+      {
+        handle((ChoiceCallback) callback);
+      }
+      else if (callback instanceof ConfirmationCallback)
+      {
+        handle((ConfirmationCallback) callback);
+      }
+      else if (callback instanceof LanguageCallback)
+      {
+        handle((LanguageCallback) callback);
+      }
+      else if (callback instanceof TextInputCallback)
+      {
+        handle((TextInputCallback) callback);
+      }
+      else if (callback instanceof TextOutputCallback)
+      {
+        handle((TextOutputCallback) callback);
+      }
+      else
+      {
+        final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+            .get(saslMechanism, String.valueOf(callback));
+        throw new UnsupportedCallbackException(callback, message.toString());
+      }
+    }
+  }
+
+
+
+  void handle(final AuthorizeCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final ChoiceCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final ConfirmationCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final LanguageCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final NameCallback callback) throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final PasswordCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final RealmCallback callback) throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final RealmChoiceCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final TextInputCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  void handle(final TextOutputCallback callback)
+      throws UnsupportedCallbackException
+  {
+    final org.opends.sdk.LocalizableMessage message = INFO_SASL_UNSUPPORTED_CALLBACK
+        .get(saslMechanism, String.valueOf(callback));
+    throw new UnsupportedCallbackException(callback, message.toString());
+  }
+
+
+
+  /**
+   * Sets the SASL credentials to be used in the next bind request.
+   *
+   * @param saslCredentials
+   *          The SASL credentials to be used in the next bind request.
+   * @return A reference to this SASL bind client.
+   */
+  final BindClient setNextSASLCredentials(final byte[] saslCredentials)
+  {
+    final ByteString value = (saslCredentials != null) ? ByteString
+        .wrap(saslCredentials) : null;
+    return setNextSASLCredentials(value);
+  }
+
+
+
+  /**
+   * Sets the SASL credentials to be used in the next bind request.
+   *
+   * @param saslCredentials
+   *          The SASL credentials to be used in the next bind request.
+   * @return A reference to this SASL bind client.
+   */
+  final BindClient setNextSASLCredentials(final ByteString saslCredentials)
+  {
+    final ByteStringBuilder builder = new ByteStringBuilder();
+    final ASN1Writer writer = ASN1.getWriter(builder);
+
+    try
+    {
+      writer.writeOctetString(saslMechanism);
+      if (saslCredentials != null)
+      {
+        writer.writeOctetString(saslCredentials);
+      }
+    }
+    catch (final IOException ioe)
+    {
+      throw new RuntimeException("Error encoding SaslCredentials");
+    }
+
+    return setNextAuthenticationValue(builder.toByteString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindRequest.java
new file mode 100644
index 0000000..2851c73
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SASLBindRequest.java
@@ -0,0 +1,108 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The SASL authentication method of the Bind operation allows clients to
+ * authenticate using one of the SASL authentication methods defined in RFC
+ * 4513.
+ * <p>
+ * <TODO>finish doc.
+ */
+public interface SASLBindRequest extends BindRequest
+{
+  /**
+   * {@inheritDoc}
+   */
+  SASLBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this SASL bind request
+   * as defined by the LDAP protocol, which is always {@code 0xA3}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the name of the Directory object that the client wishes to bind as,
+   * which is always the empty string for SASL authentication.
+   *
+   * @return The name of the Directory object that the client wishes to bind as.
+   */
+  String getName();
+
+
+
+  /**
+   * Returns the SASL mechanism for this SASL bind request.
+   *
+   * @return The SASL mechanism for this bind request.
+   */
+  String getSASLMechanism();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequest.java
new file mode 100644
index 0000000..e0e965a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequest.java
@@ -0,0 +1,356 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The Search operation is used to request a server to return, subject to access
+ * controls and other restrictions, a set of entries matching a complex search
+ * criterion. This can be used to read attributes from a single entry, from
+ * entries immediately subordinate to a particular entry, or from a whole
+ * subtree of entries.
+ */
+public interface SearchRequest extends Request
+{
+  /**
+   * Adds the provided attribute name(s) to the list of attributes to be
+   * included with each entry that matches the search criteria. Attributes that
+   * are sub-types of listed attributes are implicitly included.
+   *
+   * @param attributeDescriptions
+   *          The name(s) of the attribute to be included with each entry.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit attribute names to be
+   *           added.
+   * @throws NullPointerException
+   *           If {@code attributeDescriptions} was {@code null}.
+   */
+  SearchRequest addAttribute(String... attributeDescriptions)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Returns a {@code List} containing the list of attributes to be included
+   * with each entry that matches the search criteria. Attributes that are
+   * sub-types of listed attributes are implicitly included. The returned
+   * {@code List} may be modified if permitted by this search request.
+   *
+   * @return A {@code List} containing the list of attributes.
+   */
+  List<String> getAttributes();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns an indication as to whether or not alias entries are to be
+   * dereferenced during the search.
+   *
+   * @return The alias dereferencing policy.
+   */
+  DereferenceAliasesPolicy getDereferenceAliasesPolicy();
+
+
+
+  /**
+   * Returns the filter that defines the conditions that must be fulfilled in
+   * order for an entry to be returned.
+   *
+   * @return The search filter.
+   */
+  Filter getFilter();
+
+
+
+  /**
+   * Returns the distinguished name of the base entry relative to which the
+   * search is to be performed.
+   *
+   * @return The distinguished name of the base entry.
+   */
+  DN getName();
+
+
+
+  /**
+   * Returns the scope of the search.
+   *
+   * @return The search scope.
+   */
+  SearchScope getScope();
+
+
+
+  /**
+   * Returns the size limit that should be used in order to restrict the maximum
+   * number of entries returned by the search.
+   * <p>
+   * A value of zero (the default) in this field indicates that no
+   * client-requested size limit restrictions are in effect. Servers may also
+   * enforce a maximum number of entries to return.
+   *
+   * @return The size limit that should be used in order to restrict the maximum
+   *         number of entries returned by the search.
+   */
+  int getSizeLimit();
+
+
+
+  /**
+   * Returns the time limit that should be used in order to restrict the maximum
+   * time (in seconds) allowed for the search.
+   * <p>
+   * A value of zero (the default) in this field indicates that no
+   * client-requested time limit restrictions are in effect for the search.
+   * Servers may also enforce a maximum time limit for the search.
+   *
+   * @return The time limit that should be used in order to restrict the maximum
+   *         time (in seconds) allowed for the search.
+   */
+  int getTimeLimit();
+
+
+
+  /**
+   * Indicates whether search results are to contain both attribute descriptions
+   * and values, or just attribute descriptions.
+   *
+   * @return {@code true} if only attribute descriptions (and not values) are to
+   *         be returned, or {@code false} (the default) if both attribute
+   *         descriptions and values are to be returned.
+   */
+  boolean isTypesOnly();
+
+
+
+  /**
+   * Sets the alias dereferencing policy to be used during the search.
+   *
+   * @param policy
+   *          The alias dereferencing policy to be used during the search.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the alias dereferencing
+   *           policy to be set.
+   * @throws NullPointerException
+   *           If {@code policy} was {@code null}.
+   */
+  SearchRequest setDereferenceAliasesPolicy(DereferenceAliasesPolicy policy)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the filter that defines the conditions that must be fulfilled in order
+   * for an entry to be returned.
+   *
+   * @param filter
+   *          The filter that defines the conditions that must be fulfilled in
+   *          order for an entry to be returned.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the filter to be set.
+   * @throws NullPointerException
+   *           If {@code filter} was {@code null}.
+   */
+  SearchRequest setFilter(Filter filter) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the filter that defines the conditions that must be fulfilled in order
+   * for an entry to be returned.
+   *
+   * @param filter
+   *          The filter that defines the conditions that must be fulfilled in
+   *          order for an entry to be returned.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the filter to be set.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code filter} is not a valid LDAP string representation of a
+   *           filter.
+   * @throws NullPointerException
+   *           If {@code filter} was {@code null}.
+   */
+  SearchRequest setFilter(String filter) throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of the base entry relative to which the search
+   * is to be performed.
+   *
+   * @param dn
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  SearchRequest setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the distinguished name of the base entry relative to which the search
+   * is to be performed.
+   *
+   * @param dn
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed.
+   * @return This search request.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code dn} could not be decoded using the default schema.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the distinguished name to
+   *           be set.
+   * @throws NullPointerException
+   *           If {@code dn} was {@code null}.
+   */
+  SearchRequest setName(String dn) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the scope of the search.
+   *
+   * @param scope
+   *          The scope of the search.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the scope to be set.
+   * @throws NullPointerException
+   *           If {@code scope} was {@code null}.
+   */
+  SearchRequest setScope(SearchScope scope)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the size limit that should be used in order to restrict the maximum
+   * number of entries returned by the search.
+   * <p>
+   * A value of zero (the default) in this field indicates that no
+   * client-requested size limit restrictions are in effect. Servers may also
+   * enforce a maximum number of entries to return.
+   *
+   * @param limit
+   *          The size limit that should be used in order to restrict the
+   *          maximum number of entries returned by the search.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the size limit to be set.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code limit} was negative.
+   */
+  SearchRequest setSizeLimit(int limit) throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException;
+
+
+
+  /**
+   * Sets the time limit that should be used in order to restrict the maximum
+   * time (in seconds) allowed for the search.
+   * <p>
+   * A value of zero (the default) in this field indicates that no
+   * client-requested time limit restrictions are in effect for the search.
+   * Servers may also enforce a maximum time limit for the search.
+   *
+   * @param limit
+   *          The time limit that should be used in order to restrict the
+   *          maximum time (in seconds) allowed for the search.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the time limit to be set.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code limit} was negative.
+   */
+  SearchRequest setTimeLimit(int limit) throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException;
+
+
+
+  /**
+   * Specifies whether search results are to contain both attribute descriptions
+   * and values, or just attribute descriptions.
+   *
+   * @param typesOnly
+   *          {@code true} if only attribute descriptions (and not values) are
+   *          to be returned, or {@code false} (the default) if both attribute
+   *          descriptions and values are to be returned.
+   * @return This search request.
+   * @throws UnsupportedOperationException
+   *           If this search request does not permit the types-only parameter
+   *           to be set.
+   */
+  SearchRequest setTypesOnly(boolean typesOnly)
+      throws UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequestImpl.java
new file mode 100644
index 0000000..7d13fc6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SearchRequestImpl.java
@@ -0,0 +1,371 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Search request implementation.
+ */
+final class SearchRequestImpl extends AbstractRequestImpl<SearchRequest>
+    implements SearchRequest
+{
+
+  private final List<String> attributes = new LinkedList<String>();
+
+  private DN name;
+
+  private DereferenceAliasesPolicy dereferenceAliasesPolicy =
+      DereferenceAliasesPolicy.NEVER;
+
+  private Filter filter;
+
+  private SearchScope scope;
+
+  private int sizeLimit = 0;
+
+  private int timeLimit = 0;
+
+  private boolean typesOnly = false;
+
+
+
+  /**
+   * Creates a new search request using the provided distinguished name, scope,
+   * and filter, decoded using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the base entry relative to which the
+   *          search is to be performed.
+   * @param scope
+   *          The scope of the search.
+   * @param filter
+   *          The filter that defines the conditions that must be fulfilled in
+   *          order for an entry to be returned.
+   * @throws NullPointerException
+   *           If the {@code name}, {@code scope}, or {@code filter} were
+   *           {@code null}.
+   */
+  SearchRequestImpl(final DN name, final SearchScope scope, final Filter filter)
+      throws NullPointerException
+  {
+    this.name = name;
+    this.scope = scope;
+    this.filter = filter;
+  }
+
+
+
+  /**
+   * Creates a new search request that is an exact copy of the provided
+   * request.
+   *
+   * @param searchRequest
+   *          The search request to be copied.
+   * @throws NullPointerException
+   *           If {@code searchRequest} was {@code null} .
+   */
+  SearchRequestImpl(final SearchRequest searchRequest)
+      throws NullPointerException
+  {
+    super(searchRequest);
+    this.attributes.addAll(searchRequest.getAttributes());
+    this.name = searchRequest.getName();
+    this.dereferenceAliasesPolicy = searchRequest.getDereferenceAliasesPolicy();
+    this.filter = searchRequest.getFilter();
+    this.scope = searchRequest.getScope();
+    this.sizeLimit = searchRequest.getSizeLimit();
+    this.timeLimit = searchRequest.getTimeLimit();
+    this.typesOnly = searchRequest.isTypesOnly();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest addAttribute(final String... attributeDescriptions)
+      throws NullPointerException
+  {
+    for (String attributeDescription : attributeDescriptions)
+    {
+      attributes.add(Validator.ensureNotNull(attributeDescription));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public List<String> getAttributes()
+  {
+    return attributes;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DereferenceAliasesPolicy getDereferenceAliasesPolicy()
+  {
+    return dereferenceAliasesPolicy;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Filter getFilter()
+  {
+    return filter;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchScope getScope()
+  {
+    return scope;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getSizeLimit()
+  {
+    return sizeLimit;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getTimeLimit()
+  {
+    return timeLimit;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isTypesOnly()
+  {
+    return typesOnly;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setDereferenceAliasesPolicy(
+      final DereferenceAliasesPolicy policy) throws NullPointerException
+  {
+    Validator.ensureNotNull(policy);
+
+    this.dereferenceAliasesPolicy = policy;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setFilter(final Filter filter)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(filter);
+
+    this.filter = filter;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setFilter(final String filter)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    this.filter = Filter.valueOf(filter);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setName(final DN dn) throws NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+
+    this.name = dn;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setName(final String dn)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(dn);
+
+    this.name = DN.valueOf(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setScope(final SearchScope scope)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(scope);
+
+    this.scope = scope;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setSizeLimit(final int limit)
+      throws LocalizedIllegalArgumentException
+  {
+    // FIXME: I18N error message.
+    Validator.ensureTrue(limit >= 0, "negative size limit");
+
+    this.sizeLimit = limit;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setTimeLimit(final int limit)
+      throws LocalizedIllegalArgumentException
+  {
+    // FIXME: I18N error message.
+    Validator.ensureTrue(limit >= 0, "negative time limit");
+
+    this.timeLimit = limit;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchRequest setTypesOnly(final boolean typesOnly)
+  {
+    this.typesOnly = typesOnly;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("SearchRequest(name=");
+    builder.append(getName());
+    builder.append(", scope=");
+    builder.append(getScope());
+    builder.append(", dereferenceAliasesPolicy=");
+    builder.append(getDereferenceAliasesPolicy());
+    builder.append(", sizeLimit=");
+    builder.append(getSizeLimit());
+    builder.append(", timeLimit=");
+    builder.append(getTimeLimit());
+    builder.append(", typesOnly=");
+    builder.append(isTypesOnly());
+    builder.append(", filter=");
+    builder.append(getFilter());
+    builder.append(", attributes=");
+    builder.append(getAttributes());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  SearchRequest getThis()
+  {
+    return this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequest.java
new file mode 100644
index 0000000..5316edf
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequest.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ErrorResultException;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The simple authentication method of the Bind Operation provides three
+ * authentication mechanisms:
+ * <ul>
+ * <li>An anonymous authentication mechanism, in which both the name and
+ * password are zero length.
+ * <li>An unauthenticated authentication mechanism using credentials consisting
+ * of a name and a zero length password.
+ * <li>A name/password authentication mechanism using credentials consisting of
+ * a name and a password.
+ * </ul>
+ */
+public interface SimpleBindRequest extends BindRequest
+{
+  /**
+   * {@inheritDoc}
+   */
+  SimpleBindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindClient createBindClient(String serverName) throws ErrorResultException;
+
+
+
+  /**
+   * Returns the authentication mechanism identifier for this simple bind
+   * request as defined by the LDAP protocol, which is always {@code 0x80}.
+   *
+   * @return The authentication mechanism identifier.
+   */
+  byte getAuthenticationType();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getName();
+
+
+
+  /**
+   * Returns the password of the Directory object that the client wishes to bind
+   * as. The password may be empty (but never {@code null}) when used for of
+   * anonymous or unauthenticated binds.
+   *
+   * @return The password of the Directory object that the client wishes to bind
+   *         as.
+   */
+  ByteString getPassword();
+
+
+
+  /**
+   * Sets the name of the Directory object that the client wishes to bind as.
+   * The name may be empty (but never {@code null} when used for of anonymous
+   * binds, or when using SASL authentication. The server shall not dereference
+   * any aliases in locating the named object.
+   * <p>
+   * The LDAP protocol defines the Bind name to be a distinguished name, however
+   * some LDAP implementations have relaxed this constraint and allow other
+   * identities to be used, such as the user's email address.
+   *
+   * @param name
+   *          The name of the Directory object that the client wishes to bind
+   *          as.
+   * @return This bind request.
+   * @throws UnsupportedOperationException
+   *           If this bind request does not permit the distinguished name to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  SimpleBindRequest setName(String name) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Sets the password of the Directory object that the client wishes to bind
+   * as. The password may be empty (but never {@code null}) when used for of
+   * anonymous or unauthenticated binds.
+   *
+   * @param password
+   *          The password of the Directory object that the client wishes to
+   *          bind as, which may be empty.
+   * @return This simple bind request.
+   * @throws UnsupportedOperationException
+   *           If this simple bind request does not permit the password to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  SimpleBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the password of the Directory object that the client wishes to bind
+   * as. The password will be converted to a UTF-8 octet string. The password
+   * may be empty (but never {@code null}) when used for of anonymous or
+   * unauthenticated binds. Subsequent modifications to the {@code password}
+   * array will not alter this bind request.
+   *
+   * @param password
+   *          The password of the Directory object that the client wishes to
+   *          bind as, which may be empty.
+   * @return This simple bind request.
+   * @throws UnsupportedOperationException
+   *           If this simple bind request does not permit the password to be
+   *           set.
+   * @throws NullPointerException
+   *           If {@code password} was {@code null}.
+   */
+  SimpleBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequestImpl.java
new file mode 100644
index 0000000..dc24eb6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/SimpleBindRequestImpl.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.TYPE_AUTHENTICATION_SIMPLE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ErrorResultException;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Simple bind request implementation.
+ */
+final class SimpleBindRequestImpl extends
+    AbstractBindRequest<SimpleBindRequest> implements SimpleBindRequest
+{
+  private ByteString password = ByteString.empty();
+
+  private String name = "".intern();
+
+
+
+  /**
+   * Creates a new simple bind request having the provided name and password
+   * suitable for name/password authentication.
+   *
+   * @param name
+   *          The name of the Directory object that the client wishes to bind
+   *          as, which may be empty.
+   * @param password
+   *          The password of the Directory object that the client wishes to
+   *          bind as, which may be empty indicating that an unauthenticated
+   *          bind is to be performed.
+   * @throws NullPointerException
+   *           If {@code name} or {@code password} was {@code null}.
+   */
+  SimpleBindRequestImpl(final String name, final ByteString password)
+      throws NullPointerException
+  {
+    this.name = name;
+    this.password = password;
+  }
+
+
+
+  /**
+   * Creates a new simple bind request that is an exact copy of the
+   * provided request.
+   *
+   * @param simpleBindRequest
+   *          The simple bind request to be copied.
+   * @throws NullPointerException
+   *           If {@code simpleBindRequest} was {@code null} .
+   */
+  SimpleBindRequestImpl(final SimpleBindRequest simpleBindRequest)
+      throws NullPointerException
+  {
+    super(simpleBindRequest);
+    this.name = simpleBindRequest.getName();
+    this.password = simpleBindRequest.getPassword();
+  }
+
+
+
+  public BindClient createBindClient(final String serverName)
+      throws ErrorResultException
+  {
+    return new BindClientImpl(this).setNextAuthenticationValue(password);
+  }
+
+
+
+  public byte getAuthenticationType()
+  {
+    return TYPE_AUTHENTICATION_SIMPLE;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getName()
+  {
+    return name;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getPassword()
+  {
+    return password;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SimpleBindRequest setName(final String name)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(name);
+    this.name = name;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SimpleBindRequest setPassword(final ByteString password)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = password;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SimpleBindRequest setPassword(final char[] password)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(password);
+    this.password = ByteString.valueOf(password);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("SimpleBindRequest(name=");
+    builder.append(getName());
+    builder.append(", authentication=simple");
+    builder.append(", password=");
+    builder.append(getPassword());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequest.java
new file mode 100644
index 0000000..abe4270
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequest.java
@@ -0,0 +1,202 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import javax.net.ssl.SSLContext;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.responses.ExtendedResult;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+
+
+
+/**
+ * The start TLS extended request as defined in RFC 4511. The Start Transport
+ * Layer Security (StartTLS) operation's purpose is to initiate installation of
+ * a TLS layer.
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight
+ *      Directory Access Protocol (LDAP): The Protocol </a>
+ */
+public interface StartTLSExtendedRequest extends
+    ExtendedRequest<ExtendedResult>
+{
+
+  /**
+   * The OID for the start TLS extended operation request.
+   */
+  public static final String OID = "1.3.6.1.4.1.1466.20037";
+
+  /**
+   * A decoder which can be used to decode start TLS extended operation
+   * requests.
+   */
+  public static final ExtendedRequestDecoder<StartTLSExtendedRequest,
+                                             ExtendedResult> DECODER =
+    new StartTLSExtendedRequestImpl.RequestDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  StartTLSExtendedRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResultDecoder<ExtendedResult> getResultDecoder();
+
+
+
+  /**
+   * Returns the SSLContext that should be used when installing the TLS layer.
+   *
+   * @return The SSLContext that should be used when installing the TLS layer.
+   */
+  SSLContext getSSLContext();
+
+
+
+  /**
+   * Adds the protocol versions enabled for secure connections with the
+   * Directory Server.
+   *
+   * The protocols must be supported by the SSLContext specified in
+   * {@link #setSSLContext(SSLContext)}. Following a successful call to
+   * this method, only the protocols listed in the protocols parameter are
+   * enabled for use.
+   *
+   * @param protocols Names of all the protocols to enable.
+   * @return A reference to this LDAP connection options.
+   * @throws UnsupportedOperationException
+   *           If this start TLS extended request does not permit the enabled
+   *           protocols to be set.
+   */
+  StartTLSExtendedRequest addEnabledProtocol(String... protocols)
+      throws UnsupportedOperationException;
+
+
+  /**
+   * Adds the cipher suites enabled for secure connections with the
+   * Directory Server.
+   *
+   * The suites must be supported by the SSLContext specified in
+   * {@link #setSSLContext(SSLContext)}. Following a successful call to
+   * this method, only the suites listed in the protocols parameter are
+   * enabled for use.
+   *
+   * @param suites Names of all the suites to enable.
+   * @return A reference to this LDAP connection options.
+   * @throws UnsupportedOperationException
+   *           If this start TLS extended request does not permit the enabled
+   *           cipher suites to be set.
+   */
+  StartTLSExtendedRequest addEnabledCipherSuite(String... suites)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Returns the names of the protocol versions which are currently enabled
+   * for secure connections with the Directory Server.
+   *
+   * @return an array of protocols or empty set if the default protocols
+   * are to be used.
+   */
+  List<String> getEnabledProtocols();
+
+
+
+  /**
+   * Returns the names of the protocol versions which are currently enabled
+   * for secure connections with the Directory Server.
+   *
+   * @return an array of protocols or empty set if the default protocols
+   * are to be used.
+   */
+  List<String> getEnabledCipherSuites();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * Sets the SSLContext that should be used when installing the TLS layer.
+   *
+   * @param sslContext
+   *          The SSLContext that should be used when installing the TLS layer.
+   * @return This startTLS request.
+   */
+  StartTLSExtendedRequest setSSLContext(SSLContext sslContext);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java
new file mode 100644
index 0000000..2d0c2c3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/StartTLSExtendedRequestImpl.java
@@ -0,0 +1,280 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import javax.net.ssl.SSLContext;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.responses.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+import java.util.*;
+
+
+/**
+ * Start TLS extended request implementation.
+ */
+final class StartTLSExtendedRequestImpl extends
+    AbstractExtendedRequest<StartTLSExtendedRequest, ExtendedResult> implements
+    StartTLSExtendedRequest
+{
+  static final class RequestDecoder implements
+      ExtendedRequestDecoder<StartTLSExtendedRequest, ExtendedResult>
+  {
+
+    public StartTLSExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      // TODO: Check the OID and that the value is not present.
+      final StartTLSExtendedRequest newRequest =
+          new StartTLSExtendedRequestImpl();
+      for (final Control control : request.getControls())
+      {
+        newRequest.addControl(control);
+      }
+      return newRequest;
+    }
+  }
+
+
+
+  private static final class ResultDecoder extends
+      AbstractExtendedResultDecoder<ExtendedResult>
+  {
+    public GenericExtendedResult newExtendedErrorResult(
+        final ResultCode resultCode, final String matchedDN,
+        final String diagnosticMessage)
+    {
+      return Responses.newGenericExtendedResult(resultCode).setMatchedDN(
+          matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public ExtendedResult decodeExtendedResult(final ExtendedResult result,
+        final DecodeOptions options) throws DecodeException
+    {
+      // TODO: Should we check oid is NOT null and matches but
+      // value is null?
+      return result;
+    }
+  }
+
+
+
+  private SSLContext sslContext;
+
+  /**
+   * The list of cipher suite
+   */
+  private List<String> enabledCipherSuites = new LinkedList<String>();
+
+  /**
+   * the list of protocols
+   */
+  private List<String> enabledProtocols = new LinkedList<String>();
+
+  // No need to expose this.
+  private static final ExtendedResultDecoder<ExtendedResult> RESULT_DECODER =
+      new ResultDecoder();
+
+
+
+  StartTLSExtendedRequestImpl(final SSLContext sslContext)
+  {
+    Validator.ensureNotNull(sslContext);
+    this.sslContext = sslContext;
+  }
+
+
+
+  /**
+   * Creates a new startTLS extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param startTLSExtendedRequest
+   *          The startTLS extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code startTLSExtendedRequest} was {@code null} .
+   */
+  StartTLSExtendedRequestImpl(
+      final StartTLSExtendedRequest startTLSExtendedRequest)
+      throws NullPointerException
+  {
+    super(startTLSExtendedRequest);
+    this.sslContext = startTLSExtendedRequest.getSSLContext();
+    this.enabledCipherSuites.addAll(
+        startTLSExtendedRequest.getEnabledCipherSuites());
+    this.enabledProtocols.addAll(startTLSExtendedRequest.getEnabledProtocols());
+  }
+
+
+
+  // Prevent instantiation.
+  private StartTLSExtendedRequestImpl()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<ExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SSLContext getSSLContext()
+  {
+    return sslContext;
+  }
+
+
+
+  /**
+   * {@inheritDoc}}
+   */
+  public StartTLSExtendedRequest addEnabledProtocol(String... protocols)
+  {
+    for (final String protocol : protocols)
+    {
+      this.enabledProtocols.add(Validator.ensureNotNull(protocol));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}}
+   */
+  public StartTLSExtendedRequest addEnabledCipherSuite(String... suites)
+  {
+    for (final String suite : suites)
+    {
+      this.enabledCipherSuites.add(Validator.ensureNotNull(suite));
+    }
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}}
+   */
+  public List<String> getEnabledProtocols()
+  {
+    return this.enabledProtocols;
+  }
+
+
+
+  /**
+   * {@inheritDoc}}
+   */
+  public List<String> getEnabledCipherSuites()
+  {
+    return this.enabledCipherSuites;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public StartTLSExtendedRequest setSSLContext(final SSLContext sslContext)
+  {
+    Validator.ensureNotNull(sslContext);
+    this.sslContext = sslContext;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("StartTLSExtendedRequest(requestName=");
+    builder.append(getOID());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequest.java
new file mode 100644
index 0000000..861e260
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The Unbind operation allows a client to terminate an LDAP session.
+ */
+public interface UnbindRequest extends Request
+{
+  /**
+   * {@inheritDoc}
+   */
+  UnbindRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequestImpl.java
new file mode 100644
index 0000000..3c91a43
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnbindRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+/**
+ * Unbind request implementation.
+ */
+final class UnbindRequestImpl extends AbstractRequestImpl<UnbindRequest>
+    implements UnbindRequest
+{
+
+  /**
+   * Creates a new unbind request.
+   */
+  UnbindRequestImpl()
+  {
+    // Do nothing.
+  }
+
+
+
+  /**
+   * Creates a new unbind request that is an exact copy of the provided
+   * request.
+   *
+   * @param unbindRequest
+   *          The unbind request to be copied.
+   * @throws NullPointerException
+   *           If {@code unbindRequest} was {@code null} .
+   */
+  UnbindRequestImpl(final UnbindRequest unbindRequest)
+      throws NullPointerException
+  {
+    super(unbindRequest);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("UnbindRequest(controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  UnbindRequest getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java
new file mode 100644
index 0000000..3d058e6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAbandonRequestImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+/**
+ * Unmodifiable abandon request implementation.
+ */
+final class UnmodifiableAbandonRequestImpl
+    extends AbstractUnmodifiableRequest<AbandonRequest>
+    implements AbandonRequest
+{
+  UnmodifiableAbandonRequestImpl(AbandonRequest request) {
+    super(request);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getRequestID() {
+    return impl.getRequestID();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public AbandonRequest setRequestID(int id)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java
new file mode 100644
index 0000000..5e081d4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAddRequestImpl.java
@@ -0,0 +1,201 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Iterables;
+import org.opends.sdk.*;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+import java.util.Collection;
+
+/**
+ * Unmodifiable add request implementation.
+ */
+final class UnmodifiableAddRequestImpl
+    extends AbstractUnmodifiableRequest<AddRequest>
+    implements AddRequest
+{
+  private static final Function<Attribute, Attribute, Void>
+      UNMODIFIABLE_ATTRIBUTE_FUNCTION =
+      new Function<Attribute, Attribute, Void>()
+  {
+
+    public Attribute apply(final Attribute value, final Void p)
+    {
+      return Attributes.unmodifiableAttribute(value);
+    }
+
+  };
+
+  UnmodifiableAddRequestImpl(AddRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public boolean addAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean addAttribute(Attribute attribute,
+                             Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest addAttribute(String attributeDescription,
+                                 Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest clearAttributes()
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean containsAttribute(Attribute attribute,
+                               Collection<ByteString> missingValues)
+      throws NullPointerException {
+    return impl.containsAttribute(attribute, missingValues);
+  }
+
+  public boolean containsAttribute(String attributeDescription,
+                                   Object... values)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    return impl.containsAttribute(attributeDescription, values);
+  }
+
+  public Iterable<Attribute> getAllAttributes() {
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
+        .getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Iterable<Attribute> getAllAttributes(
+      AttributeDescription attributeDescription)
+      throws NullPointerException {
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
+        .getAllAttributes(attributeDescription),
+        UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Iterable<Attribute> getAllAttributes(
+      String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
+        .getAllAttributes(attributeDescription),
+        UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Attribute getAttribute(
+      AttributeDescription attributeDescription)
+      throws NullPointerException {
+    final Attribute attribute =
+        impl.getAttribute(attributeDescription);
+    if (attribute != null)
+    {
+      return Attributes.unmodifiableAttribute(attribute);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  public Attribute getAttribute(String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    final Attribute attribute =
+        impl.getAttribute(attributeDescription);
+    if (attribute != null)
+    {
+      return Attributes.unmodifiableAttribute(attribute);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  public int getAttributeCount() {
+    return impl.getAttributeCount();
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public boolean removeAttribute(Attribute attribute,
+                               Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean removeAttribute(
+      AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest removeAttribute(String attributeDescription,
+                                    Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean replaceAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest replaceAttribute(String attributeDescription,
+                                     Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public AddRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java
new file mode 100644
index 0000000..38701cb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableAnonymousSASLBindRequestImpl.java
@@ -0,0 +1,51 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+/**
+ * Unmodifiable anonymous SASL bind request implementation.
+ */
+final class UnmodifiableAnonymousSASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<AnonymousSASLBindRequest> implements
+    AnonymousSASLBindRequest
+{
+  UnmodifiableAnonymousSASLBindRequestImpl(AnonymousSASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getTraceString() {
+    return impl.getTraceString();
+  }
+
+  @Override
+  public AnonymousSASLBindRequest setTraceString(String traceString)
+      throws NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java
new file mode 100644
index 0000000..8f0d2da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable CRAM-MD5 SASL bind request implementation.
+ */
+final class UnmodifiableCRAMMD5SASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<CRAMMD5SASLBindRequest> implements
+    CRAMMD5SASLBindRequest
+{
+  UnmodifiableCRAMMD5SASLBindRequestImpl(CRAMMD5SASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public CRAMMD5SASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public CRAMMD5SASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public CRAMMD5SASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java
new file mode 100644
index 0000000..48770d7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCancelExtendedRequestImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.responses.ExtendedResult;
+
+/**
+ * Unmodifiable cancel extended request implementation.
+ */
+final class UnmodifiableCancelExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <CancelExtendedRequest, ExtendedResult>
+    implements CancelExtendedRequest
+{
+  UnmodifiableCancelExtendedRequestImpl(
+      CancelExtendedRequest impl) {
+    super(impl);
+  }
+
+  public int getRequestID() {
+    return impl.getRequestID();
+  }
+
+  public CancelExtendedRequest setRequestID(int id)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java
new file mode 100644
index 0000000..7fad857
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableCompareRequestImpl.java
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.AttributeDescription;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable compare request implementation.
+ */
+final class UnmodifiableCompareRequestImpl
+    extends AbstractUnmodifiableRequest<CompareRequest>
+    implements CompareRequest
+{
+  UnmodifiableCompareRequestImpl(CompareRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getAssertionValue() {
+    return impl.getAssertionValue();
+  }
+
+  public String getAssertionValueAsString() {
+    return impl.getAssertionValueAsString();
+  }
+
+  public AttributeDescription getAttributeDescription() {
+    return impl.getAttributeDescription();
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public CompareRequest setAssertionValue(ByteString value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setAssertionValue(Object value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setAttributeDescription(
+      AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setAttributeDescription(
+      String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public CompareRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java
new file mode 100644
index 0000000..c91efb4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDeleteRequestImpl.java
@@ -0,0 +1,63 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+/**
+ * Unmodifiable delete request implementation.
+ */
+final class UnmodifiableDeleteRequestImpl
+    extends AbstractUnmodifiableRequest<DeleteRequest>
+    implements DeleteRequest
+{
+  UnmodifiableDeleteRequestImpl(DeleteRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public DeleteRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public DeleteRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java
new file mode 100644
index 0000000..94aef03
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java
@@ -0,0 +1,165 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unmodifiable digest-MD5 SASL bind request implementation.
+ */
+final class UnmodifiableDigestMD5SASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<DigestMD5SASLBindRequest> implements
+    DigestMD5SASLBindRequest
+{
+  UnmodifiableDigestMD5SASLBindRequestImpl(DigestMD5SASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest addAdditionalAuthParam(String name,
+                                                         String value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest addQOP(String... qopValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Map<String, String> getAdditionalAuthParams() {
+    return Collections.unmodifiableMap(impl.getAdditionalAuthParams());
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return impl.getAuthorizationID();
+  }
+
+  @Override
+  public String getCipher() {
+    return impl.getCipher();
+  }
+
+  @Override
+  public int getMaxReceiveBufferSize() {
+    return impl.getMaxReceiveBufferSize();
+  }
+
+  @Override
+  public int getMaxSendBufferSize() {
+    return impl.getMaxSendBufferSize();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public List<String> getQOPs() {
+    return Collections.unmodifiableList(impl.getQOPs());
+  }
+
+  @Override
+  public String getRealm() {
+    return impl.getRealm();
+  }
+
+  @Override
+  public boolean isServerAuth() {
+    return impl.isServerAuth();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setCipher(String cipher)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setMaxReceiveBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setMaxSendBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setRealm(String realm)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public DigestMD5SASLBindRequest setServerAuth(boolean serverAuth)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java
new file mode 100644
index 0000000..cc596e2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableExternalSASLBindRequestImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable external SASL bind request implementation.
+ */
+final class UnmodifiableExternalSASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<ExternalSASLBindRequest> implements
+    ExternalSASLBindRequest
+{
+  UnmodifiableExternalSASLBindRequestImpl(ExternalSASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return  impl.getAuthorizationID();
+  }
+
+  @Override
+  public ExternalSASLBindRequest setAuthorizationID(String authorizationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java
new file mode 100644
index 0000000..0f4a683
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGSSAPISASLBindRequestImpl.java
@@ -0,0 +1,175 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+import javax.security.auth.Subject;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Unmodifiable GSSAPI SASL bind request implementation.
+ */
+final class UnmodifiableGSSAPISASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<GSSAPISASLBindRequest> implements
+    GSSAPISASLBindRequest
+{
+  UnmodifiableGSSAPISASLBindRequestImpl(GSSAPISASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public GSSAPISASLBindRequest addAdditionalAuthParam(String name, String value)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Map<String, String> getAdditionalAuthParams() {
+    return Collections.unmodifiableMap(impl.getAdditionalAuthParams());
+  }
+
+  @Override
+  public GSSAPISASLBindRequest addQOP(String... qopValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return impl.getAuthorizationID();
+  }
+
+  @Override
+  public String getKDCAddress() {
+    return impl.getKDCAddress();
+  }
+
+  @Override
+  public int getMaxReceiveBufferSize() {
+    return impl.getMaxReceiveBufferSize();
+  }
+
+  @Override
+  public int getMaxSendBufferSize() {
+    return impl.getMaxSendBufferSize();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public List<String> getQOPs() {
+    return Collections.unmodifiableList(impl.getQOPs());
+  }
+
+  @Override
+  public String getRealm() {
+    return impl.getRealm();
+  }
+
+  @Override
+  public Subject getSubject() {
+    return impl.getSubject();
+  }
+
+  @Override
+  public boolean isServerAuth() {
+    return impl.isServerAuth();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setAuthenticationID(String authenticationID)
+      throws LocalizedIllegalArgumentException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setKDCAddress(String address)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setMaxReceiveBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setMaxSendBufferSize(int size)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setRealm(String realm)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setServerAuth(boolean serverAuth)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GSSAPISASLBindRequest setSubject(Subject subject)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.java
new file mode 100644
index 0000000..2308a85
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericBindRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable generic bind request implementation.
+ */
+final class UnmodifiableGenericBindRequestImpl
+    extends AbstractUnmodifiableBindRequest<GenericBindRequest>
+    implements GenericBindRequest
+{
+  UnmodifiableGenericBindRequestImpl(GenericBindRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getAuthenticationValue() {
+    return impl.getAuthenticationValue();
+  }
+
+  public GenericBindRequest setAuthenticationType(byte type)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public GenericBindRequest setAuthenticationValue(ByteString bytes)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public GenericBindRequest setName(String name)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java
new file mode 100644
index 0000000..b17d854
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableGenericExtendedRequestImpl.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.responses.GenericExtendedResult;
+
+/**
+ * Unmodifiable generic extended request implementation.
+ */
+final class UnmodifiableGenericExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <GenericExtendedRequest, GenericExtendedResult>
+    implements GenericExtendedRequest
+{
+  UnmodifiableGenericExtendedRequestImpl(GenericExtendedRequest impl) {
+    super(impl);
+  }
+
+  public GenericExtendedRequest setOID(String oid)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public GenericExtendedRequest setValue(ByteString bytes)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java
new file mode 100644
index 0000000..7231be6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyDNRequestImpl.java
@@ -0,0 +1,103 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.RDN;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+/**
+ * Unmodifiable modify DN request implementation.
+ */
+final class UnmodifiableModifyDNRequestImpl
+    extends AbstractUnmodifiableRequest<ModifyDNRequest>
+    implements ModifyDNRequest
+{
+  UnmodifiableModifyDNRequestImpl(ModifyDNRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public RDN getNewRDN() {
+    return impl.getNewRDN();
+  }
+
+  public DN getNewSuperior() {
+    return impl.getNewSuperior();
+  }
+
+  public boolean isDeleteOldRDN() {
+    return impl.isDeleteOldRDN();
+  }
+
+  public ModifyDNRequest setDeleteOldRDN(boolean deleteOldRDN)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewRDN(RDN rdn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewRDN(String rdn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewSuperior(DN dn)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyDNRequest setNewSuperior(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.java
new file mode 100644
index 0000000..f871a40
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableModifyRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.*;
+import org.opends.sdk.ldif.ChangeRecordVisitor;
+
+import com.sun.opends.sdk.util.Collections2;
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Functions;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unmodifiable modify request implementation.
+ */
+final class UnmodifiableModifyRequestImpl
+    extends AbstractUnmodifiableRequest<ModifyRequest>
+    implements ModifyRequest
+{
+  UnmodifiableModifyRequestImpl(ModifyRequest impl) {
+    super(impl);
+  }
+
+  public <R, P> R accept(ChangeRecordVisitor<R, P> v, P p) {
+    return v.visitChangeRecord(p, this);
+  }
+
+  public ModifyRequest addModification(Modification modification)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyRequest addModification(ModificationType type,
+                                       String attributeDescription,
+                                       Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public List<Modification> getModifications()
+  {
+    // We need to make all attributes unmodifiable as well.
+    Function<Modification, Modification, Void> function =
+      new Function<Modification, Modification, Void>()
+    {
+
+      public Modification apply(Modification value, Void p)
+      {
+        ModificationType type = value.getModificationType();
+        Attribute attribute = Attributes.unmodifiableAttribute(value
+            .getAttribute());
+        return new Modification(type, attribute);
+      }
+
+    };
+
+    List<Modification> unmodifiableModifications = Collections2.transformedList(
+        impl.getModifications(), function,
+        Functions.<Modification> identityFunction());
+    return Collections.unmodifiableList(unmodifiableModifications);
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public ModifyRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public ModifyRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java
new file mode 100644
index 0000000..44a61b8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePasswordModifyExtendedRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.responses.PasswordModifyExtendedResult;
+
+/**
+ * Unmodifiable password modify extended request implementation.
+ */
+final class UnmodifiablePasswordModifyExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <PasswordModifyExtendedRequest, PasswordModifyExtendedResult>
+    implements PasswordModifyExtendedRequest
+{
+  UnmodifiablePasswordModifyExtendedRequestImpl(
+      PasswordModifyExtendedRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getNewPassword() {
+    return impl.getNewPassword();
+  }
+
+  public ByteString getOldPassword() {
+    return impl.getOldPassword();
+  }
+
+  public ByteString getUserIdentity() {
+    return impl.getUserIdentity();
+  }
+
+  public String getUserIdentityAsString() {
+    return impl.getUserIdentityAsString();
+  }
+
+  public PasswordModifyExtendedRequest setNewPassword(ByteString newPassword)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setNewPassword(char[] newPassword) {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setOldPassword(ByteString oldPassword)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setOldPassword(char[] oldPassword) {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setUserIdentity(
+      ByteString userIdentity) {
+    throw new UnsupportedOperationException();
+  }
+
+  public PasswordModifyExtendedRequest setUserIdentity(String userIdentity) {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.java
new file mode 100644
index 0000000..79b03c4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiablePlainSASLBindRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable plain SASL bind request implementation.
+ */
+final class UnmodifiablePlainSASLBindRequestImpl extends
+    AbstractUnmodifiableSASLBindRequest<PlainSASLBindRequest> implements
+    PlainSASLBindRequest
+{
+  UnmodifiablePlainSASLBindRequestImpl(PlainSASLBindRequest impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getAuthenticationID() {
+    return impl.getAuthenticationID();
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return impl.getAuthorizationID();
+  }
+
+  @Override
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  @Override
+  public PlainSASLBindRequest setAuthenticationID(String authenticationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException,
+      NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public PlainSASLBindRequest setAuthorizationID(String authorizationID)
+      throws UnsupportedOperationException, LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public PlainSASLBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public PlainSASLBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java
new file mode 100644
index 0000000..29c740f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSearchRequestImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.*;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unmodifiable search request implementation.
+ */
+final class UnmodifiableSearchRequestImpl
+    extends AbstractUnmodifiableRequest<SearchRequest>
+    implements SearchRequest
+{
+  UnmodifiableSearchRequestImpl(SearchRequest impl) {
+    super(impl);
+  }
+
+  public SearchRequest addAttribute(String... attributeDescriptions)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public List<String> getAttributes() {
+    return Collections.unmodifiableList(impl.getAttributes());
+  }
+
+  public DereferenceAliasesPolicy getDereferenceAliasesPolicy() {
+    return impl.getDereferenceAliasesPolicy();
+  }
+
+  public Filter getFilter() {
+    return impl.getFilter();
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public SearchScope getScope() {
+    return impl.getScope();
+  }
+
+  public int getSizeLimit() {
+    return impl.getSizeLimit();
+  }
+
+  public int getTimeLimit() {
+    return impl.getTimeLimit();
+  }
+
+  public boolean isTypesOnly() {
+    return impl.isTypesOnly();
+  }
+
+  public SearchRequest setDereferenceAliasesPolicy(
+      DereferenceAliasesPolicy policy)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setFilter(Filter filter)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setFilter(String filter)
+      throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setScope(SearchScope scope)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setSizeLimit(int limit)
+      throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setTimeLimit(int limit)
+      throws UnsupportedOperationException,
+      LocalizedIllegalArgumentException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchRequest setTypesOnly(boolean typesOnly)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.java
new file mode 100644
index 0000000..0f143b6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableSimpleBindRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable simple bind request implementation.
+ */
+final class UnmodifiableSimpleBindRequestImpl
+    extends AbstractUnmodifiableBindRequest<SimpleBindRequest>
+    implements SimpleBindRequest
+{
+  UnmodifiableSimpleBindRequestImpl(SimpleBindRequest impl) {
+    super(impl);
+  }
+
+  public ByteString getPassword() {
+    return impl.getPassword();
+  }
+
+  public SimpleBindRequest setName(String name)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SimpleBindRequest setPassword(ByteString password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SimpleBindRequest setPassword(char[] password)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.java
new file mode 100644
index 0000000..8f14d81
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableStartTLSExtendedRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.responses.ExtendedResult;
+
+import javax.net.ssl.SSLContext;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unmodifiable start TLS extended request implementation.
+ */
+final class UnmodifiableStartTLSExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <StartTLSExtendedRequest, ExtendedResult>
+    implements StartTLSExtendedRequest
+{
+  UnmodifiableStartTLSExtendedRequestImpl(StartTLSExtendedRequest impl) {
+    super(impl);
+  }
+
+  public SSLContext getSSLContext() {
+    return impl.getSSLContext();
+  }
+
+  public StartTLSExtendedRequest addEnabledProtocol(String... protocols) {
+    throw new UnsupportedOperationException();
+  }
+
+  public StartTLSExtendedRequest addEnabledCipherSuite(String... suites) {
+    throw new UnsupportedOperationException();
+  }
+
+  public List<String> getEnabledProtocols() {
+    return Collections.unmodifiableList(impl.getEnabledProtocols());
+  }
+
+  public List<String> getEnabledCipherSuites() {
+    return Collections.unmodifiableList(impl.getEnabledCipherSuites());
+  }
+
+  public StartTLSExtendedRequest setSSLContext(SSLContext sslContext) {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java
new file mode 100644
index 0000000..823ce66
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableUnbindRequestImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+/**
+ * Unmodifiable unbind request implementation.
+ */
+final class UnmodifiableUnbindRequestImpl
+    extends AbstractUnmodifiableRequest<UnbindRequest>
+    implements UnbindRequest
+{
+  UnmodifiableUnbindRequestImpl(UnbindRequest impl) {
+    super(impl);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java
new file mode 100644
index 0000000..1d94ee2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/UnmodifiableWhoAmIExtendedRequestImpl.java
@@ -0,0 +1,43 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+import org.opends.sdk.responses.WhoAmIExtendedResult;
+
+/**
+ * Unmodifiable Who Am I extended request implementation.
+ */
+final class UnmodifiableWhoAmIExtendedRequestImpl
+    extends AbstractUnmodifiableExtendedRequest
+    <WhoAmIExtendedRequest, WhoAmIExtendedResult>
+    implements WhoAmIExtendedRequest
+{
+  UnmodifiableWhoAmIExtendedRequestImpl(WhoAmIExtendedRequest impl) {
+    super(impl);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequest.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequest.java
new file mode 100644
index 0000000..f03262c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequest.java
@@ -0,0 +1,133 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.responses.ExtendedResultDecoder;
+import org.opends.sdk.responses.WhoAmIExtendedResult;
+
+
+
+/**
+ *The who am I extended request as defined in RFC 4532. This operation allows
+ * clients to obtain the primary authorization identity, in its primary form,
+ * that the server has associated with the user or application entity.
+ * <p>
+ * This operation may preferable to the Authorization Identity Controls
+ * mechanism defined in RFC 3829, which uses Bind request and response controls
+ * to request and return the authorization identity. Bind controls are not
+ * protected by security layers established by the Bind operation that includes
+ * them. While it is possible to establish security layers using StartTLS prior
+ * to the Bind operation, it is often desirable to use security layers
+ * established by the Bind operation. An extended operation sent after a Bind
+ * operation is protected by the security layers established by the Bind
+ * operation.
+ *
+ * @see WhoAmIExtendedResult
+ * @see org.opends.sdk.controls.AuthorizationIdentityRequestControl
+ * @see <a href="http://tools.ietf.org/html/rfc4532">RFC 4532 - Lightweight
+ *      Directory Access Protocol (LDAP) "Who am I?" Operation </a>
+ * @see <a href="http://tools.ietf.org/html/rfc3829">RFC 3829 - Lightweight
+ *      Directory Access Protocol (LDAP) Authorization Identity Request and
+ *      Response Controls </a>
+ */
+public interface WhoAmIExtendedRequest extends
+    ExtendedRequest<WhoAmIExtendedResult>
+{
+
+  /**
+   * The OID for the who am I extended operation request.
+   */
+  public static final String OID = "1.3.6.1.4.1.4203.1.11.3";
+
+  /**
+   * A decoder which can be used to decode who am I extended operation requests.
+   */
+  public static final ExtendedRequestDecoder<WhoAmIExtendedRequest,
+                                             WhoAmIExtendedResult> DECODER =
+    new WhoAmIExtendedRequestImpl.RequestDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  WhoAmIExtendedRequest addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResultDecoder<WhoAmIExtendedResult> getResultDecoder();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.java
new file mode 100644
index 0000000..bec193f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/WhoAmIExtendedRequestImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.responses.*;
+
+
+
+/**
+ * Who Am I extended request implementation.
+ */
+final class WhoAmIExtendedRequestImpl extends
+    AbstractExtendedRequest<WhoAmIExtendedRequest, WhoAmIExtendedResult>
+    implements WhoAmIExtendedRequest
+{
+
+  static final class RequestDecoder implements
+      ExtendedRequestDecoder<WhoAmIExtendedRequest, WhoAmIExtendedResult>
+  {
+
+    public WhoAmIExtendedRequest decodeExtendedRequest(
+        final ExtendedRequest<?> request, final DecodeOptions options)
+        throws DecodeException
+    {
+      // TODO: Check the OID and that the value is not present.
+      final WhoAmIExtendedRequest newRequest = new WhoAmIExtendedRequestImpl();
+      for (final Control control : request.getControls())
+      {
+        newRequest.addControl(control);
+      }
+      return newRequest;
+    }
+  }
+
+
+
+  private static final class ResultDecoder extends
+      AbstractExtendedResultDecoder<WhoAmIExtendedResult>
+  {
+    public WhoAmIExtendedResult newExtendedErrorResult(
+        final ResultCode resultCode, final String matchedDN,
+        final String diagnosticMessage)
+    {
+      return Responses.newWhoAmIExtendedResult(resultCode).setMatchedDN(
+          matchedDN).setDiagnosticMessage(diagnosticMessage);
+    }
+
+
+
+    public WhoAmIExtendedResult decodeExtendedResult(
+        final ExtendedResult result, final DecodeOptions options)
+        throws DecodeException
+    {
+      if (result instanceof WhoAmIExtendedResult)
+      {
+        return (WhoAmIExtendedResult) result;
+      }
+      else
+      {
+        final WhoAmIExtendedResult newResult = Responses
+            .newWhoAmIExtendedResult(result.getResultCode()).setMatchedDN(
+                result.getMatchedDN()).setDiagnosticMessage(
+                result.getDiagnosticMessage());
+
+        final ByteString responseValue = result.getValue();
+        if (responseValue != null)
+        {
+          try
+          {
+            newResult.setAuthorizationID(responseValue.toString());
+          }
+          catch (final LocalizedIllegalArgumentException e)
+          {
+            throw DecodeException.error(e.getMessageObject());
+          }
+        }
+
+        for (final Control control : result.getControls())
+        {
+          newResult.addControl(control);
+        }
+
+        return newResult;
+      }
+    }
+  }
+
+
+
+  // No need to expose this.
+  private static final ExtendedResultDecoder<WhoAmIExtendedResult>
+    RESULT_DECODER = new ResultDecoder();
+
+
+
+  // Prevent instantiation.
+  WhoAmIExtendedRequestImpl()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * Creates a new Who Am I extended request that is an exact copy of the
+   * provided request.
+   *
+   * @param whoAmIExtendedRequest
+   *          The who Am I extended request to be copied.
+   * @throws NullPointerException
+   *           If {@code whoAmIExtendedRequest} was {@code null} .
+   */
+  WhoAmIExtendedRequestImpl(
+      final WhoAmIExtendedRequest whoAmIExtendedRequest)
+      throws NullPointerException
+  {
+    super(whoAmIExtendedRequest);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return OID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ExtendedResultDecoder<WhoAmIExtendedResult> getResultDecoder()
+  {
+    return RESULT_DECODER;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("WhoAmIExtendedRequest(requestName=");
+    builder.append(getOID());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/package-info.java
new file mode 100755
index 0000000..cf35739
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/requests/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes and interfaces for core LDAP requests.
+ */
+package org.opends.sdk.requests;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResult.java
new file mode 100644
index 0000000..12e5cec
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResult.java
@@ -0,0 +1,143 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ResultCode;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An abstract Extended result which can be used as the basis for implementing
+ * new Extended operations.
+ *
+ * @param <S>
+ *          The type of Extended result.
+ */
+public abstract class AbstractExtendedResult<S extends ExtendedResult>
+    extends AbstractResultImpl<S> implements ExtendedResult
+{
+
+  /**
+   * Creates a new extended result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  protected AbstractExtendedResult(final ResultCode resultCode)
+      throws NullPointerException
+  {
+    super(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new extended result that is an exact copy of the provided
+   * result.
+   *
+   * @param extendedResult
+   *          The extended result to be copied.
+   * @throws NullPointerException
+   *           If {@code extendedResult} was {@code null} .
+   */
+  protected AbstractExtendedResult(ExtendedResult extendedResult)
+      throws NullPointerException
+  {
+    super(extendedResult);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract boolean hasValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("ExtendedResult(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", responseName=");
+    builder.append(getOID() == null ? "" : getOID());
+    if (hasValue())
+    {
+      builder.append(", responseValue=");
+      StaticUtils.toHexPlusAscii(getValue(), builder, 4);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @SuppressWarnings("unchecked")
+  final S getThis()
+  {
+    return (S) this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResultDecoder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResultDecoder.java
new file mode 100644
index 0000000..d940ca9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractExtendedResultDecoder.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.ExtendedRequest;
+
+
+
+/**
+ * This class provides a skeletal implementation of the
+ * {@code ExtendedResultDecoder} interface, to minimize the effort required to
+ * implement this interface.
+ *
+ * @param <S>
+ *          The type of result.
+ */
+public abstract class AbstractExtendedResultDecoder<S extends ExtendedResult>
+    implements ExtendedResultDecoder<S>
+{
+  /**
+   * Creates a new abstract extended result decoder.
+   */
+  protected AbstractExtendedResultDecoder()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public S adaptDecodeException(final DecodeException exception)
+      throws NullPointerException
+  {
+    final S adaptedResult = newExtendedErrorResult(ResultCode.PROTOCOL_ERROR,
+        "", exception.getMessage());
+    adaptedResult.setCause(exception.getCause());
+    return adaptedResult;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public <R extends ExtendedResult> ResultHandler<S> adaptExtendedResultHandler(
+      final ExtendedRequest<R> request,
+      final ResultHandler<? super R> resultHandler, final DecodeOptions options)
+  {
+    return new ResultHandler<S>()
+    {
+
+      @Override
+      public void handleErrorResult(final ErrorResultException error)
+      {
+        final Result result = error.getResult();
+        final R adaptedResult = request.getResultDecoder()
+            .newExtendedErrorResult(result.getResultCode(),
+                result.getMatchedDN(), result.getDiagnosticMessage());
+        adaptedResult.setCause(result.getCause());
+        resultHandler.handleErrorResult(ErrorResultException
+            .wrap(adaptedResult));
+      }
+
+
+
+      @Override
+      public void handleResult(final S result)
+      {
+        try
+        {
+          final R adaptedResult = request.getResultDecoder()
+              .decodeExtendedResult(result, options);
+          resultHandler.handleResult(adaptedResult);
+        }
+        catch (final DecodeException e)
+        {
+          final R adaptedResult = request.getResultDecoder()
+              .adaptDecodeException(e);
+          resultHandler.handleErrorResult(ErrorResultException
+              .wrap(adaptedResult));
+        }
+      }
+
+    };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public abstract S decodeExtendedResult(ExtendedResult result,
+      DecodeOptions options) throws DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public abstract S newExtendedErrorResult(ResultCode resultCode,
+      String matchedDN, String diagnosticMessage) throws NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractIntermediateResponse.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractIntermediateResponse.java
new file mode 100644
index 0000000..348d1ad
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractIntermediateResponse.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.ByteString;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An abstract Intermediate response which can be used as the basis for
+ * implementing new Intermediate responses.
+ *
+ * @param <S>
+ *          The type of Intermediate response.
+ */
+public abstract class AbstractIntermediateResponse<S extends IntermediateResponse>
+    extends AbstractResponseImpl<S> implements IntermediateResponse
+{
+
+  /**
+   * Creates a new intermediate response.
+   */
+  protected AbstractIntermediateResponse()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * Creates a new intermediate response that is an exact copy of the provided
+   * response.
+   *
+   * @param intermediateResponse
+   *          The intermediate response to be copied.
+   * @throws NullPointerException
+   *           If {@code intermediateResponse} was {@code null} .
+   */
+  protected AbstractIntermediateResponse(
+      IntermediateResponse intermediateResponse)
+      throws NullPointerException
+  {
+    super(intermediateResponse);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public abstract boolean hasValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("IntermediateResponse(responseName=");
+    builder.append(getOID() == null ? "" : getOID());
+    if (hasValue())
+    {
+      builder.append(", responseValue=");
+      StaticUtils.toHexPlusAscii(getValue(), builder, 4);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @SuppressWarnings("unchecked")
+  final S getThis()
+  {
+    return (S) this;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResponseImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResponseImpl.java
new file mode 100644
index 0000000..d5f0dff
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResponseImpl.java
@@ -0,0 +1,144 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+/**
+ * Modifiable response implementation.
+ *
+ * @param <S>
+ *          The type of response.
+ */
+abstract class AbstractResponseImpl<S extends Response> implements Response
+{
+  private final List<Control> controls = new LinkedList<Control>();
+
+
+
+  /**
+   * Creates a new modifiable response implementation.
+   */
+  AbstractResponseImpl()
+  {
+    // No implementation required.
+  }
+
+
+
+  /**
+   * Creates a new abstract response that is an exact copy of the provided
+   * response.
+   *
+   * @param response
+   *          The response to be copied.
+   * @throws NullPointerException
+   *           If {@code response} was {@code null} .
+   */
+  AbstractResponseImpl(Response response) throws NullPointerException
+  {
+    Validator.ensureNotNull(response);
+    for (Control control : response.getControls())
+    {
+      // Create defensive copy.
+      controls.add(GenericControl.newControl(control));
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final S addControl(final Control control) throws NullPointerException
+  {
+    Validator.ensureNotNull(control);
+    controls.add(control);
+    return getThis();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final <C extends Control> C getControl(
+      final ControlDecoder<C> decoder, final DecodeOptions options)
+      throws NullPointerException, DecodeException
+  {
+    Validator.ensureNotNull(decoder, options);
+
+    // Avoid creating an iterator if possible.
+    if (controls.isEmpty())
+    {
+      return null;
+    }
+
+    for (final Control control : controls)
+    {
+      if (control.getOID().equals(decoder.getOID()))
+      {
+        return decoder.decodeControl(control, options);
+      }
+    }
+
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final List<Control> getControls()
+  {
+    return controls;
+  }
+
+
+
+  @Override
+  public abstract String toString();
+
+
+
+  abstract S getThis();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResultImpl.java
new file mode 100644
index 0000000..626efb7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractResultImpl.java
@@ -0,0 +1,246 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.ResultCode;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Modifiable result implementation.
+ *
+ * @param <S>
+ *          The type of result.
+ */
+abstract class AbstractResultImpl<S extends Result> extends
+    AbstractResponseImpl<S> implements Result
+{
+  // For local errors caused by internal exceptions.
+  private Throwable cause = null;
+
+  private String diagnosticMessage = "";
+
+  private String matchedDN = "";
+
+  private final List<String> referralURIs = new LinkedList<String>();
+
+  private ResultCode resultCode;
+
+
+
+  /**
+   * Creates a new modifiable result implementation using the provided result
+   * code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  AbstractResultImpl(final ResultCode resultCode) throws NullPointerException
+  {
+    this.resultCode = resultCode;
+  }
+
+
+
+  /**
+   * Creates a new modifiable result that is an exact copy of the provided
+   * result.
+   *
+   * @param result
+   *          The result to be copied.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  AbstractResultImpl(Result result) throws NullPointerException
+  {
+    super(result);
+    this.cause = result.getCause();
+    this.diagnosticMessage = result.getDiagnosticMessage();
+    this.matchedDN = result.getMatchedDN();
+    this.referralURIs.addAll(result.getReferralURIs());
+    this.resultCode = result.getResultCode();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final S addReferralURI(final String uri) throws NullPointerException
+  {
+    Validator.ensureNotNull(uri);
+
+    referralURIs.add(uri);
+    return getThis();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final Throwable getCause()
+  {
+    return cause;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final String getDiagnosticMessage()
+  {
+    return diagnosticMessage;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final String getMatchedDN()
+  {
+    return matchedDN;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final List<String> getReferralURIs()
+  {
+    return referralURIs;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final ResultCode getResultCode()
+  {
+    return resultCode;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isReferral()
+  {
+    final ResultCode code = getResultCode();
+    return code.equals(ResultCode.REFERRAL);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final boolean isSuccess()
+  {
+    final ResultCode code = getResultCode();
+    return !code.isExceptional();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final S setCause(final Throwable cause)
+  {
+    this.cause = cause;
+    return getThis();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final S setDiagnosticMessage(final String message)
+  {
+    if (message == null)
+    {
+      this.diagnosticMessage = "";
+    }
+    else
+    {
+      this.diagnosticMessage = message;
+    }
+
+    return getThis();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final S setMatchedDN(final String dn)
+  {
+    if (dn == null)
+    {
+      this.matchedDN = "";
+    }
+    else
+    {
+      this.matchedDN = dn;
+    }
+
+    return getThis();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public final S setResultCode(final ResultCode resultCode)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+
+    this.resultCode = resultCode;
+    return getThis();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableExtendedResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableExtendedResultImpl.java
new file mode 100644
index 0000000..8c796e6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableExtendedResultImpl.java
@@ -0,0 +1,60 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * An abstract unmodifiable Extended result which can be used as the basis for
+ * implementing new unmodifiable Extended operations.
+ *
+ * @param <S>
+ *          The type of Extended result.
+ */
+abstract class AbstractUnmodifiableExtendedResultImpl<S extends ExtendedResult>
+    extends AbstractUnmodifiableResultImpl<S> implements ExtendedResult
+{
+  protected AbstractUnmodifiableExtendedResultImpl(S impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getOID() {
+    return impl.getOID();
+  }
+
+  @Override
+  public ByteString getValue() {
+    return impl.getValue();
+  }
+
+  @Override
+  public boolean hasValue() {
+    return impl.hasValue();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableIntermediateResponseImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableIntermediateResponseImpl.java
new file mode 100644
index 0000000..dbd05c6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableIntermediateResponseImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * An abstract unmodifiable Intermediate response which can be used as the basis
+ * for implementing new unmodifiable Intermediate responses.
+ *
+ * @param <S>
+ *          The type of Intermediate response.
+ */
+abstract class AbstractUnmodifiableIntermediateResponseImpl
+    <S extends IntermediateResponse> extends AbstractUnmodifiableResponseImpl<S>
+    implements IntermediateResponse
+{
+  protected AbstractUnmodifiableIntermediateResponseImpl(S impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getOID() {
+    return impl.getOID();
+  }
+
+  @Override
+  public ByteString getValue() {
+    return impl.getValue();
+  }
+
+  @Override
+  public boolean hasValue() {
+    return impl.hasValue();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java
new file mode 100644
index 0000000..30d35b7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResponseImpl.java
@@ -0,0 +1,173 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.Collections;
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
+
+import com.sun.opends.sdk.util.Collections2;
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Functions;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Unmodifiable response implementation.
+ *
+ * @param <S>
+ *          The type of response.
+ */
+abstract class AbstractUnmodifiableResponseImpl<S extends Response> implements
+    Response
+{
+
+  protected final S impl;
+
+
+
+  /**
+   * Creates a new unmodifiable response implementation.
+   *
+   * @param impl
+   *          The underlying response implementation to be made unmodifiable.
+   */
+  AbstractUnmodifiableResponseImpl(final S impl)
+  {
+    Validator.ensureNotNull(impl);
+    this.impl = impl;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final S addControl(final Control control)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final <C extends Control> C getControl(
+      final ControlDecoder<C> decoder, final DecodeOptions options)
+      throws NullPointerException, DecodeException
+  {
+    Validator.ensureNotNull(decoder, options);
+
+    final List<Control> controls = impl.getControls();
+
+    // Avoid creating an iterator if possible.
+    if (controls.isEmpty())
+    {
+      return null;
+    }
+
+    for (final Control control : controls)
+    {
+      if (control.getOID().equals(decoder.getOID()))
+      {
+        // Got a match. Return a defensive copy only if necessary.
+        final C decodedControl = decoder.decodeControl(control, options);
+
+        if (decodedControl != control)
+        {
+          // This was not the original control so return it immediately.
+          return decodedControl;
+        }
+        else if (decodedControl instanceof GenericControl)
+        {
+          // Generic controls are immutable, so return it immediately.
+          return decodedControl;
+        }
+        else
+        {
+          // Re-decode to get defensive copy.
+          final GenericControl genericControl = GenericControl
+              .newControl(control);
+          return decoder.decodeControl(genericControl, options);
+        }
+      }
+    }
+
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final List<Control> getControls()
+  {
+    // We need to make all controls unmodifiable as well, which implies making
+    // defensive copies where necessary.
+    final Function<Control, Control, Void> function = new Function<Control, Control, Void>()
+    {
+
+      @Override
+      public Control apply(final Control value, final Void p)
+      {
+        // Return defensive copy.
+        return GenericControl.newControl(value);
+      }
+
+    };
+
+    final List<Control> unmodifiableControls = Collections2.transformedList(
+        impl.getControls(), function, Functions.<Control> identityFunction());
+    return Collections.unmodifiableList(unmodifiableControls);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public final String toString()
+  {
+    return impl.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResultImpl.java
new file mode 100644
index 0000000..827d90f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/AbstractUnmodifiableResultImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.Collections;
+import java.util.List;
+
+import org.opends.sdk.ResultCode;
+
+
+
+/**
+ * Unmodifiable result implementation.
+ *
+ * @param <S>
+ *          The type of result.
+ */
+abstract class AbstractUnmodifiableResultImpl<S extends Result> extends
+    AbstractUnmodifiableResponseImpl<S> implements Result
+{
+
+  /**
+   * Creates a new unmodifiable result implementation.
+   *
+   * @param impl
+   *          The underlying result implementation to be made unmodifiable.
+   */
+  AbstractUnmodifiableResultImpl(final S impl)
+  {
+    super(impl);
+  }
+
+
+
+  public final S addReferralURI(final String uri)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+
+
+  public final Throwable getCause()
+  {
+    return impl.getCause();
+  }
+
+
+
+  public final String getDiagnosticMessage()
+  {
+    return impl.getDiagnosticMessage();
+  }
+
+
+
+  public final String getMatchedDN()
+  {
+    return impl.getMatchedDN();
+  }
+
+
+
+  public final List<String> getReferralURIs()
+  {
+    return Collections.unmodifiableList(impl.getReferralURIs());
+  }
+
+
+
+  public final ResultCode getResultCode()
+  {
+    return impl.getResultCode();
+  }
+
+
+
+  public final boolean isReferral()
+  {
+    return impl.isReferral();
+  }
+
+
+
+  public final boolean isSuccess()
+  {
+    return impl.isSuccess();
+  }
+
+
+
+  public final S setCause(final Throwable cause)
+      throws UnsupportedOperationException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+
+
+  public final S setDiagnosticMessage(final String message)
+      throws UnsupportedOperationException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+
+
+  public final S setMatchedDN(final String dn)
+      throws UnsupportedOperationException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+
+
+  public final S setResultCode(final ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResult.java
new file mode 100644
index 0000000..e8222d1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResult.java
@@ -0,0 +1,215 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A Bind result indicates the status of the client's request for
+ * authentication.
+ * <p>
+ * A successful Bind operation is indicated by a Bind result with a result code
+ * set to {@link ResultCode#SUCCESS} and can be determined by invoking the
+ * {@link #isSuccess} method.
+ * <p>
+ * The server SASL credentials field is used as part of a SASL-defined bind
+ * mechanism to allow the client to authenticate the server to which it is
+ * communicating, or to perform "challenge-response" authentication. If the
+ * client bound using a form of simple authentication, or the SASL mechanism
+ * does not require the server to return information to the client, then this
+ * field shall not be included in the Bind result.
+ * <p>
+ * If the server requires the client to send a new SASL Bind request in order to
+ * continue the authentication process then the result code is set to
+ * {@link ResultCode#SASL_BIND_IN_PROGRESS} and can be determined by invoking
+ * the {@link #isSASLBindInProgress} method.
+ */
+public interface BindResult extends Result
+{
+  /**
+   * {@inheritDoc}
+   */
+  BindResult addControl(Control control) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindResult addReferralURI(String uri) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Throwable getCause();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getDiagnosticMessage();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getMatchedDN();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<String> getReferralURIs();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ResultCode getResultCode();
+
+
+
+  /**
+   * Returns the server SASL credentials associated with this bind result.
+   *
+   * @return The server SASL credentials, or {@code null} indicating that none
+   *         was provided.
+   */
+  ByteString getServerSASLCredentials();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isReferral();
+
+
+
+  /**
+   * Indicates whether or not the server requires the client to send a new SASL
+   * Bind request with the same SASL mechanism in order to continue the
+   * authentication process. This typically occurs during multi-stage (challenge
+   * response) authentication.
+   * <p>
+   * Specifically, this method returns {@code true} if the result code is equal
+   * to {@link ResultCode#SASL_BIND_IN_PROGRESS}.
+   *
+   * @return {@code true} if the server requires the client to send a new SASL
+   *         Bind request, otherwise {@code false}.
+   */
+  boolean isSASLBindInProgress();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isSuccess();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindResult setCause(Throwable cause) throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindResult setDiagnosticMessage(String message)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindResult setMatchedDN(String dn) throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  BindResult setResultCode(ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the server SASL credentials associated with this bind result.
+   *
+   * @param credentials
+   *          The server SASL credentials associated with this bind result,
+   *          which may be {@code null} indicating that none was provided.
+   * @return This bind result.
+   * @throws UnsupportedOperationException
+   *           If this bind result does not permit the server SASL credentials
+   *           to be set.
+   */
+  BindResult setServerSASLCredentials(ByteString credentials)
+      throws UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResultImpl.java
new file mode 100644
index 0000000..a10bc39
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/BindResultImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ResultCode;
+
+
+
+/**
+ * Bind result implementation.
+ */
+final class BindResultImpl extends AbstractResultImpl<BindResult> implements
+    BindResult
+{
+  private ByteString credentials = null;
+
+
+
+  /**
+   * Creates a new bind result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  BindResultImpl(final ResultCode resultCode) throws NullPointerException
+  {
+    super(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new bind result that is an exact copy of the provided
+   * result.
+   *
+   * @param bindResult
+   *          The bind result to be copied.
+   * @throws NullPointerException
+   *           If {@code bindResult} was {@code null} .
+   */
+  BindResultImpl(final BindResult bindResult)
+      throws NullPointerException
+  {
+    super(bindResult);
+    this.credentials = bindResult.getServerSASLCredentials();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getServerSASLCredentials()
+  {
+    return credentials;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isSASLBindInProgress()
+  {
+    final ResultCode code = getResultCode();
+    return code.equals(ResultCode.SASL_BIND_IN_PROGRESS);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public BindResult setServerSASLCredentials(final ByteString credentials)
+      throws UnsupportedOperationException
+  {
+    this.credentials = credentials;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("BindResult(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", serverSASLCreds=");
+    builder.append(getServerSASLCredentials() == null ? ByteString.empty()
+        : getServerSASLCredentials());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  BindResult getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResult.java
new file mode 100644
index 0000000..92ec492
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResult.java
@@ -0,0 +1,174 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * An Compare result indicates the final status of an Compare operation.
+ * <p>
+ * If the attribute value assertion in the Compare request matched a value of
+ * the attribute or sub-type according to the attribute's equality matching rule
+ * then the result code is set to {@link ResultCode#COMPARE_TRUE} and can be
+ * determined by invoking the {@link #matched} method.
+ */
+public interface CompareResult extends Result
+{
+  /**
+   * {@inheritDoc}
+   */
+  CompareResult addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  CompareResult addReferralURI(String uri)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Throwable getCause();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getDiagnosticMessage();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getMatchedDN();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<String> getReferralURIs();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ResultCode getResultCode();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isReferral();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isSuccess();
+
+
+
+  /**
+   * Indicates whether or not the attribute value assertion in the Compare
+   * request matched a value of the attribute or sub-type according to the
+   * attribute's equality matching rule.
+   * <p>
+   * Specifically, this method returns {@code true} if the result code is equal
+   * to {@link ResultCode#COMPARE_TRUE}.
+   *
+   * @return {@code true} if the attribute value assertion matched, otherwise
+   *         {@code false}.
+   */
+  boolean matched();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  CompareResult setCause(Throwable cause) throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  CompareResult setDiagnosticMessage(String message)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  CompareResult setMatchedDN(String dn) throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  CompareResult setResultCode(ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResultImpl.java
new file mode 100644
index 0000000..01dcf0c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/CompareResultImpl.java
@@ -0,0 +1,115 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.ResultCode;
+
+
+
+/**
+ * Compare result implementation.
+ */
+final class CompareResultImpl extends AbstractResultImpl<CompareResult>
+    implements CompareResult
+{
+
+  /**
+   * Creates a new compare result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  CompareResultImpl(final ResultCode resultCode) throws NullPointerException
+  {
+    super(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new compare result that is an exact copy of the provided
+   * result.
+   *
+   * @param compareResult
+   *          The compare result to be copied.
+   * @throws NullPointerException
+   *           If {@code compareResult} was {@code null} .
+   */
+  CompareResultImpl(final CompareResult compareResult)
+      throws NullPointerException
+  {
+    super(compareResult);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean matched()
+  {
+    final ResultCode code = getResultCode();
+    return code.equals(ResultCode.COMPARE_TRUE);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("CompareResult(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  CompareResult getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResult.java
new file mode 100644
index 0000000..ccbed68
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResult.java
@@ -0,0 +1,192 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A Extended result indicates the status of an Extended operation and any
+ * additional information associated with the Extended operation, including the
+ * optional response name and value. These can be retrieved using the
+ * {@link #getOID} and {@link #getValue} methods respectively.
+ */
+public interface ExtendedResult extends Result
+{
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResult addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResult addReferralURI(String uri)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Throwable getCause();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getDiagnosticMessage();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getMatchedDN();
+
+
+
+  /**
+   * Returns the numeric OID, if any, associated with this extended result.
+   *
+   * @return The numeric OID associated with this extended result, or {@code
+   *         null} if there is no OID.
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<String> getReferralURIs();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ResultCode getResultCode();
+
+
+
+  /**
+   * Returns the value, if any, associated with this extended result. Its format
+   * is defined by the specification of this extended result.
+   *
+   * @return The value associated with this extended result, or {@code null} if
+   *         there is no value.
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * Returns {@code true} if this extended result has a value. In some
+   * circumstances it may be useful to determine if a extended result has a
+   * value, without actually calculating the value and incurring any performance
+   * costs.
+   *
+   * @return {@code true} if this extended result has a value, or {@code false}
+   *         if there is no value.
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isReferral();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isSuccess();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResult setCause(Throwable cause) throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResult setDiagnosticMessage(String message)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResult setMatchedDN(String dn) throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ExtendedResult setResultCode(ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResultDecoder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResultDecoder.java
new file mode 100644
index 0000000..5e4c637
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ExtendedResultDecoder.java
@@ -0,0 +1,134 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.ResultHandler;
+import org.opends.sdk.requests.ExtendedRequest;
+
+
+
+/**
+ * A factory interface for decoding a generic extended result as an extended
+ * result of specific type.
+ *
+ * @param <S>
+ *          The type of result.
+ */
+public interface ExtendedResultDecoder<S extends ExtendedResult>
+{
+
+  /**
+   * Creates a new extended operation error result using the provided decoding
+   * exception. This method should be used to adapt {@code DecodeException}
+   * encountered while decoding an extended request or result. The returned
+   * error result will have the result code {@link ResultCode#PROTOCOL_ERROR}.
+   *
+   * @param exception
+   *          The decoding exception to be adapted.
+   * @return An extended operation error result representing the decoding
+   *         exception.
+   * @throws NullPointerException
+   *           If {@code exception} was {@code null}.
+   */
+  S adaptDecodeException(DecodeException exception) throws NullPointerException;
+
+
+
+  /**
+   * Adapts the provided extended result handler into a result handler which is
+   * compatible with this extended result decoder. Extended results handled by
+   * the returned handler will be automatically converted and passed to the
+   * provided result handler. Decoding errors encountered while decoding the
+   * extended result will be converted into protocol errors.
+   *
+   * @param <R>
+   *          The type of result handler to be adapted.
+   * @param request
+   *          The extended request whose result handler is to be adapted.
+   * @param resultHandler
+   *          The extended result handler which is to be adapted.
+   * @param options
+   *          The set of decode options which should be used when decoding the
+   *          extended operation result.
+   * @return A result handler which is compatible with this extended result
+   *         decoder.
+   */
+  <R extends ExtendedResult> ResultHandler<S> adaptExtendedResultHandler(
+      final ExtendedRequest<R> request,
+      final ResultHandler<? super R> resultHandler, DecodeOptions options);
+
+
+
+  /**
+   * Decodes the provided extended operation result as a {@code Result} of type
+   * {@code S}. This method is called when an extended result is received from
+   * the server. The result may indicate success or failure of the extended
+   * request.
+   *
+   * @param result
+   *          The extended operation result to be decoded.
+   * @param options
+   *          The set of decode options which should be used when decoding the
+   *          extended operation result.
+   * @return The decoded extended operation result.
+   * @throws DecodeException
+   *           If the provided extended operation result could not be decoded.
+   *           For example, if the request name was wrong, or if the request
+   *           value was invalid.
+   */
+  S decodeExtendedResult(ExtendedResult result, DecodeOptions options)
+      throws DecodeException;
+
+
+
+  /**
+   * Creates a new extended error result using the provided result code, matched
+   * DN, and diagnostic message. This method is called when a generic failure
+   * occurs, such as a connection failure, and the error result needs to be
+   * converted to a {@code Result} of type {@code S}.
+   *
+   * @param resultCode
+   *          The result code.
+   * @param matchedDN
+   *          The matched DN, which may be empty if none was provided.
+   * @param diagnosticMessage
+   *          The diagnostic message, which may be empty if none was provided.
+   * @return The decoded extended operation error result.
+   * @throws NullPointerException
+   *           If {@code resultCode}, {@code matchedDN}, or
+   *           {@code diagnosticMessage} were {@code null}.
+   */
+  S newExtendedErrorResult(ResultCode resultCode, String matchedDN,
+      String diagnosticMessage) throws NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResult.java
new file mode 100644
index 0000000..f6439ea
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResult.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A Generic Extended result indicates the final status of an Generic Extended
+ * operation.
+ */
+public interface GenericExtendedResult extends ExtendedResult
+{
+  /**
+   * {@inheritDoc}
+   */
+  GenericExtendedResult addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  GenericExtendedResult addReferralURI(String uri)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Throwable getCause();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getDiagnosticMessage();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getMatchedDN();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<String> getReferralURIs();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ResultCode getResultCode();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isReferral();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isSuccess();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  GenericExtendedResult setCause(Throwable cause)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  GenericExtendedResult setDiagnosticMessage(String message)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  GenericExtendedResult setMatchedDN(String dn)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the numeric OID, if any, associated with this extended result.
+   *
+   * @param oid
+   *          The numeric OID associated with this extended result, or {@code
+   *          null} if there is no value.
+   * @return This generic extended result.
+   * @throws UnsupportedOperationException
+   *           If this generic extended result does not permit the result name
+   *           to be set.
+   */
+  GenericExtendedResult setOID(String oid) throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  GenericExtendedResult setResultCode(ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Sets the value, if any, associated with this extended result. Its format is
+   * defined by the specification of this extended result.
+   *
+   * @param bytes
+   *          The value associated with this extended result, or {@code null} if
+   *          there is no value.
+   * @return This generic extended result.
+   * @throws UnsupportedOperationException
+   *           If this generic extended result does not permit the result value
+   *           to be set.
+   */
+  GenericExtendedResult setValue(ByteString bytes)
+      throws UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResultImpl.java
new file mode 100644
index 0000000..c5633c3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericExtendedResultImpl.java
@@ -0,0 +1,169 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ResultCode;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Generic extended result implementation.
+ */
+final class GenericExtendedResultImpl extends
+    AbstractExtendedResult<GenericExtendedResult> implements ExtendedResult,
+    GenericExtendedResult
+{
+
+  private String responseName = null;
+
+  private ByteString responseValue = null;
+
+
+
+  /**
+   * Creates a new generic extended result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  GenericExtendedResultImpl(final ResultCode resultCode)
+      throws NullPointerException
+  {
+    super(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new generic extended result that is an exact copy of the provided
+   * result.
+   *
+   * @param genericExtendedResult
+   *          The generic extended result to be copied.
+   * @throws NullPointerException
+   *           If {@code genericExtendedResult} was {@code null} .
+   */
+  GenericExtendedResultImpl(final GenericExtendedResult genericExtendedResult)
+      throws NullPointerException
+  {
+    super(genericExtendedResult);
+    this.responseName = genericExtendedResult.getOID();
+    this.responseValue = genericExtendedResult.getValue();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getOID()
+  {
+    return responseName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getValue()
+  {
+    return responseValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasValue()
+  {
+    return responseValue != null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericExtendedResult setOID(final String oid)
+      throws UnsupportedOperationException
+  {
+    this.responseName = oid;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericExtendedResult setValue(final ByteString bytes)
+      throws UnsupportedOperationException
+  {
+    this.responseValue = bytes;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GenericExtendedResult(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", responseName=");
+    builder.append(getOID() == null ? "" : getOID());
+    if (hasValue())
+    {
+      builder.append(", responseValue=");
+      StaticUtils.toHexPlusAscii(getValue(), builder, 4);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponse.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponse.java
new file mode 100644
index 0000000..f3c8006
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponse.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A Generic Intermediate response provides a mechanism for communicating
+ * unrecognized or unsupported Intermediate responses to the client.
+ */
+public interface GenericIntermediateResponse extends IntermediateResponse
+{
+  /**
+   * {@inheritDoc}
+   */
+  GenericIntermediateResponse addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * Sets the numeric OID, if any, associated with this intermediate response.
+   *
+   * @param oid
+   *          The numeric OID associated with this intermediate response, or
+   *          {@code null} if there is no value.
+   * @return This generic intermediate response.
+   * @throws UnsupportedOperationException
+   *           If this intermediate response does not permit the response name
+   *           to be set.
+   */
+  GenericIntermediateResponse setOID(String oid)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the value, if any, associated with this intermediate response. Its
+   * format is defined by the specification of this intermediate response.
+   *
+   * @param bytes
+   *          The value associated with this intermediate response, or {@code
+   *          null} if there is no value.
+   * @return This generic intermediate response.
+   * @throws UnsupportedOperationException
+   *           If this intermediate response does not permit the response value
+   *           to be set.
+   */
+  GenericIntermediateResponse setValue(ByteString bytes)
+      throws UnsupportedOperationException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponseImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponseImpl.java
new file mode 100644
index 0000000..966d078
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/GenericIntermediateResponseImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.ByteString;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Generic intermediate response implementation.
+ */
+final class GenericIntermediateResponseImpl extends
+    AbstractIntermediateResponse<GenericIntermediateResponse> implements
+    GenericIntermediateResponse
+{
+
+  private String responseName = null;
+
+  private ByteString responseValue = null;
+
+
+
+  /**
+   * Creates a new generic intermediate response using the provided response
+   * name and value.
+   *
+   * @param responseName
+   *          The dotted-decimal representation of the unique OID corresponding
+   *          to this intermediate response, which may be {@code null}
+   *          indicating that none was provided.
+   * @param responseValue
+   *          The response value associated with this generic intermediate
+   *          response, which may be {@code null} indicating that none was
+   *          provided.
+   */
+  GenericIntermediateResponseImpl(final String responseName,
+      final ByteString responseValue)
+  {
+    this.responseName = responseName;
+    this.responseValue = responseValue;
+  }
+
+
+
+  /**
+   * Creates a new generic intermediate response that is an exact copy of the
+   * provided result.
+   *
+   * @param genericIntermediateResponse
+   *          The generic intermediate response to be copied.
+   * @throws NullPointerException
+   *           If {@code genericExtendedResult} was {@code null} .
+   */
+  GenericIntermediateResponseImpl(
+      final GenericIntermediateResponse genericIntermediateResponse)
+      throws NullPointerException
+  {
+    super(genericIntermediateResponse);
+    this.responseName = genericIntermediateResponse.getOID();
+    this.responseValue = genericIntermediateResponse.getValue();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    return responseName;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return responseValue;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return responseValue != null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericIntermediateResponse setOID(final String oid)
+      throws UnsupportedOperationException
+  {
+    this.responseName = oid;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public GenericIntermediateResponse setValue(final ByteString bytes)
+      throws UnsupportedOperationException
+  {
+    this.responseValue = bytes;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("GenericIntermediateResponse(responseName=");
+    builder.append(getOID() == null ? "" : getOID());
+    if (hasValue())
+    {
+      builder.append(", requestValue=");
+      StaticUtils.toHexPlusAscii(getValue(), builder, 4);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/IntermediateResponse.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/IntermediateResponse.java
new file mode 100644
index 0000000..993b3a9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/IntermediateResponse.java
@@ -0,0 +1,112 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * An Intermediate response provides a general mechanism for defining
+ * single-request/multiple-response operations. This response is intended to be
+ * used in conjunction with the Extended operation to define new
+ * single-request/multiple-response operations or in conjunction with a control
+ * when extending existing operations in a way that requires them to return
+ * Intermediate response information.
+ * <p>
+ * An Intermediate response may convey an optional response name and value.
+ * These can be retrieved using the {@link #getOID} and {@link #getValue}
+ * methods respectively.
+ */
+public interface IntermediateResponse extends Response
+{
+  /**
+   * {@inheritDoc}
+   */
+  IntermediateResponse addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the numeric OID, if any, associated with this intermediate
+   * response.
+   *
+   * @return The numeric OID associated with this intermediate response, or
+   *         {@code null} if there is no OID.
+   */
+  String getOID();
+
+
+
+  /**
+   * Returns the value, if any, associated with this intermediate response. Its
+   * format is defined by the specification of this intermediate response.
+   *
+   * @return The value associated with this intermediate response, or {@code
+   *         null} if there is no value.
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * Returns {@code true} if this intermediate response has a value. In some
+   * circumstances it may be useful to determine if an intermediate response has
+   * a value, without actually calculating the value and incurring any
+   * performance costs.
+   *
+   * @return {@code true} if this intermediate response has a value, or {@code
+   *         false} if there is no value.
+   */
+  boolean hasValue();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResult.java
new file mode 100644
index 0000000..6f04319
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResult.java
@@ -0,0 +1,230 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The password modify extended result as defined in RFC 3062. The result
+ * includes the generated password, if requested, but only if the modify request
+ * succeeded.
+ *
+ * @see org.opends.sdk.requests.PasswordModifyExtendedRequest
+ * @see <a href="http://tools.ietf.org/html/rfc3909">RFC 3062 - LDAP Password
+ *      Modify Extended Operation </a>
+ */
+public interface PasswordModifyExtendedResult extends ExtendedResult
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  PasswordModifyExtendedResult addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  PasswordModifyExtendedResult addReferralURI(String uri)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Throwable getCause();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getDiagnosticMessage();
+
+
+
+  /**
+   * Returns the newly generated password, but only if the password modify
+   * request succeeded and a generated password was requested.
+   *
+   * @return The newly generated password, or {@code null} if the password
+   *         modify request failed or a generated password was not requested.
+   */
+  ByteString getGeneratedPassword();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getMatchedDN();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<String> getReferralURIs();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ResultCode getResultCode();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isReferral();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isSuccess();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  PasswordModifyExtendedResult setCause(Throwable cause)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  PasswordModifyExtendedResult setDiagnosticMessage(String message)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the generated password.
+   *
+   * @param password
+   *          The generated password, or {@code null} if there is no generated
+   *          password associated with this result.
+   * @return This password modify result.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended result does not permit the
+   *           generated password to be set.
+   */
+  PasswordModifyExtendedResult setGeneratedPassword(ByteString password)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the generated password. The password will be converted to a UTF-8
+   * octet string.
+   *
+   * @param password
+   *          The generated password, or {@code null} if there is no generated
+   *          password associated with this result.
+   * @return This password modify result.
+   * @throws UnsupportedOperationException
+   *           If this password modify extended result does not permit the
+   *           generated password to be set.
+   */
+  PasswordModifyExtendedResult setGeneratedPassword(char[] password)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  PasswordModifyExtendedResult setMatchedDN(String dn)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  PasswordModifyExtendedResult setResultCode(ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.java
new file mode 100644
index 0000000..a90d214
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/PasswordModifyExtendedResultImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Writer;
+
+
+
+/**
+ * Password modify extended result implementation.
+ */
+final class PasswordModifyExtendedResultImpl extends
+    AbstractExtendedResult<PasswordModifyExtendedResult> implements
+    PasswordModifyExtendedResult
+{
+  private ByteString password;
+
+  /**
+   * The ASN.1 element type that will be used to encode the genPasswd component
+   * in a password modify extended response.
+   */
+  private static final byte TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD =
+      (byte) 0x80;
+
+
+
+  // Instantiation via factory.
+  PasswordModifyExtendedResultImpl(final ResultCode resultCode)
+  {
+    super(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new password modify extended result that is an exact copy of the
+   * provided result.
+   *
+   * @param passwordModifyExtendedResult
+   *          The password modify extended result to be copied.
+   * @throws NullPointerException
+   *           If {@code passwordModifyExtendedResult} was {@code null} .
+   */
+  PasswordModifyExtendedResultImpl(
+      final PasswordModifyExtendedResult passwordModifyExtendedResult)
+      throws NullPointerException
+  {
+    super(passwordModifyExtendedResult);
+    this.password = passwordModifyExtendedResult.getGeneratedPassword();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString getGeneratedPassword()
+  {
+    return password;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    // No response name defined.
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    if (password != null)
+    {
+      final ByteStringBuilder buffer = new ByteStringBuilder();
+      final ASN1Writer writer = ASN1.getWriter(buffer);
+
+      try
+      {
+        writer.writeStartSequence();
+        writer.writeOctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD,
+            password);
+        writer.writeEndSequence();
+      }
+      catch (final IOException ioe)
+      {
+        // This should never happen unless there is a bug somewhere.
+        throw new RuntimeException(ioe);
+      }
+
+      return buffer.toByteString();
+    }
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return password != null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedResult setGeneratedPassword(
+      final ByteString password) throws UnsupportedOperationException
+  {
+    this.password = password;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public PasswordModifyExtendedResult setGeneratedPassword(
+      final char[] password) throws UnsupportedOperationException
+  {
+    this.password = (password != null) ? ByteString.valueOf(password) : null;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("PasswordModifyExtendedResponse(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    if (password != null)
+    {
+      builder.append(", genPassword=");
+      builder.append(password);
+    }
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Response.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Response.java
new file mode 100644
index 0000000..0c92715
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Response.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The base class of all Responses provides methods for querying and
+ * manipulating the set of Controls included with a Response.
+ * <p>
+ * TODO: added complete description including sub-types.
+ */
+public interface Response
+{
+
+  /**
+   * Adds the provided control to this response.
+   *
+   * @param control
+   *          The control to be added.
+   * @return This response.
+   * @throws UnsupportedOperationException
+   *           If this response does not permit controls to be added.
+   * @throws NullPointerException
+   *           If {@code control} was {@code null}.
+   */
+  Response addControl(Control control) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Decodes and returns the first control in this response having an OID
+   * corresponding to the provided control decoder.
+   *
+   * @param <C>
+   *          The type of control to be decoded and returned.
+   * @param decoder
+   *          The control decoder.
+   * @param options
+   *          The set of decode options which should be used when decoding the
+   *          control.
+   * @return The decoded control, or {@code null} if the control is not included
+   *         with this response.
+   * @throws DecodeException
+   *           If the control could not be decoded because it was malformed in
+   *           some way (e.g. the control value was missing, or its content
+   *           could not be decoded).
+   * @throws NullPointerException
+   *           If {@code decoder} or {@code options} was {@code null}.
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * Returns a {@code List} containing the controls included with this response.
+   * The returned {@code List} may be modified if permitted by this response.
+   *
+   * @return A {@code List} containing the controls.
+   */
+  List<Control> getControls();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Responses.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Responses.java
new file mode 100644
index 0000000..d7b48eb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Responses.java
@@ -0,0 +1,665 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class contains various methods for creating and manipulating responses.
+ * <p>
+ * All copy constructors of the form {@code copyOfXXXResult} perform deep copies
+ * of their response parameter. More specifically, any controls, modifications,
+ * and attributes contained within the response will be duplicated.
+ * <p>
+ * Similarly, all unmodifiable views of responses returned by methods of the
+ * form {@code unmodifiableXXXResult} return deep unmodifiable views of their
+ * response parameter. More specifically, any controls, modifications, and
+ * attributes contained within the returned response will be unmodifiable.
+ */
+public final class Responses
+{
+
+  // TODO: search reference from LDAP URL.
+
+  // TODO: referral from LDAP URL.
+
+  // TODO: synchronized requests?
+
+  /**
+   * Creates a new bind result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @return The new bind result.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static BindResult newBindResult(final ResultCode resultCode)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+    return new BindResultImpl(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new compare result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @return The new compare result.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static CompareResult newCompareResult(final ResultCode resultCode)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+    return new CompareResultImpl(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new generic extended result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @return The new generic extended result.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static GenericExtendedResult newGenericExtendedResult(
+      final ResultCode resultCode) throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+    return new GenericExtendedResultImpl(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new generic intermediate response with no name or value.
+   *
+   * @return The new generic intermediate response.
+   */
+  public static GenericIntermediateResponse newGenericIntermediateResponse()
+  {
+    return new GenericIntermediateResponseImpl(null, null);
+  }
+
+
+
+  /**
+   * Creates a new generic intermediate response using the provided response
+   * name and value.
+   *
+   * @param responseName
+   *          The dotted-decimal representation of the unique OID corresponding
+   *          to this intermediate response, which may be {@code null}
+   *          indicating that none was provided.
+   * @param responseValue
+   *          The response value associated with this generic intermediate
+   *          response, which may be {@code null} indicating that none was
+   *          provided.
+   * @return The new generic intermediate response.
+   */
+  public static GenericIntermediateResponse newGenericIntermediateResponse(
+      final String responseName, final ByteString responseValue)
+  {
+    return new GenericIntermediateResponseImpl(responseName, responseValue);
+  }
+
+
+
+  /**
+   * Creates a new password modify extended result using the provided result
+   * code, and no generated password.
+   *
+   * @param resultCode
+   *          The result code.
+   * @return The new password modify extended result.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static PasswordModifyExtendedResult newPasswordModifyExtendedResult(
+      final ResultCode resultCode) throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+    return new PasswordModifyExtendedResultImpl(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @return The new result.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  public static Result newResult(final ResultCode resultCode)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+    return new ResultImpl(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new search result entry using the provided distinguished name.
+   *
+   * @param name
+   *          The distinguished name of the entry.
+   * @return The new search result entry.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static SearchResultEntry newSearchResultEntry(final DN name)
+      throws NullPointerException
+  {
+    final Entry entry = new LinkedHashMapEntry().setName(name);
+    return new SearchResultEntryImpl(entry);
+  }
+
+
+
+  /**
+   * Creates a new search result entry backed by the provided entry.
+   * Modifications made to {@code entry} will be reflected in the returned
+   * search result entry. The returned search result entry supports updates to
+   * its list of controls, as well as updates to the name and attributes if the
+   * underlying entry allows.
+   *
+   * @param entry
+   *          The entry.
+   * @return The new search result entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  public static SearchResultEntry newSearchResultEntry(final Entry entry)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(entry);
+    return new SearchResultEntryImpl(entry);
+  }
+
+
+
+  /**
+   * Creates a new search result entry using the provided distinguished name
+   * decoded using the default schema.
+   *
+   * @param name
+   *          The distinguished name of the entry.
+   * @return The new search result entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code name} could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public static SearchResultEntry newSearchResultEntry(final String name)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    final Entry entry = new LinkedHashMapEntry().setName(name);
+    return new SearchResultEntryImpl(entry);
+  }
+
+
+
+  /**
+   * Creates a new search result entry using the provided lines of LDIF decoded
+   * using the default schema.
+   *
+   * @param ldifLines
+   *          Lines of LDIF containing an LDIF add change record or an LDIF
+   *          entry record.
+   * @return The new search result entry.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code ldifLines} was empty, or contained invalid LDIF, or
+   *           could not be decoded using the default schema.
+   * @throws NullPointerException
+   *           If {@code ldifLines} was {@code null} .
+   */
+  public static SearchResultEntry newSearchResultEntry(
+      final String... ldifLines) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    return newSearchResultEntry(new LinkedHashMapEntry(ldifLines));
+  }
+
+
+
+  /**
+   * Creates a new search result reference using the provided continuation
+   * reference URI.
+   *
+   * @param uri
+   *          The first continuation reference URI to be added to this search
+   *          result reference.
+   * @return The new search result reference.
+   * @throws NullPointerException
+   *           If {@code uri} was {@code null}.
+   */
+  public static SearchResultReference newSearchResultReference(final String uri)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(uri);
+    return new SearchResultReferenceImpl(uri);
+  }
+
+
+
+  /**
+   * Creates a new who am I extended result with the provided result code and no
+   * authorization ID.
+   *
+   * @param resultCode
+   *          The result code.
+   * @return The new who am I extended result.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null} .
+   */
+  public static WhoAmIExtendedResult newWhoAmIExtendedResult(
+      final ResultCode resultCode) throws NullPointerException
+  {
+    Validator.ensureNotNull(resultCode);
+    return new WhoAmIExtendedResultImpl(ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable bind result using the provided response.
+   *
+   * @param result
+   *          The bind result to be copied.
+   * @return The unmodifiable bind result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static BindResult unmodifiableBindResult(final BindResult result)
+      throws NullPointerException
+  {
+    if (result instanceof UnmodifiableBindResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableBindResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable compare result using the provided response.
+   *
+   * @param result
+   *          The compare result to be copied.
+   * @return The unmodifiable compare result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static CompareResult unmodifiableCompareResult(
+      final CompareResult result) throws NullPointerException
+  {
+    if (result instanceof UnmodifiableCompareResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableCompareResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable generic extended result using the provided
+   * response.
+   *
+   * @param result
+   *          The generic extended result to be copied.
+   * @return The unmodifiable generic extended result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static GenericExtendedResult unmodifiableGenericExtendedResult(
+      final GenericExtendedResult result) throws NullPointerException
+  {
+    if (result instanceof UnmodifiableGenericExtendedResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableGenericExtendedResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable generic intermediate response using the provided
+   * response.
+   *
+   * @param response
+   *          The generic intermediate response to be copied.
+   * @return The unmodifiable generic intermediate response.
+   * @throws NullPointerException
+   *           If {@code response} was {@code null}.
+   */
+  public static GenericIntermediateResponse unmodifiableGenericIntermediateResponse(
+      final GenericIntermediateResponse response) throws NullPointerException
+  {
+    if (response instanceof UnmodifiableGenericIntermediateResponseImpl)
+    {
+      return response;
+    }
+    return new UnmodifiableGenericIntermediateResponseImpl(response);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable password modify extended result using the provided
+   * response.
+   *
+   * @param result
+   *          The password modify extended result to be copied.
+   * @return The unmodifiable password modify extended result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static PasswordModifyExtendedResult unmodifiablePasswordModifyExtendedResult(
+      final PasswordModifyExtendedResult result) throws NullPointerException
+  {
+    if (result instanceof UnmodifiablePasswordModifyExtendedResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiablePasswordModifyExtendedResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable result using the provided response.
+   *
+   * @param result
+   *          The result to be copied.
+   * @return The unmodifiable result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static Result unmodifiableResult(final Result result)
+      throws NullPointerException
+  {
+    if (result instanceof UnmodifiableResultImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable search result entry using the provided response.
+   *
+   * @param entry
+   *          The search result entry to be copied.
+   * @return The unmodifiable search result entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public static SearchResultEntry unmodifiableSearchResultEntry(
+      final SearchResultEntry entry) throws NullPointerException
+  {
+    if (entry instanceof UnmodifiableSearchResultEntryImpl)
+    {
+      return entry;
+    }
+    return new UnmodifiableSearchResultEntryImpl(entry);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable search result reference using the provided
+   * response.
+   *
+   * @param reference
+   *          The search result reference to be copied.
+   * @return The unmodifiable search result reference.
+   * @throws NullPointerException
+   *           If {@code searchResultReference} was {@code null}.
+   */
+  public static SearchResultReference unmodifiableSearchResultReference(
+      final SearchResultReference reference) throws NullPointerException
+  {
+    if (reference instanceof UnmodifiableSearchResultReferenceImpl)
+    {
+      return reference;
+    }
+    return new UnmodifiableSearchResultReferenceImpl(reference);
+  }
+
+
+
+  /**
+   * Creates an unmodifiable who am I extended result using the provided
+   * response.
+   *
+   * @param result
+   *          The who am I result to be copied.
+   * @return The unmodifiable who am I extended result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null} .
+   */
+  public static WhoAmIExtendedResult unmodifiableWhoAmIExtendedResult(
+      final WhoAmIExtendedResult result) throws NullPointerException
+  {
+    if (result instanceof UnmodifiableSearchResultReferenceImpl)
+    {
+      return result;
+    }
+    return new UnmodifiableWhoAmIExtendedResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates a new bind result that is an exact copy of the provided result.
+   *
+   * @param result
+   *          The bind result to be copied.
+   * @return The new bind result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static BindResult copyOfBindResult(final BindResult result)
+      throws NullPointerException
+  {
+    return new BindResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates a new compare result that is an exact copy of the provided result.
+   *
+   * @param result
+   *          The compare result to be copied.
+   * @return The new compare result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static CompareResult copyOfCompareResult(final CompareResult result)
+      throws NullPointerException
+  {
+    return new CompareResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates a new generic extended result that is an exact copy of the provided
+   * result.
+   *
+   * @param result
+   *          The generic extended result to be copied.
+   * @return The new generic extended result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static GenericExtendedResult copyOfGenericExtendedResult(
+      final GenericExtendedResult result) throws NullPointerException
+  {
+    return new GenericExtendedResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates a new generic intermediate response that is an exact copy of the
+   * provided response.
+   *
+   * @param result
+   *          The generic intermediate response to be copied.
+   * @return The new generic intermediate response.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static GenericIntermediateResponse copyOfGenericIntermediateResponse(
+      final GenericIntermediateResponse result) throws NullPointerException
+  {
+    return new GenericIntermediateResponseImpl(result);
+  }
+
+
+
+  /**
+   * Creates a new password modify extended result that is an exact copy of the
+   * provided result.
+   *
+   * @param result
+   *          The password modify extended result to be copied.
+   * @return The new password modify extended result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static PasswordModifyExtendedResult copyOfPasswordModifyExtendedResult(
+      final PasswordModifyExtendedResult result) throws NullPointerException
+  {
+    return new PasswordModifyExtendedResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates a new result that is an exact copy of the provided result.
+   *
+   * @param result
+   *          The result to be copied.
+   * @return The new result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null}.
+   */
+  public static Result copyOfResult(final Result result)
+      throws NullPointerException
+  {
+    return new ResultImpl(result);
+  }
+
+
+
+  /**
+   * Creates a new search result entry that is an exact copy of the provided
+   * result.
+   *
+   * @param entry
+   *          The search result entry to be copied.
+   * @return The new search result entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public static SearchResultEntry copyOfSearchResultEntry(
+      final SearchResultEntry entry) throws NullPointerException
+  {
+    return new SearchResultEntryImpl(entry);
+  }
+
+
+
+  /**
+   * Creates a new search result reference that is an exact copy of the provided
+   * result.
+   *
+   * @param reference
+   *          The search result reference to be copied.
+   * @return The new search result reference.
+   * @throws NullPointerException
+   *           If {@code reference} was {@code null}.
+   */
+  public static SearchResultReference copyOfSearchResultReference(
+      final SearchResultReference reference) throws NullPointerException
+  {
+    return new SearchResultReferenceImpl(reference);
+  }
+
+
+
+  /**
+   * Creates a new who am I extended result that is an exact copy of the
+   * provided result.
+   *
+   * @param result
+   *          The who am I result to be copied.
+   * @return The new who am I extended result.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null} .
+   */
+  public static WhoAmIExtendedResult copyOfWhoAmIExtendedResult(
+      final WhoAmIExtendedResult result) throws NullPointerException
+  {
+    return new WhoAmIExtendedResultImpl(result);
+  }
+
+
+
+  // Private constructor.
+  private Responses()
+  {
+    // Prevent instantiation.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Result.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Result.java
new file mode 100644
index 0000000..24ecd02
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/Result.java
@@ -0,0 +1,239 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.ResultCode;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A Result is used to indicate the status of an operation performed by the
+ * server. A Result is comprised of several fields:
+ * <ul>
+ * <li>The <b>result code</b> can be retrieved using the method
+ * {@link #getResultCode}. This indicates the overall outcome of the operation.
+ * In particular, whether or not it succeeded which is indicated using a value
+ * of {@link ResultCode#SUCCESS}.
+ * <li>The optional <b>diagnostic message</b> can be retrieved using the method
+ * {@link #getDiagnosticMessage}. At the server's discretion, a diagnostic
+ * message may be included in a Result in order to supplement the result code
+ * with additional human-readable information.
+ * <li>The optional <b>matched DN</b> can be retrieved using the method
+ * {@link #getMatchedDN}. For certain result codes, this is used to indicate to
+ * the client the last entry used in finding the Request's target (or base)
+ * entry.
+ * <li>The optional <b>referrals</b> can be retrieved using the method
+ * {@link #getReferralURIs}. Referrals are present in a Result if the result
+ * code is set to {@link ResultCode#REFERRAL}, and it are absent with all other
+ * result codes.
+ * </ul>
+ */
+public interface Result extends Response
+{
+  /**
+   * {@inheritDoc}
+   */
+  Result addControl(Control control) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Adds the provided referral URI to this result.
+   *
+   * @param uri
+   *          The referral URI to be added.
+   * @return This result.
+   * @throws UnsupportedOperationException
+   *           If this result does not permit referrals to be added.
+   * @throws NullPointerException
+   *           If {@code uri} was {@code null}.
+   */
+  Result addReferralURI(String uri) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * Returns the throwable cause associated with this result if available. A
+   * cause may be provided in cases where a result indicates a failure due to a
+   * client-side error.
+   *
+   * @return The throwable cause, or {@code null} if none was provided.
+   */
+  Throwable getCause();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns the diagnostic message associated with this result.
+   *
+   * @return The diagnostic message, which may be empty if none was provided
+   *         (never {@code null}).
+   */
+  String getDiagnosticMessage();
+
+
+
+  /**
+   * Returns the matched DN associated with this result.
+   *
+   * @return The matched DN, which may be empty if none was provided (never
+   *         {@code null}).
+   */
+  String getMatchedDN();
+
+
+
+  /**
+   * Returns a {@code List} containing the referral URIs included with this
+   * result. The returned {@code List} may be modified if permitted by this
+   * result.
+   *
+   * @return A {@code List} containing the referral URIs.
+   */
+  List<String> getReferralURIs();
+
+
+
+  /**
+   * Returns the result code associated with this result.
+   *
+   * @return The result code.
+   */
+  ResultCode getResultCode();
+
+
+
+  /**
+   * Indicates whether or not a referral needs to be chased in order to complete
+   * the operation.
+   * <p>
+   * Specifically, this method returns {@code true} if the result code is equal
+   * to {@link ResultCode#REFERRAL}.
+   *
+   * @return {@code true} if a referral needs to be chased, otherwise {@code
+   *         false}.
+   */
+  boolean isReferral();
+
+
+
+  /**
+   * Indicates whether or not the request succeeded or not. This method will
+   * return {code true} for all non-error responses.
+   *
+   * @return {@code true} if the request succeeded, otherwise {@code false}.
+   */
+  boolean isSuccess();
+
+
+
+  /**
+   * Sets the throwable cause associated with this result if available. A cause
+   * may be provided in cases where a result indicates a failure due to a
+   * client-side error.
+   *
+   * @param cause
+   *          The throwable cause, which may be {@code null} indicating that
+   *          none was provided.
+   * @return This result.
+   * @throws UnsupportedOperationException
+   *           If this result does not permit the cause to be set.
+   */
+  Result setCause(Throwable cause) throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the diagnostic message associated with this result.
+   *
+   * @param message
+   *          The diagnostic message, which may be empty or {@code null}
+   *          indicating that none was provided.
+   * @return This result.
+   * @throws UnsupportedOperationException
+   *           If this result does not permit the diagnostic message to be set.
+   */
+  Result setDiagnosticMessage(String message)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the matched DN associated with this result.
+   *
+   * @param dn
+   *          The matched DN associated, which may be empty or {@code null}
+   *          indicating that none was provided.
+   * @return This result.
+   * @throws UnsupportedOperationException
+   *           If this result does not permit the matched DN to be set.
+   */
+  Result setMatchedDN(String dn) throws UnsupportedOperationException;
+
+
+
+  /**
+   * Sets the result code associated with this result.
+   *
+   * @param resultCode
+   *          The result code.
+   * @return This result.
+   * @throws UnsupportedOperationException
+   *           If this result does not permit the result code to be set.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  Result setResultCode(ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ResultImpl.java
new file mode 100644
index 0000000..8ae508a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/ResultImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.ResultCode;
+
+
+
+/**
+ * A generic result indicates the final status of an operation.
+ */
+final class ResultImpl extends AbstractResultImpl<Result> implements Result
+{
+
+  /**
+   * Creates a new generic result using the provided result code.
+   *
+   * @param resultCode
+   *          The result code.
+   * @throws NullPointerException
+   *           If {@code resultCode} was {@code null}.
+   */
+  ResultImpl(final ResultCode resultCode) throws NullPointerException
+  {
+    super(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new result that is an exact copy of the provided result.
+   *
+   * @param result
+   *          The result to be copied.
+   * @throws NullPointerException
+   *           If {@code result} was {@code null} .
+   */
+  ResultImpl(final Result result) throws NullPointerException
+  {
+    super(result);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("Result(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  Result getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntry.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntry.java
new file mode 100644
index 0000000..9da4d6a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntry.java
@@ -0,0 +1,240 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.Collection;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A Search Result Entry represents an entry found during a Search operation.
+ * <p>
+ * Each entry returned in a Search Result Entry will contain all appropriate
+ * attributes as specified in the Search request, subject to access control and
+ * other administrative policy.
+ * <p>
+ * Note that a Search Result Entry may hold zero attributes. This may happen
+ * when none of the attributes of an entry were requested or could be returned.
+ * <p>
+ * Note also that each returned attribute may hold zero attribute values. This
+ * may happen when only attribute types are requested, access controls prevent
+ * the return of values, or other reasons.
+ */
+public interface SearchResultEntry extends Response, Entry
+{
+  /**
+   * {@inheritDoc}
+   */
+  boolean addAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean addAttribute(Attribute attribute,
+      Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultEntry addAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultEntry addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultEntry clearAttributes() throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean containsAttribute(Attribute attribute,
+      Collection<ByteString> missingValues) throws NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean containsAttribute(String attributeDescription, Object... values)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Iterable<Attribute> getAllAttributes();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Iterable<Attribute> getAllAttributes(AttributeDescription attributeDescription)
+      throws NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Iterable<Attribute> getAllAttributes(String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Attribute getAttribute(AttributeDescription attributeDescription)
+      throws NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Attribute getAttribute(String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  int getAttributeCount();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  DN getName();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean removeAttribute(Attribute attribute,
+      Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean removeAttribute(AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultEntry removeAttribute(String attributeDescription,
+      Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean replaceAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultEntry replaceAttribute(String attributeDescription,
+      Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultEntry setName(DN dn) throws UnsupportedOperationException,
+      NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultEntry setName(String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntryImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntryImpl.java
new file mode 100644
index 0000000..77c03dc
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultEntryImpl.java
@@ -0,0 +1,360 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.Collection;
+
+import org.opends.sdk.*;
+
+
+
+/**
+ * Search result entry implementation.
+ */
+final class SearchResultEntryImpl extends
+    AbstractResponseImpl<SearchResultEntry> implements SearchResultEntry
+{
+
+  private final Entry entry;
+
+
+
+  /**
+   * Creates a new search result entry backed by the provided entry.
+   * Modifications made to {@code entry} will be reflected in the returned
+   * search result entry. The returned search result entry supports updates to
+   * its list of controls, as well as updates to the name and attributes if the
+   * underlying entry allows.
+   *
+   * @param entry
+   *          The entry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null} .
+   */
+  SearchResultEntryImpl(final Entry entry) throws NullPointerException
+  {
+    this.entry = entry;
+  }
+
+
+
+  /**
+   * Creates a new search result entry that is an exact copy of the provided
+   * result.
+   *
+   * @param searchResultEntry
+   *          The search result entry to be copied.
+   * @throws NullPointerException
+   *           If {@code searchResultEntry} was {@code null} .
+   */
+  SearchResultEntryImpl(final SearchResultEntry searchResultEntry)
+      throws NullPointerException
+  {
+    super(searchResultEntry);
+    this.entry = LinkedHashMapEntry.deepCopyOfEntry(searchResultEntry);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean addAttribute(final Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.addAttribute(attribute);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean addAttribute(final Attribute attribute,
+      final Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.addAttribute(attribute, duplicateValues);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry addAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    entry.addAttribute(attributeDescription, values);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry clearAttributes()
+      throws UnsupportedOperationException
+  {
+    entry.clearAttributes();
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean containsAttribute(final Attribute attribute,
+      final Collection<ByteString> missingValues) throws NullPointerException
+  {
+    return entry.containsAttribute(attribute, missingValues);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean containsAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      NullPointerException
+  {
+    return entry.containsAttribute(attributeDescription, values);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes()
+  {
+    return entry.getAllAttributes();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes(
+      final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    return entry.getAllAttributes(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Iterable<Attribute> getAllAttributes(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return entry.getAllAttributes(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Attribute getAttribute(final AttributeDescription attributeDescription)
+      throws NullPointerException
+  {
+    return entry.getAttribute(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public Attribute getAttribute(final String attributeDescription)
+      throws LocalizedIllegalArgumentException, NullPointerException
+  {
+    return entry.getAttribute(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public int getAttributeCount()
+  {
+    return entry.getAttributeCount();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getName()
+  {
+    return entry.getName();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean removeAttribute(final Attribute attribute,
+      final Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.removeAttribute(attribute, missingValues);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean removeAttribute(final AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.removeAttribute(attributeDescription);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry removeAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    entry.removeAttribute(attributeDescription, values);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean replaceAttribute(final Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    return entry.replaceAttribute(attribute);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry replaceAttribute(final String attributeDescription,
+      final Object... values) throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException
+  {
+    entry.replaceAttribute(attributeDescription, values);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry setName(final DN dn)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    entry.setName(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultEntry setName(final String dn)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException,
+      NullPointerException
+  {
+    entry.setName(dn);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("SearchResultEntry(name=");
+    builder.append(getName());
+    builder.append(", attributes=");
+    builder.append(getAllAttributes());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  SearchResultEntry getThis()
+  {
+    return this;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return entry.hashCode();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object object)
+  {
+    return entry.equals(object);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReference.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReference.java
new file mode 100644
index 0000000..0d6f133
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReference.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * A Search Result Reference represents an area not yet explored during a Search
+ * operation.
+ */
+public interface SearchResultReference extends Response
+{
+  /**
+   * {@inheritDoc}
+   */
+  SearchResultReference addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Adds the provided continuation reference URI to this search result
+   * reference.
+   *
+   * @param uri
+   *          The continuation reference URI to be added.
+   * @return This search result reference.
+   * @throws UnsupportedOperationException
+   *           If this search result reference does not permit continuation
+   *           reference URI to be added.
+   * @throws NullPointerException
+   *           If {@code uri} was {@code null}.
+   */
+  SearchResultReference addURI(String uri)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * Returns a {@code List} containing the continuation reference URIs included
+   * with this search result reference. The returned {@code List} may be
+   * modified if permitted by this search result reference.
+   *
+   * @return A {@code List} containing the continuation reference URIs.
+   */
+  List<String> getURIs();
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReferenceImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReferenceImpl.java
new file mode 100644
index 0000000..9f9c102
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/SearchResultReferenceImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.LinkedList;
+import java.util.List;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Search result reference implementation.
+ */
+final class SearchResultReferenceImpl extends
+    AbstractResponseImpl<SearchResultReference> implements
+    SearchResultReference
+{
+
+  private final List<String> uris = new LinkedList<String>();
+
+
+
+  /**
+   * Creates a new search result reference using the provided continuation
+   * reference URI.
+   *
+   * @param uri
+   *          The first continuation reference URI to be added to this search
+   *          result reference.
+   * @throws NullPointerException
+   *           If {@code uri} was {@code null}.
+   */
+  SearchResultReferenceImpl(final String uri) throws NullPointerException
+  {
+    addURI(uri);
+  }
+
+
+
+  /**
+   * Creates a new search result reference that is an exact copy of the provided
+   * result.
+   *
+   * @param searchResultReference
+   *          The search result reference to be copied.
+   * @throws NullPointerException
+   *           If {@code searchResultReference} was {@code null} .
+   */
+  SearchResultReferenceImpl(final SearchResultReference searchResultReference)
+      throws NullPointerException
+  {
+    super(searchResultReference);
+    this.uris.addAll(searchResultReference.getURIs());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public SearchResultReference addURI(final String uri)
+      throws UnsupportedOperationException, NullPointerException
+  {
+    Validator.ensureNotNull(uri);
+    uris.add(uri);
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public List<String> getURIs()
+  {
+    return uris;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("SearchResultReference(uris=");
+    builder.append(getURIs());
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+
+
+
+  @Override
+  SearchResultReference getThis()
+  {
+    return this;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableBindResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableBindResultImpl.java
new file mode 100644
index 0000000..7b61774
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableBindResultImpl.java
@@ -0,0 +1,57 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable Bind result implementation.
+ */
+class UnmodifiableBindResultImpl
+    extends AbstractUnmodifiableResultImpl<BindResult> implements BindResult
+{
+  public UnmodifiableBindResultImpl(BindResult impl) {
+    super(impl);
+  }
+
+  @Override
+  public ByteString getServerSASLCredentials() {
+    return impl.getServerSASLCredentials();
+  }
+
+  @Override
+  public boolean isSASLBindInProgress() {
+    return impl.isSASLBindInProgress();
+  }
+
+  @Override
+  public BindResult setServerSASLCredentials(ByteString credentials)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableCompareResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableCompareResultImpl.java
new file mode 100644
index 0000000..c2070c5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableCompareResultImpl.java
@@ -0,0 +1,45 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+/**
+ * Unmodifiable Compare result implementation.
+ */
+class UnmodifiableCompareResultImpl
+    extends AbstractUnmodifiableResultImpl<CompareResult>
+    implements CompareResult
+{
+  UnmodifiableCompareResultImpl(CompareResult impl) {
+    super(impl);
+  }
+
+  @Override
+  public boolean matched() {
+    return impl.matched();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericExtendedResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericExtendedResultImpl.java
new file mode 100644
index 0000000..8d03c17
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericExtendedResultImpl.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable Generic extended result implementation.
+ */
+class UnmodifiableGenericExtendedResultImpl extends
+    AbstractUnmodifiableExtendedResultImpl<GenericExtendedResult>
+    implements ExtendedResult, GenericExtendedResult
+{
+  UnmodifiableGenericExtendedResultImpl(GenericExtendedResult impl) {
+    super(impl);
+  }
+
+  @Override
+  public GenericExtendedResult setOID(String oid)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GenericExtendedResult setValue(ByteString bytes)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericIntermediateResponseImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericIntermediateResponseImpl.java
new file mode 100644
index 0000000..f4faa13
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableGenericIntermediateResponseImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable Generic extended result implementation.
+ */
+class UnmodifiableGenericIntermediateResponseImpl extends
+    AbstractUnmodifiableIntermediateResponseImpl<GenericIntermediateResponse>
+    implements GenericIntermediateResponse
+{
+  UnmodifiableGenericIntermediateResponseImpl(
+      GenericIntermediateResponse impl) {
+    super(impl);
+  }
+
+  @Override
+  public GenericIntermediateResponse setOID(String oid)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public GenericIntermediateResponse setValue(ByteString bytes)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiablePasswordModifyExtendedResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiablePasswordModifyExtendedResultImpl.java
new file mode 100644
index 0000000..58b1947
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiablePasswordModifyExtendedResultImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import org.opends.sdk.ByteString;
+
+/**
+ * Unmodifiable Password modify extended result implementation.
+ */
+class UnmodifiablePasswordModifyExtendedResultImpl extends
+    AbstractUnmodifiableExtendedResultImpl<PasswordModifyExtendedResult>
+    implements PasswordModifyExtendedResult
+{
+  UnmodifiablePasswordModifyExtendedResultImpl(
+      PasswordModifyExtendedResult impl) {
+    super(impl);
+  }
+
+  @Override
+  public ByteString getGeneratedPassword() {
+    return impl.getGeneratedPassword();
+  }
+
+  @Override
+  public PasswordModifyExtendedResult setGeneratedPassword(ByteString password)
+      throws UnsupportedOperationException
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public PasswordModifyExtendedResult setGeneratedPassword(char[] password)
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableResultImpl.java
new file mode 100644
index 0000000..0c498dd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableResultImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+/**
+ * A unmodifiable generic result indicates the final status of an operation.
+ */
+class UnmodifiableResultImpl
+    extends AbstractUnmodifiableResultImpl<Result> implements Result
+{
+  UnmodifiableResultImpl(Result impl) {
+    super(impl);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java
new file mode 100644
index 0000000..ee50662
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultEntryImpl.java
@@ -0,0 +1,196 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import com.sun.opends.sdk.util.Function;
+import com.sun.opends.sdk.util.Iterables;
+import org.opends.sdk.*;
+
+import java.util.Collection;
+
+/**
+ * Unmodifiable Search result entry implementation.
+ */
+class UnmodifiableSearchResultEntryImpl  extends
+    AbstractUnmodifiableResponseImpl<SearchResultEntry>
+    implements SearchResultEntry
+{
+  private static final Function<Attribute, Attribute, Void>
+      UNMODIFIABLE_ATTRIBUTE_FUNCTION =
+      new Function<Attribute, Attribute, Void>()
+      {
+
+        public Attribute apply(final Attribute value, final Void p)
+        {
+          return Attributes.unmodifiableAttribute(value);
+        }
+
+      };
+
+  UnmodifiableSearchResultEntryImpl(SearchResultEntry impl) {
+    super(impl);
+  }
+
+  public boolean addAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean addAttribute(Attribute attribute,
+                              Collection<ByteString> duplicateValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchResultEntry addAttribute(String attributeDescription,
+                                        Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchResultEntry clearAttributes()
+      throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean containsAttribute(Attribute attribute,
+                                   Collection<ByteString> missingValues)
+      throws NullPointerException {
+    return impl.containsAttribute(attribute, missingValues);
+  }
+
+  public boolean containsAttribute(String attributeDescription,
+                                   Object... values)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    return impl.containsAttribute(attributeDescription, values);
+  }
+
+  public Iterable<Attribute> getAllAttributes() {
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
+        .getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Iterable<Attribute> getAllAttributes(
+      AttributeDescription attributeDescription)
+      throws NullPointerException {
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
+        .getAllAttributes(attributeDescription),
+        UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Iterable<Attribute> getAllAttributes(
+      String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    return Iterables.unmodifiableIterable(Iterables.transformedIterable(impl
+        .getAllAttributes(attributeDescription),
+        UNMODIFIABLE_ATTRIBUTE_FUNCTION));
+  }
+
+  public Attribute getAttribute(
+      AttributeDescription attributeDescription)
+      throws NullPointerException {
+    final Attribute attribute =
+        impl.getAttribute(attributeDescription);
+    if (attribute != null)
+    {
+      return Attributes.unmodifiableAttribute(attribute);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  public Attribute getAttribute(String attributeDescription)
+      throws LocalizedIllegalArgumentException,
+      NullPointerException {
+    final Attribute attribute =
+        impl.getAttribute(attributeDescription);
+    if (attribute != null)
+    {
+      return Attributes.unmodifiableAttribute(attribute);
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+  public int getAttributeCount() {
+    return impl.getAttributeCount();
+  }
+
+  public DN getName() {
+    return impl.getName();
+  }
+
+  public boolean removeAttribute(Attribute attribute,
+                                 Collection<ByteString> missingValues)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean removeAttribute(
+      AttributeDescription attributeDescription)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchResultEntry removeAttribute(String attributeDescription,
+                                           Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean replaceAttribute(Attribute attribute)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchResultEntry replaceAttribute(String attributeDescription,
+                                            Object... values)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchResultEntry setName(DN dn)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  public SearchResultEntry setName(String dn)
+      throws LocalizedIllegalArgumentException,
+      UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultReferenceImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultReferenceImpl.java
new file mode 100644
index 0000000..48b284d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableSearchResultReferenceImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import java.util.List;
+
+/**
+ * Unmodifiable Search result reference implementation.
+ */
+class UnmodifiableSearchResultReferenceImpl extends
+    AbstractUnmodifiableResponseImpl<SearchResultReference> implements
+    SearchResultReference
+{
+  UnmodifiableSearchResultReferenceImpl(SearchResultReference impl) {
+    super(impl);
+  }
+
+  @Override
+  public SearchResultReference addURI(String uri)
+      throws UnsupportedOperationException, NullPointerException {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public List<String> getURIs() {
+    return impl.getURIs();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableWhoAmIExtendedResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableWhoAmIExtendedResultImpl.java
new file mode 100644
index 0000000..5b004d3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/UnmodifiableWhoAmIExtendedResultImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+/**
+ * Unmodifiable Who Am I extended result implementation.
+ */
+class UnmodifiableWhoAmIExtendedResultImpl extends
+    AbstractUnmodifiableExtendedResultImpl<WhoAmIExtendedResult> implements
+    WhoAmIExtendedResult
+{
+  UnmodifiableWhoAmIExtendedResultImpl(WhoAmIExtendedResult impl) {
+    super(impl);
+  }
+
+  @Override
+  public String getAuthorizationID() {
+    return impl.getAuthorizationID();
+  }
+
+  @Override
+  public WhoAmIExtendedResult setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResult.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResult.java
new file mode 100644
index 0000000..bdce671
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResult.java
@@ -0,0 +1,223 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+
+
+
+/**
+ * The who am I extended result as defined in RFC 4532. The result includes the
+ * primary authorization identity, in its primary form, that the server has
+ * associated with the user or application entity, but only if the who am I
+ * request succeeded.
+ * <p>
+ * The authorization identity is specified using an authorization ID, or {@code
+ * authzId}, as defined in RFC 4513 section 5.2.1.8.
+ *
+ * @see org.opends.sdk.requests.WhoAmIExtendedRequest
+ * @see org.opends.sdk.controls.AuthorizationIdentityRequestControl
+ * @see <a href="http://tools.ietf.org/html/rfc4532">RFC 4532 - Lightweight
+ *      Directory Access Protocol (LDAP) "Who am I?" Operation </a>
+ * @see <a href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513 -
+ *      SASL Authorization Identities (authzId) </a>
+ */
+public interface WhoAmIExtendedResult extends ExtendedResult
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  WhoAmIExtendedResult addControl(Control control)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  WhoAmIExtendedResult addReferralURI(String uri)
+      throws UnsupportedOperationException, NullPointerException;
+
+
+
+  /**
+   * Returns the authorization ID of the user. The authorization ID usually has
+   * the form "dn:" immediately followed by the distinguished name of the user,
+   * or "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @return The authorization ID of the user, or {@code null} if this result
+   *         does not contain an authorization ID.
+   */
+  String getAuthorizationID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  Throwable getCause();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  <C extends Control> C getControl(ControlDecoder<C> decoder,
+      DecodeOptions options) throws NullPointerException, DecodeException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<Control> getControls();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getDiagnosticMessage();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getMatchedDN();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  String getOID();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  List<String> getReferralURIs();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ResultCode getResultCode();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  ByteString getValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean hasValue();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isReferral();
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  boolean isSuccess();
+
+
+
+  /**
+   * Sets the authorization ID of the user. The authorization ID usually has the
+   * form "dn:" immediately followed by the distinguished name of the user, or
+   * "u:" followed by a user ID string, but other forms are permitted.
+   *
+   * @param authorizationID
+   *          The authorization ID of the user, which may be {@code null} if
+   *          this result does not contain an authorization ID.
+   * @return This who am I result.
+   * @throws LocalizedIllegalArgumentException
+   *           If {@code authorizationID} was non-empty and did not contain a
+   *           valid authorization ID type.
+   * @throws UnsupportedOperationException
+   *           If this who am I extended result does not permit the
+   *           authorization ID to be set.
+   */
+  WhoAmIExtendedResult setAuthorizationID(String authorizationID)
+      throws LocalizedIllegalArgumentException, UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  WhoAmIExtendedResult setCause(Throwable cause)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  WhoAmIExtendedResult setDiagnosticMessage(String message)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  WhoAmIExtendedResult setMatchedDN(String dn)
+      throws UnsupportedOperationException;
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  WhoAmIExtendedResult setResultCode(ResultCode resultCode)
+      throws UnsupportedOperationException, NullPointerException;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResultImpl.java
new file mode 100644
index 0000000..577ab11
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/WhoAmIExtendedResultImpl.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_WHOAMI_INVALID_AUTHZID_TYPE;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.opends.sdk.ResultCode;
+
+
+
+/**
+ * Who Am I extended result implementation.
+ */
+final class WhoAmIExtendedResultImpl extends
+    AbstractExtendedResult<WhoAmIExtendedResult> implements
+    WhoAmIExtendedResult
+{
+
+  // The authorization ID.
+  private String authorizationID = null;
+
+
+
+  // Instantiation via factory.
+  WhoAmIExtendedResultImpl(final ResultCode resultCode)
+  {
+    super(resultCode);
+  }
+
+
+
+  /**
+   * Creates a new who am I extended result that is an exact copy of the
+   * provided result.
+   *
+   * @param whoAmIExtendedResult
+   *          The who am I extended result to be copied.
+   * @throws NullPointerException
+   *           If {@code whoAmIExtendedResult} was {@code null} .
+   */
+  WhoAmIExtendedResultImpl(final WhoAmIExtendedResult whoAmIExtendedResult)
+      throws NullPointerException
+  {
+    super(whoAmIExtendedResult);
+    this.authorizationID = whoAmIExtendedResult.getAuthorizationID();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getAuthorizationID()
+  {
+    return authorizationID;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getOID()
+  {
+    // No response name defined.
+    return null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ByteString getValue()
+  {
+    return (authorizationID != null) ? ByteString.valueOf(authorizationID)
+        : null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean hasValue()
+  {
+    return (authorizationID != null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public WhoAmIExtendedResult setAuthorizationID(final String authorizationID)
+      throws LocalizedIllegalArgumentException
+  {
+    if (authorizationID != null && authorizationID.length() != 0)
+    {
+      final int colonIndex = authorizationID.indexOf(':');
+      if (colonIndex < 0)
+      {
+        final LocalizableMessage message = ERR_WHOAMI_INVALID_AUTHZID_TYPE
+            .get(authorizationID);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+    }
+
+    this.authorizationID = authorizationID;
+    return this;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    final StringBuilder builder = new StringBuilder();
+    builder.append("WhoAmIExtendedResponse(resultCode=");
+    builder.append(getResultCode());
+    builder.append(", matchedDN=");
+    builder.append(getMatchedDN());
+    builder.append(", diagnosticMessage=");
+    builder.append(getDiagnosticMessage());
+    builder.append(", referrals=");
+    builder.append(getReferralURIs());
+    builder.append(", authzId=");
+    builder.append(authorizationID);
+    builder.append(", controls=");
+    builder.append(getControls());
+    builder.append(")");
+    return builder.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/package-info.java
new file mode 100755
index 0000000..66a69da
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/responses/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes and interfaces for core LDAP responses.
+ */
+package org.opends.sdk.responses;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractMatchingRuleImpl.java
new file mode 100644
index 0000000..2e9309c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractMatchingRuleImpl.java
@@ -0,0 +1,133 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import java.util.Comparator;
+import java.util.List;
+
+import org.opends.sdk.Assertion;
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * This class implements a default equality or approximate matching rule that
+ * matches normalized values in byte order.
+ */
+abstract class AbstractMatchingRuleImpl implements MatchingRuleImpl
+{
+  static class DefaultEqualityAssertion implements Assertion
+  {
+    ByteSequence normalizedAssertionValue;
+
+
+
+    protected DefaultEqualityAssertion(
+        final ByteSequence normalizedAssertionValue)
+    {
+      this.normalizedAssertionValue = normalizedAssertionValue;
+    }
+
+
+
+    public ConditionResult matches(final ByteSequence attributeValue)
+    {
+      return normalizedAssertionValue.equals(attributeValue) ? ConditionResult.TRUE
+          : ConditionResult.FALSE;
+    }
+  }
+
+
+
+  private static final Assertion UNDEFINED_ASSERTION = new Assertion()
+  {
+    public ConditionResult matches(final ByteSequence attributeValue)
+    {
+      return ConditionResult.UNDEFINED;
+    }
+  };
+
+  private static final Comparator<ByteSequence> DEFAULT_COMPARATOR = new Comparator<ByteSequence>()
+  {
+    public int compare(final ByteSequence o1, final ByteSequence o2)
+    {
+      return o1.compareTo(o2);
+    }
+  };
+
+
+
+  AbstractMatchingRuleImpl()
+  {
+    // Nothing to do.
+  }
+
+
+
+  public Comparator<ByteSequence> comparator(final Schema schema)
+  {
+    return DEFAULT_COMPARATOR;
+  }
+
+
+
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    return new DefaultEqualityAssertion(normalizeAttributeValue(schema, value));
+  }
+
+
+
+  public Assertion getAssertion(final Schema schema,
+      final ByteSequence subInitial,
+      final List<? extends ByteSequence> subAnyElements,
+      final ByteSequence subFinal) throws DecodeException
+  {
+    return UNDEFINED_ASSERTION;
+  }
+
+
+
+  public Assertion getGreaterOrEqualAssertion(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    return UNDEFINED_ASSERTION;
+  }
+
+
+
+  public Assertion getLessOrEqualAssertion(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    return UNDEFINED_ASSERTION;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..db6822b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractOrderingMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.*;
+
+
+
+/**
+ * This class implements a default ordering matching rule that matches
+ * normalized values in byte order.
+ */
+abstract class AbstractOrderingMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  AbstractOrderingMatchingRuleImpl()
+  {
+    // Nothing to do.
+  }
+
+
+
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    final ByteString normAssertion = normalizeAttributeValue(schema, value);
+    return new Assertion()
+    {
+      public ConditionResult matches(final ByteSequence attributeValue)
+      {
+        return attributeValue.compareTo(normAssertion) < 0 ? ConditionResult.TRUE
+            : ConditionResult.FALSE;
+      }
+    };
+  }
+
+
+
+  @Override
+  public Assertion getGreaterOrEqualAssertion(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final ByteString normAssertion = normalizeAttributeValue(schema, value);
+    return new Assertion()
+    {
+      public ConditionResult matches(final ByteSequence attributeValue)
+      {
+        return attributeValue.compareTo(normAssertion) >= 0 ? ConditionResult.TRUE
+            : ConditionResult.FALSE;
+      }
+    };
+  }
+
+
+
+  @Override
+  public Assertion getLessOrEqualAssertion(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final ByteString normAssertion = normalizeAttributeValue(schema, value);
+    return new Assertion()
+    {
+      public ConditionResult matches(final ByteSequence attributeValue)
+      {
+        return attributeValue.compareTo(normAssertion) <= 0 ? ConditionResult.TRUE
+            : ConditionResult.FALSE;
+      }
+    };
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..1885f48
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSubstringMatchingRuleImpl.java
@@ -0,0 +1,539 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements a default substring matching rule that matches
+ * normalized substring assertion values in byte order.
+ */
+abstract class AbstractSubstringMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  static class DefaultSubstringAssertion implements Assertion
+  {
+    private final ByteString normInitial;
+    private final ByteString[] normAnys;
+    private final ByteString normFinal;
+
+
+
+    protected DefaultSubstringAssertion(final ByteString normInitial,
+        final ByteString[] normAnys, final ByteString normFinal)
+    {
+      this.normInitial = normInitial;
+      this.normAnys = normAnys;
+      this.normFinal = normFinal;
+    }
+
+
+
+    public ConditionResult matches(final ByteSequence attributeValue)
+    {
+      final int valueLength = attributeValue.length();
+
+      int pos = 0;
+      if (normInitial != null)
+      {
+        final int initialLength = normInitial.length();
+        if (initialLength > valueLength)
+        {
+          return ConditionResult.FALSE;
+        }
+
+        for (; pos < initialLength; pos++)
+        {
+          if (normInitial.byteAt(pos) != attributeValue.byteAt(pos))
+          {
+            return ConditionResult.FALSE;
+          }
+        }
+      }
+
+      if (normAnys != null && normAnys.length != 0)
+      {
+        for (final ByteSequence element : normAnys)
+        {
+          final int anyLength = element.length();
+          if (anyLength == 0)
+          {
+            continue;
+          }
+          final int end = valueLength - anyLength;
+          boolean match = false;
+          for (; pos <= end; pos++)
+          {
+            if (element.byteAt(0) == attributeValue.byteAt(pos))
+            {
+              boolean subMatch = true;
+              for (int i = 1; i < anyLength; i++)
+              {
+                if (element.byteAt(i) != attributeValue.byteAt(pos + i))
+                {
+                  subMatch = false;
+                  break;
+                }
+              }
+
+              if (subMatch)
+              {
+                match = subMatch;
+                break;
+              }
+            }
+          }
+
+          if (match)
+          {
+            pos += anyLength;
+          }
+          else
+          {
+            return ConditionResult.FALSE;
+          }
+        }
+      }
+
+      if (normFinal != null)
+      {
+        final int finalLength = normFinal.length();
+
+        if (valueLength - finalLength < pos)
+        {
+          return ConditionResult.FALSE;
+        }
+
+        pos = valueLength - finalLength;
+        for (int i = 0; i < finalLength; i++, pos++)
+        {
+          if (normFinal.byteAt(i) != attributeValue.byteAt(pos))
+          {
+            return ConditionResult.FALSE;
+          }
+        }
+      }
+
+      return ConditionResult.TRUE;
+    }
+  }
+
+
+
+  AbstractSubstringMatchingRuleImpl()
+  {
+    // Nothing to do.
+  }
+
+
+
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    if (value.length() == 0)
+    {
+      throw DecodeException.error(WARN_ATTR_SYNTAX_SUBSTRING_EMPTY.get());
+    }
+
+    ByteSequence initialString = null;
+    ByteSequence finalString = null;
+    List<ByteSequence> anyStrings = null;
+
+    final String valueString = value.toString();
+
+    if (valueString.length() == 1 && valueString.charAt(0) == '*')
+    {
+      return getAssertion(schema, initialString, anyStrings, finalString);
+    }
+
+    final char[] escapeChars = new char[] { '*' };
+    final SubstringReader reader = new SubstringReader(valueString);
+
+    ByteString bytes = evaluateEscapes(reader, escapeChars, false);
+    if (bytes.length() > 0)
+    {
+      initialString = normalizeSubString(schema, bytes);
+    }
+    if (reader.remaining() == 0)
+    {
+      throw DecodeException.error(WARN_ATTR_SYNTAX_SUBSTRING_NO_WILDCARDS
+          .get(value.toString()));
+    }
+    while (true)
+    {
+      reader.read();
+      bytes = evaluateEscapes(reader, escapeChars, false);
+      if (reader.remaining() > 0)
+      {
+        if (bytes.length() == 0)
+        {
+          throw DecodeException
+              .error(WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS.get(value
+                  .toString(), reader.pos()));
+        }
+        if (anyStrings == null)
+        {
+          anyStrings = new LinkedList<ByteSequence>();
+        }
+        anyStrings.add(normalizeSubString(schema, bytes));
+      }
+      else
+      {
+        if (bytes.length() > 0)
+        {
+          finalString = normalizeSubString(schema, bytes);
+        }
+        break;
+      }
+    }
+
+    return getAssertion(schema, initialString, anyStrings, finalString);
+  }
+
+
+
+  @Override
+  public Assertion getAssertion(final Schema schema,
+      final ByteSequence subInitial,
+      final List<? extends ByteSequence> subAnyElements,
+      final ByteSequence subFinal) throws DecodeException
+  {
+    final ByteString normInitial = subInitial == null ? null
+        : normalizeSubString(schema, subInitial);
+
+    ByteString[] normAnys = null;
+    if (subAnyElements != null && !subAnyElements.isEmpty())
+    {
+      normAnys = new ByteString[subAnyElements.size()];
+      for (int i = 0; i < subAnyElements.size(); i++)
+      {
+        normAnys[i] = normalizeSubString(schema, subAnyElements.get(i));
+      }
+    }
+    final ByteString normFinal = subFinal == null ? null : normalizeSubString(
+        schema, subFinal);
+
+    return new DefaultSubstringAssertion(normInitial, normAnys, normFinal);
+  }
+
+
+
+  ByteString normalizeSubString(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    return normalizeAttributeValue(schema, value);
+  }
+
+
+
+  private char evaluateEscapedChar(final SubstringReader reader,
+      final char[] escapeChars) throws DecodeException
+  {
+    final char c1 = reader.read();
+    byte b;
+    switch (c1)
+    {
+    case '0':
+      b = 0x00;
+      break;
+    case '1':
+      b = 0x10;
+      break;
+    case '2':
+      b = 0x20;
+      break;
+    case '3':
+      b = 0x30;
+      break;
+    case '4':
+      b = 0x40;
+      break;
+    case '5':
+      b = 0x50;
+      break;
+    case '6':
+      b = 0x60;
+      break;
+    case '7':
+      b = 0x70;
+      break;
+    case '8':
+      b = (byte) 0x80;
+      break;
+    case '9':
+      b = (byte) 0x90;
+      break;
+    case 'A':
+    case 'a':
+      b = (byte) 0xA0;
+      break;
+    case 'B':
+    case 'b':
+      b = (byte) 0xB0;
+      break;
+    case 'C':
+    case 'c':
+      b = (byte) 0xC0;
+      break;
+    case 'D':
+    case 'd':
+      b = (byte) 0xD0;
+      break;
+    case 'E':
+    case 'e':
+      b = (byte) 0xE0;
+      break;
+    case 'F':
+    case 'f':
+      b = (byte) 0xF0;
+      break;
+    default:
+      if (c1 == 0x5C)
+      {
+        return c1;
+      }
+      if (escapeChars != null)
+      {
+        for (final char escapeChar : escapeChars)
+        {
+          if (c1 == escapeChar)
+          {
+            return c1;
+          }
+        }
+      }
+      final LocalizableMessage message = ERR_INVALID_ESCAPE_CHAR.get(reader
+          .getString(), c1);
+      throw DecodeException.error(message);
+    }
+
+    // The two positions must be the hex characters that
+    // comprise the escaped value.
+    if (reader.remaining() == 0)
+    {
+      final LocalizableMessage message = ERR_HEX_DECODE_INVALID_LENGTH
+          .get(reader.getString());
+
+      throw DecodeException.error(message);
+    }
+
+    final char c2 = reader.read();
+    switch (c2)
+    {
+    case '0':
+      // No action required.
+      break;
+    case '1':
+      b |= 0x01;
+      break;
+    case '2':
+      b |= 0x02;
+      break;
+    case '3':
+      b |= 0x03;
+      break;
+    case '4':
+      b |= 0x04;
+      break;
+    case '5':
+      b |= 0x05;
+      break;
+    case '6':
+      b |= 0x06;
+      break;
+    case '7':
+      b |= 0x07;
+      break;
+    case '8':
+      b |= 0x08;
+      break;
+    case '9':
+      b |= 0x09;
+      break;
+    case 'A':
+    case 'a':
+      b |= 0x0A;
+      break;
+    case 'B':
+    case 'b':
+      b |= 0x0B;
+      break;
+    case 'C':
+    case 'c':
+      b |= 0x0C;
+      break;
+    case 'D':
+    case 'd':
+      b |= 0x0D;
+      break;
+    case 'E':
+    case 'e':
+      b |= 0x0E;
+      break;
+    case 'F':
+    case 'f':
+      b |= 0x0F;
+      break;
+    default:
+      final LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get(
+          new String(new char[] { c1, c2 }), c1);
+      throw DecodeException.error(message);
+    }
+    return (char) b;
+  }
+
+
+
+  private ByteString evaluateEscapes(final SubstringReader reader,
+      final char[] escapeChars, final boolean trim) throws DecodeException
+  {
+    return evaluateEscapes(reader, escapeChars, escapeChars, trim);
+  }
+
+
+
+  private ByteString evaluateEscapes(final SubstringReader reader,
+      final char[] escapeChars, final char[] delimiterChars, final boolean trim)
+      throws DecodeException
+  {
+    int length = 0;
+    int lengthWithoutSpace = 0;
+    char c;
+    ByteStringBuilder valueBuffer = null;
+
+    if (trim)
+    {
+      reader.skipWhitespaces();
+    }
+
+    reader.mark();
+    while (reader.remaining() > 0)
+    {
+      c = reader.read();
+      if (c == 0x5C) // The backslash character
+      {
+        if (valueBuffer == null)
+        {
+          valueBuffer = new ByteStringBuilder();
+        }
+        valueBuffer.append(reader.read(length));
+        valueBuffer.append(evaluateEscapedChar(reader, escapeChars));
+        reader.mark();
+        length = lengthWithoutSpace = 0;
+      }
+      if (delimiterChars != null)
+      {
+        for (final char delimiterChar : delimiterChars)
+        {
+          if (c == delimiterChar)
+          {
+            reader.reset();
+            if (valueBuffer != null)
+            {
+              if (trim)
+              {
+                valueBuffer.append(reader.read(lengthWithoutSpace));
+              }
+              else
+              {
+                valueBuffer.append(reader.read(length));
+              }
+              return valueBuffer.toByteString();
+            }
+            else
+            {
+              if (trim)
+              {
+                if (lengthWithoutSpace > 0)
+                {
+                  return ByteString.valueOf(reader.read(lengthWithoutSpace));
+                }
+                return ByteString.empty();
+              }
+              if (length > 0)
+              {
+                return ByteString.valueOf(reader.read(length));
+              }
+              return ByteString.empty();
+            }
+          }
+        }
+      }
+      length++;
+      if (c != ' ')
+      {
+        lengthWithoutSpace = length;
+      }
+      else
+      {
+        lengthWithoutSpace++;
+      }
+    }
+
+    reader.reset();
+    if (valueBuffer != null)
+    {
+      if (trim)
+      {
+        valueBuffer.append(reader.read(lengthWithoutSpace));
+      }
+      else
+      {
+        valueBuffer.append(reader.read(length));
+      }
+      return valueBuffer.toByteString();
+    }
+    else
+    {
+      if (trim)
+      {
+        if (lengthWithoutSpace > 0)
+        {
+          return ByteString.valueOf(reader.read(lengthWithoutSpace));
+        }
+        return ByteString.empty();
+      }
+      if (length > 0)
+      {
+        return ByteString.valueOf(reader.read(length));
+      }
+      return ByteString.empty();
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSyntaxImpl.java
new file mode 100644
index 0000000..81ac6a0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AbstractSyntaxImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+/**
+ * This class defines the set of methods and structures that must be implemented
+ * to define a new attribute syntax.
+ */
+abstract class AbstractSyntaxImpl implements SyntaxImpl
+{
+  AbstractSyntaxImpl()
+  {
+    // Nothing to do.
+  }
+
+
+
+  public String getApproximateMatchingRule()
+  {
+    return null;
+  }
+
+
+
+  public String getEqualityMatchingRule()
+  {
+    return null;
+  }
+
+
+
+  public String getOrderingMatchingRule()
+  {
+    return null;
+  }
+
+
+
+  public String getSubstringMatchingRule()
+  {
+    return null;
+  }
+
+
+
+  public boolean isBEREncodingRequired()
+  {
+    return false;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeType.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeType.java
new file mode 100644
index 0000000..bba7148
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeType.java
@@ -0,0 +1,900 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.SCHEMA_PROPERTY_APPROX_RULE;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a data structure for storing and interacting with an
+ * attribute type, which contains information about the format of an attribute
+ * and the syntax and matching rules that should be used when interacting with
+ * it.
+ * <p>
+ * Where ordered sets of names, or extra properties are provided, the ordering
+ * will be preserved when the associated fields are accessed via their getters
+ * or via the {@link #toString()} methods.
+ */
+public final class AttributeType extends SchemaElement implements
+    Comparable<AttributeType>
+{
+
+  // The approximate matching rule for this attribute type.
+  private final String approximateMatchingRuleOID;
+
+  // The attribute usage for this attribute type.
+  private final AttributeUsage attributeUsage;
+
+  // The definition string used to create this objectclass.
+  private final String definition;
+
+  // The equality matching rule for this attribute type.
+  private final String equalityMatchingRuleOID;
+
+  // Indicates whether this attribute type is declared "collective".
+  private final boolean isCollective;
+
+  // Indicates whether this attribute type is declared
+  // "no-user-modification".
+  private final boolean isNoUserModification;
+
+  // Indicates whether this definition is declared "obsolete".
+  private final boolean isObsolete;
+
+  // Indicates whether this attribute type is declared "single-value".
+  private final boolean isSingleValue;
+
+  // The set of user defined names for this definition.
+  private final List<String> names;
+
+  // The OID that may be used to reference this definition.
+  private final String oid;
+
+  // The ordering matching rule for this attribute type.
+  private final String orderingMatchingRuleOID;
+
+  // The substring matching rule for this attribute type.
+  private final String substringMatchingRuleOID;
+
+  // The superior attribute type from which this attribute type
+  // inherits.
+  private final String superiorTypeOID;
+
+  // The syntax for this attribute type.
+  private final String syntaxOID;
+
+  // True if this type has OID 2.5.4.0.
+  private final boolean isObjectClassType;
+
+  // The normalized name of this attribute type.
+  private final String normalizedName;
+
+  // The superior attribute type from which this attribute type
+  // inherits.
+  private AttributeType superiorType;
+
+  // The equality matching rule for this attribute type.
+  private MatchingRule equalityMatchingRule;
+
+  // The ordering matching rule for this attribute type.
+  private MatchingRule orderingMatchingRule;
+
+  // The substring matching rule for this attribute type.
+  private MatchingRule substringMatchingRule;
+
+  // The approximate matching rule for this attribute type.
+  private MatchingRule approximateMatchingRule;
+
+  // The syntax for this attribute type.
+  private Syntax syntax;
+
+
+
+  AttributeType(final String oid, final List<String> names,
+      final String description, final boolean obsolete,
+      final String superiorType, final String equalityMatchingRule,
+      final String orderingMatchingRule, final String substringMatchingRule,
+      final String approximateMatchingRule, final String syntax,
+      final boolean singleValue, final boolean collective,
+      final boolean noUserModification, final AttributeUsage attributeUsage,
+      final Map<String, List<String>> extraProperties, final String definition)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(oid, names, description, attributeUsage);
+    Validator.ensureTrue(superiorType != null || syntax != null,
+        "superiorType and/or syntax must not be null");
+    Validator.ensureNotNull(extraProperties);
+
+    this.oid = oid;
+    this.names = names;
+    this.isObsolete = obsolete;
+    this.superiorTypeOID = superiorType;
+    this.equalityMatchingRuleOID = equalityMatchingRule;
+    this.orderingMatchingRuleOID = orderingMatchingRule;
+    this.substringMatchingRuleOID = substringMatchingRule;
+    this.approximateMatchingRuleOID = approximateMatchingRule;
+    this.syntaxOID = syntax;
+    this.isSingleValue = singleValue;
+    this.isCollective = collective;
+    this.isNoUserModification = noUserModification;
+    this.attributeUsage = attributeUsage;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+
+    this.isObjectClassType = oid.equals("2.5.4.0");
+    this.normalizedName = StaticUtils.toLowerCase(getNameOrOID());
+  }
+
+
+
+  AttributeType(final String oid, final List<String> names,
+      final String description, final MatchingRule equalityMatchingRule,
+      final Syntax syntax)
+  {
+    super(description, Collections.<String, List<String>> emptyMap());
+
+    Validator.ensureNotNull(oid, names, description);
+
+    this.oid = oid;
+    this.names = names;
+    this.isObsolete = false;
+    this.superiorTypeOID = null;
+    this.superiorType = null;
+    this.equalityMatchingRuleOID = equalityMatchingRule.getOID();
+    this.equalityMatchingRule = equalityMatchingRule;
+    this.orderingMatchingRuleOID = null;
+    this.substringMatchingRuleOID = null;
+    this.approximateMatchingRuleOID = null;
+    this.syntaxOID = syntax.getOID();
+    this.syntax = syntax;
+    this.isSingleValue = false;
+    this.isCollective = false;
+    this.isNoUserModification = false;
+    this.attributeUsage = AttributeUsage.USER_APPLICATIONS;
+    this.definition = buildDefinition();
+
+    this.isObjectClassType = oid.equals("2.5.4.0");
+    this.normalizedName = StaticUtils.toLowerCase(getNameOrOID());
+  }
+
+
+
+  /**
+   * Compares this attribute type to the provided attribute type. The sort-order
+   * is defined as follows:
+   * <ul>
+   * <li>The {@code objectClass} attribute is less than all other attribute
+   * types.
+   * <li>User attributes are less than operational attributes.
+   * <li>Lexicographic comparison of the primary name or OID.
+   * </ul>
+   *
+   * @param type
+   *          The attribute type to be compared.
+   * @return A negative integer, zero, or a positive integer as this attribute
+   *         type is less than, equal to, or greater than the specified
+   *         attribute type.
+   * @throws NullPointerException
+   *           If {@code name} was {@code null}.
+   */
+  public int compareTo(final AttributeType type) throws NullPointerException
+  {
+    if (isObjectClassType)
+    {
+      return type.isObjectClassType ? 0 : -1;
+    }
+    else if (type.isObjectClassType)
+    {
+      return 1;
+    }
+    else
+    {
+      final boolean isOperational = getUsage().isOperational();
+      final boolean typeIsOperational = type.getUsage().isOperational();
+
+      if (isOperational == typeIsOperational)
+      {
+        return normalizedName.compareTo(type.normalizedName);
+      }
+      else
+      {
+        return isOperational ? 1 : -1;
+      }
+    }
+  }
+
+
+
+  @Override
+  public boolean equals(final Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+
+    if (o instanceof AttributeType)
+    {
+      final AttributeType other = (AttributeType) o;
+      return oid.equals(other.oid);
+    }
+
+    return false;
+  }
+
+
+
+  /**
+   * Returns the matching rule that should be used for approximate matching with
+   * this attribute type.
+   *
+   * @return The matching rule that should be used for approximate matching with
+   *         this attribute type.
+   */
+  public MatchingRule getApproximateMatchingRule()
+  {
+    return approximateMatchingRule;
+  }
+
+
+
+  /**
+   * Returns the matching rule that should be used for equality matching with
+   * this attribute type.
+   *
+   * @return The matching rule that should be used for equality matching with
+   *         this attribute type.
+   */
+  public MatchingRule getEqualityMatchingRule()
+  {
+    return equalityMatchingRule;
+  }
+
+
+
+  /**
+   * Returns the name or OID for this schema definition. If it has one or more
+   * names, then the primary name will be returned. If it does not have any
+   * names, then the OID will be returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public String getNameOrOID()
+  {
+    if (names.isEmpty())
+    {
+      return oid;
+    }
+    return names.get(0);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the user-defined names that may be
+   * used to reference this schema definition.
+   *
+   * @return Returns an unmodifiable list containing the user-defined names that
+   *         may be used to reference this schema definition.
+   */
+  public List<String> getNames()
+  {
+    return names;
+  }
+
+
+
+  /**
+   * Returns the OID for this schema definition.
+   *
+   * @return The OID for this schema definition.
+   */
+  public String getOID()
+  {
+
+    return oid;
+  }
+
+
+
+  /**
+   * Returns the matching rule that should be used for ordering with this
+   * attribute type.
+   *
+   * @return The matching rule that should be used for ordering with this
+   *         attribute type.
+   */
+  public MatchingRule getOrderingMatchingRule()
+  {
+    return orderingMatchingRule;
+  }
+
+
+
+  /**
+   * Returns the matching rule that should be used for substring matching with
+   * this attribute type.
+   *
+   * @return The matching rule that should be used for substring matching with
+   *         this attribute type.
+   */
+  public MatchingRule getSubstringMatchingRule()
+  {
+    return substringMatchingRule;
+  }
+
+
+
+  /**
+   * Returns the superior type for this attribute type.
+   *
+   * @return The superior type for this attribute type, or <CODE>null</CODE> if
+   *         it does not have one.
+   */
+  public AttributeType getSuperiorType()
+  {
+    return superiorType;
+  }
+
+
+
+  /**
+   * Returns the syntax for this attribute type.
+   *
+   * @return The syntax for this attribute type.
+   */
+  public Syntax getSyntax()
+  {
+    return syntax;
+  }
+
+
+
+  /**
+   * Returns the usage indicator for this attribute type.
+   *
+   * @return The usage indicator for this attribute type.
+   */
+  public AttributeUsage getUsage()
+  {
+    return attributeUsage;
+  }
+
+
+
+  @Override
+  public int hashCode()
+  {
+    return oid.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name.
+   *
+   * @param name
+   *          The name for which to make the determination.
+   * @return {@code true} if the specified name is assigned to this schema
+   *         definition, or {@code false} if not.
+   */
+  public boolean hasName(final String name)
+  {
+    for (final String n : names)
+    {
+      if (n.equalsIgnoreCase(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name or OID.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return {@code true} if the provided value matches the OID or one of the
+   *         names assigned to this schema definition, or {@code false} if not.
+   */
+  public boolean hasNameOrOID(final String value)
+  {
+    return hasName(value) || getOID().equals(value);
+  }
+
+
+
+  /**
+   * Indicates whether this attribute type is declared "collective".
+   *
+   * @return {@code true} if this attribute type is declared "collective", or
+   *         {@code false} if not.
+   */
+  public boolean isCollective()
+  {
+    return isCollective;
+  }
+
+
+
+  /**
+   * Indicates whether this attribute type is declared "no-user-modification".
+   *
+   * @return {@code true} if this attribute type is declared
+   *         "no-user-modification", or {@code false} if not.
+   */
+  public boolean isNoUserModification()
+  {
+    return isNoUserModification;
+  }
+
+
+
+  /**
+   * Indicates whether or not this attribute type is the {@code objectClass}
+   * attribute type having the OID 2.5.4.0.
+   *
+   * @return {@code true} if this attribute type is the {@code objectClass}
+   *         attribute type, or {@code false} if not.
+   */
+  public boolean isObjectClass()
+  {
+    return isObjectClassType;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition is declared "obsolete".
+   *
+   * @return {@code true} if this schema definition is declared "obsolete", or
+   *         {@code false} if not.
+   */
+  public boolean isObsolete()
+  {
+    return isObsolete;
+  }
+
+
+
+  /**
+   * Indicates whether this is an operational attribute. An operational
+   * attribute is one with a usage of "directoryOperation",
+   * "distributedOperation", or "dSAOperation" (i.e., only userApplications is
+   * not operational).
+   *
+   * @return {@code true} if this is an operational attribute, or {@code false}
+   *         if not.
+   */
+  public boolean isOperational()
+  {
+    return attributeUsage.isOperational();
+  }
+
+
+
+  /**
+   * Indicates whether this attribute type is declared "single-value".
+   *
+   * @return {@code true} if this attribute type is declared "single-value", or
+   *         {@code false} if not.
+   */
+  public boolean isSingleValue()
+  {
+    return isSingleValue;
+  }
+
+
+
+  /**
+   * Indicates whether or not this attribute type is a sub-type of the provided
+   * attribute type.
+   *
+   * @param type
+   *          The attribute type for which to make the determination.
+   * @return {@code true} if this attribute type is a sub-type of the provided
+   *         attribute type, or {@code false} if not.
+   * @throws NullPointerException
+   *           If {@code type} was {@code null}.
+   */
+  public boolean isSubTypeOf(final AttributeType type)
+      throws NullPointerException
+  {
+    AttributeType tmp = this;
+    do
+    {
+      if (tmp.equals(type))
+      {
+        return true;
+      }
+      tmp = tmp.getSuperiorType();
+    }
+    while (tmp != null);
+    return false;
+  }
+
+
+
+  /**
+   * Returns the string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  AttributeType duplicate()
+  {
+    return new AttributeType(oid, names, description, isObsolete,
+        superiorTypeOID, equalityMatchingRuleOID, orderingMatchingRuleOID,
+        substringMatchingRuleOID, approximateMatchingRuleOID, syntaxOID,
+        isSingleValue, isCollective, isNoUserModification, attributeUsage,
+        extraProperties, definition);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(oid);
+
+    if (!names.isEmpty())
+    {
+      final Iterator<String> iterator = names.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NAME ( '");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append("' '");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append("' )");
+      }
+      else
+      {
+        buffer.append(" NAME '");
+        buffer.append(firstName);
+        buffer.append("'");
+      }
+    }
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+
+    if (isObsolete)
+    {
+      buffer.append(" OBSOLETE");
+    }
+
+    if (superiorTypeOID != null)
+    {
+      buffer.append(" SUP ");
+      buffer.append(superiorTypeOID);
+    }
+
+    if (equalityMatchingRuleOID != null)
+    {
+      buffer.append(" EQUALITY ");
+      buffer.append(equalityMatchingRuleOID);
+    }
+
+    if (orderingMatchingRuleOID != null)
+    {
+      buffer.append(" ORDERING ");
+      buffer.append(orderingMatchingRuleOID);
+    }
+
+    if (substringMatchingRuleOID != null)
+    {
+      buffer.append(" SUBSTR ");
+      buffer.append(substringMatchingRuleOID);
+    }
+
+    if (syntaxOID != null)
+    {
+      buffer.append(" SYNTAX ");
+      buffer.append(syntaxOID);
+    }
+
+    if (isSingleValue())
+    {
+      buffer.append(" SINGLE-VALUE");
+    }
+
+    if (isCollective())
+    {
+      buffer.append(" COLLECTIVE");
+    }
+
+    if (isNoUserModification())
+    {
+      buffer.append(" NO-USER-MODIFICATION");
+    }
+
+    if (attributeUsage != null)
+    {
+      buffer.append(" USAGE ");
+      buffer.append(attributeUsage.toString());
+    }
+
+    if (approximateMatchingRuleOID != null)
+    {
+      buffer.append(" ");
+      buffer.append(SCHEMA_PROPERTY_APPROX_RULE);
+      buffer.append(" '");
+      buffer.append(approximateMatchingRuleOID);
+      buffer.append("'");
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    if (superiorTypeOID != null)
+    {
+      try
+      {
+        superiorType = schema.getAttributeType(superiorTypeOID);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE
+            .get(getNameOrOID(), superiorTypeOID);
+        throw new SchemaException(message);
+      }
+
+      // If there is a superior type, then it must have the same usage
+      // as the subordinate type. Also, if the superior type is
+      // collective, then so must the subordinate type be collective.
+      if (superiorType.getUsage() != getUsage())
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE
+            .get(getNameOrOID(), getUsage().toString(), superiorType
+                .getNameOrOID());
+        throw new SchemaException(message);
+      }
+
+      if (superiorType.isCollective() != isCollective())
+      {
+        LocalizableMessage message;
+        if (isCollective())
+        {
+          message = WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE
+              .get(getNameOrOID(), superiorType.getNameOrOID());
+        }
+        else
+        {
+          message = WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE
+              .get(getNameOrOID(), superiorType.getNameOrOID());
+        }
+        throw new SchemaException(message);
+      }
+    }
+
+    if (syntaxOID != null)
+    {
+      if (!schema.hasSyntax(syntaxOID))
+      {
+        // Try substituting a syntax from the core schema. This will
+        // never fail since the core schema is non-strict and will
+        // substitute the syntax if required.
+        syntax = Schema.getCoreSchema().getSyntax(syntaxOID);
+        final LocalizableMessage message = WARN_ATTR_TYPE_NOT_DEFINED.get(
+            getNameOrOID(), syntaxOID, syntax.toString());
+        warnings.add(message);
+      }
+      else
+      {
+        syntax = schema.getSyntax(syntaxOID);
+      }
+    }
+    else if (getSuperiorType() != null && getSuperiorType().getSyntax() != null)
+    {
+      // Try to inherit the syntax from the superior type if possible
+      syntax = getSuperiorType().getSyntax();
+    }
+
+    if (equalityMatchingRuleOID != null)
+    {
+      // Use explicitly defined matching rule first.
+      try
+      {
+        equalityMatchingRule = schema.getMatchingRule(equalityMatchingRuleOID);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR
+            .get(getNameOrOID(), equalityMatchingRuleOID);
+        throw new SchemaException(message);
+      }
+    }
+    else if (getSuperiorType() != null
+        && getSuperiorType().getEqualityMatchingRule() != null)
+    {
+      // Inherit matching rule from superior type if possible
+      equalityMatchingRule = getSuperiorType().getEqualityMatchingRule();
+    }
+    else if (getSyntax() != null
+        && getSyntax().getEqualityMatchingRule() != null)
+    {
+      // Use default for syntax
+      equalityMatchingRule = getSyntax().getEqualityMatchingRule();
+    }
+
+    if (orderingMatchingRuleOID != null)
+    {
+      // Use explicitly defined matching rule first.
+      try
+      {
+        orderingMatchingRule = schema.getMatchingRule(orderingMatchingRuleOID);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR
+            .get(getNameOrOID(), orderingMatchingRuleOID);
+        throw new SchemaException(message);
+      }
+    }
+    else if (getSuperiorType() != null
+        && getSuperiorType().getOrderingMatchingRule() != null)
+    {
+      // Inherit matching rule from superior type if possible
+      orderingMatchingRule = getSuperiorType().getOrderingMatchingRule();
+    }
+    else if (getSyntax() != null
+        && getSyntax().getOrderingMatchingRule() != null)
+    {
+      // Use default for syntax
+      orderingMatchingRule = getSyntax().getOrderingMatchingRule();
+    }
+
+    if (substringMatchingRuleOID != null)
+    {
+      // Use explicitly defined matching rule first.
+      try
+      {
+        substringMatchingRule = schema
+            .getMatchingRule(substringMatchingRuleOID);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR
+            .get(getNameOrOID(), substringMatchingRuleOID);
+        throw new SchemaException(message);
+      }
+    }
+    else if (getSuperiorType() != null
+        && getSuperiorType().getSubstringMatchingRule() != null)
+    {
+      // Inherit matching rule from superior type if possible
+      substringMatchingRule = getSuperiorType().getSubstringMatchingRule();
+    }
+    else if (getSyntax() != null
+        && getSyntax().getSubstringMatchingRule() != null)
+    {
+      // Use default for syntax
+      substringMatchingRule = getSyntax().getSubstringMatchingRule();
+    }
+
+    if (approximateMatchingRuleOID != null)
+    {
+      // Use explicitly defined matching rule first.
+      try
+      {
+        approximateMatchingRule = schema
+            .getMatchingRule(approximateMatchingRuleOID);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR
+            .get(getNameOrOID(), approximateMatchingRuleOID);
+        throw new SchemaException(message);
+      }
+    }
+    else if (getSuperiorType() != null
+        && getSuperiorType().getApproximateMatchingRule() != null)
+    {
+      // Inherit matching rule from superior type if possible
+      approximateMatchingRule = getSuperiorType().getApproximateMatchingRule();
+    }
+    else if (getSyntax() != null
+        && getSyntax().getApproximateMatchingRule() != null)
+    {
+      // Use default for syntax
+      approximateMatchingRule = getSyntax().getApproximateMatchingRule();
+    }
+
+    // If the attribute type is COLLECTIVE, then it must have a usage of
+    // userApplications.
+    if (isCollective() && getUsage() != AttributeUsage.USER_APPLICATIONS)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL
+          .get(getNameOrOID());
+      warnings.add(message);
+    }
+
+    // If the attribute type is NO-USER-MODIFICATION, then it must not
+    // have a usage of userApplications.
+    if (isNoUserModification()
+        && getUsage() == AttributeUsage.USER_APPLICATIONS)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL
+          .get(getNameOrOID());
+      warnings.add(message);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeTypeSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeTypeSyntaxImpl.java
new file mode 100644
index 0000000..4afeb85
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeTypeSyntaxImpl.java
@@ -0,0 +1,280 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_ILLEGAL_TOKEN;
+import static com.sun.opends.sdk.messages.Messages.
+  WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_ATTRIBUTE_TYPE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class defines the attribute type description syntax, which is used to
+ * hold attribute type definitions in the server schema. The format of this
+ * syntax is defined in RFC 2252.
+ */
+final class AttributeTypeSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_ATTRIBUTE_TYPE_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the definition was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE
+            .get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("AttributeTypeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("AttributeTypeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the definition. But before we start, set default
+      // values for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("sup"))
+        {
+          // This specifies the name or OID of the superior attribute
+          // type from which this attribute type should inherit its
+          // properties.
+          SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("equality"))
+        {
+          // This specifies the name or OID of the equality matching
+          // rule to use for this attribute type.
+          SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("ordering"))
+        {
+          // This specifies the name or OID of the ordering matching
+          // rule to use for this attribute type.
+          SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("substr"))
+        {
+          // This specifies the name or OID of the substring matching
+          // rule to use for this attribute type.
+          SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("syntax"))
+        {
+          // This specifies the numeric OID of the syntax for this
+          // matching rule. It may optionally be immediately followed by
+          // an open curly brace, an integer definition, and a close
+          // curly brace to suggest the minimum number of characters
+          // that should be allowed in values of that type. This
+          // implementation will ignore any such length because it does
+          // not impose any practical limit on the length of attribute
+          // values.
+          SchemaUtils.readOIDLen(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("single-definition"))
+        {
+          // This indicates that attributes of this type are allowed to
+          // have at most one definition. We do not need any more
+          // parsing for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("single-value"))
+        {
+          // This indicates that attributes of this type are allowed to
+          // have at most one value. We do not need any more parsing for
+          // this token.
+        }
+        else if (tokenName.equalsIgnoreCase("collective"))
+        {
+          // This indicates that attributes of this type are collective
+          // (i.e., have their values generated dynamically in some
+          // way). We do not need any more parsing for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("no-user-modification"))
+        {
+          // This indicates that the values of attributes of this type
+          // are not to be modified by end users. We do not need any
+          // more parsing for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("usage"))
+        {
+          // This specifies the usage string for this attribute type. It
+          // should be followed by one of the strings
+          // "userApplications", "directoryOperation",
+          // "distributedOperation", or "dSAOperation".
+          int length = 0;
+
+          reader.skipWhitespaces();
+          reader.mark();
+
+          while (reader.read() != ' ')
+          {
+            length++;
+          }
+
+          reader.reset();
+          final String usageStr = reader.read(length);
+          if (!usageStr.equalsIgnoreCase("userapplications")
+              && !usageStr.equalsIgnoreCase("directoryoperation")
+              && !usageStr.equalsIgnoreCase("distributedoperation")
+              && !usageStr.equalsIgnoreCase("dsaoperation"))
+          {
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE
+                .get(String.valueOf(oid), usageStr);
+            final DecodeException e = DecodeException.error(message);
+            StaticUtils.DEBUG_LOG.throwing("AttributeTypeSyntax",
+                "valueIsAcceptable", e);
+            throw e;
+          }
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          SchemaUtils.readExtensions(reader);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("AttributeTypeSyntax",
+              "valueIsAcceptable", e);
+          throw e;
+        }
+      }
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeUsage.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeUsage.java
new file mode 100644
index 0000000..65d2481
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AttributeUsage.java
@@ -0,0 +1,110 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+/**
+ * This enumeration defines the set of possible attribute usage values that may
+ * apply to an attribute type, as defined in RFC 2252.
+ */
+public enum AttributeUsage
+{
+  /**
+   * The attribute usage intended for user-defined attribute types.
+   */
+  USER_APPLICATIONS("userApplications", false),
+
+  /**
+   * The attribute usage intended for standard operational attributes.
+   */
+  DIRECTORY_OPERATION("directoryOperation", true),
+
+  /**
+   * The attribute usage intended for non-standard operational attributes shared
+   * among multiple DSAs.
+   */
+  DISTRIBUTED_OPERATION("distributedOperation", true),
+
+  /**
+   * The attribute usage intended for non-standard operational attributes used
+   * by a single DSA.
+   */
+  DSA_OPERATION("dSAOperation", true);
+
+  // The string representation of this attribute usage.
+  private final String usageString;
+
+  // Flag indicating whether or not the usage should be categorized as
+  // operational.
+  private final boolean isOperational;
+
+
+
+  /**
+   * Creates a new attribute usage with the provided string representation.
+   *
+   * @param usageString
+   *          The string representation of this attribute usage.
+   * @param isOperational
+   *          <code>true</code> if attributes having this attribute usage are
+   *          operational, or <code>false</code> otherwise.
+   */
+  private AttributeUsage(final String usageString, final boolean isOperational)
+  {
+    this.usageString = usageString;
+    this.isOperational = isOperational;
+  }
+
+
+
+  /**
+   * Determine whether or not attributes having this attribute usage are
+   * operational.
+   *
+   * @return Returns <code>true</code> if attributes having this attribute usage
+   *         are operational, or <code>false</code> otherwise.
+   */
+  public boolean isOperational()
+  {
+    return isOperational;
+  }
+
+
+
+  /**
+   * Retrieves a string representation of this attribute usage.
+   *
+   * @return A string representation of this attribute usage.
+   */
+  @Override
+  public String toString()
+  {
+    return usageString;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordExactEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordExactEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..ab5a823
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordExactEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * This class implements the authPasswordMatch matching rule defined in RFC
+ * 3112.
+ */
+final class AuthPasswordExactEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final StringBuilder[] authPWComponents = AuthPasswordSyntaxImpl
+        .decodeAuthPassword(value.toString());
+
+    final StringBuilder normalizedValue = new StringBuilder(2
+        + authPWComponents[0].length() + authPWComponents[1].length()
+        + authPWComponents[2].length());
+    normalizedValue.append(authPWComponents[0]);
+    normalizedValue.append('$');
+    normalizedValue.append(authPWComponents[1]);
+    normalizedValue.append('$');
+    normalizedValue.append(authPWComponents[2]);
+
+    return ByteString.valueOf(normalizedValue.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordSyntaxImpl.java
new file mode 100644
index 0000000..f58743a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/AuthPasswordSyntaxImpl.java
@@ -0,0 +1,340 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.EMR_AUTH_PASSWORD_EXACT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_AUTH_PASSWORD_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the auth password attribute syntax, which is defined in
+ * RFC 3112 and is used to hold authentication information. Only equality
+ * matching will be allowed by default.
+ */
+final class AuthPasswordSyntaxImpl extends AbstractSyntaxImpl
+{
+  /**
+   * Decodes the provided authentication password value into its component
+   * parts.
+   *
+   * @param authPasswordValue
+   *          The authentication password value to be decoded.
+   * @return A three-element array, containing the scheme, authInfo, and
+   *         authValue components of the given string, in that order.
+   * @throws DecodeException
+   *           If a problem is encountered while attempting to decode the value.
+   */
+  static StringBuilder[] decodeAuthPassword(final String authPasswordValue)
+      throws DecodeException
+  {
+    // Create placeholders for the values to return.
+    final StringBuilder scheme = new StringBuilder();
+    final StringBuilder authInfo = new StringBuilder();
+    final StringBuilder authValue = new StringBuilder();
+
+    // First, ignore any leading whitespace.
+    final int length = authPasswordValue.length();
+    int pos = 0;
+    while (pos < length && authPasswordValue.charAt(pos) == ' ')
+    {
+      pos++;
+    }
+
+    // The next set of characters will be the scheme, which must consist
+    // only of digits, uppercase alphabetic characters, dash, period,
+    // slash, and underscore characters. It must be immediately followed
+    // by one or more spaces or a dollar sign.
+    readScheme: while (pos < length)
+    {
+      final char c = authPasswordValue.charAt(pos);
+
+      switch (c)
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case 'A':
+      case 'B':
+      case 'C':
+      case 'D':
+      case 'E':
+      case 'F':
+      case 'G':
+      case 'H':
+      case 'I':
+      case 'J':
+      case 'K':
+      case 'L':
+      case 'M':
+      case 'N':
+      case 'O':
+      case 'P':
+      case 'Q':
+      case 'R':
+      case 'S':
+      case 'T':
+      case 'U':
+      case 'V':
+      case 'W':
+      case 'X':
+      case 'Y':
+      case 'Z':
+      case '-':
+      case '.':
+      case '/':
+      case '_':
+        scheme.append(c);
+        pos++;
+        break;
+      case ' ':
+      case '$':
+        break readScheme;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR
+            .get(pos);
+        throw DecodeException.error(message);
+      }
+    }
+
+    // The scheme must consist of at least one character.
+    if (scheme.length() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME.get();
+      throw DecodeException.error(message);
+    }
+
+    // Ignore any spaces before the dollar sign separator. Then read the
+    // dollar sign and ignore any trailing spaces.
+    while (pos < length && authPasswordValue.charAt(pos) == ' ')
+    {
+      pos++;
+    }
+
+    if (pos < length && authPasswordValue.charAt(pos) == '$')
+    {
+      pos++;
+    }
+    else
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    while (pos < length && authPasswordValue.charAt(pos) == ' ')
+    {
+      pos++;
+    }
+
+    // The next component must be the authInfo element, containing only
+    // printable characters other than the dollar sign and space
+    // character.
+    readAuthInfo: while (pos < length)
+    {
+      final char c = authPasswordValue.charAt(pos);
+      if (c == ' ' || c == '$')
+      {
+        break readAuthInfo;
+      }
+      else if (PrintableStringSyntaxImpl.isPrintableCharacter(c))
+      {
+        authInfo.append(c);
+        pos++;
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR
+            .get(pos);
+        throw DecodeException.error(message);
+      }
+    }
+
+    // The authInfo element must consist of at least one character.
+    if (scheme.length() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    // Ignore any spaces before the dollar sign separator. Then read the
+    // dollar sign and ignore any trailing spaces.
+    while (pos < length && authPasswordValue.charAt(pos) == ' ')
+    {
+      pos++;
+    }
+
+    if (pos < length && authPasswordValue.charAt(pos) == '$')
+    {
+      pos++;
+    }
+    else
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    while (pos < length && authPasswordValue.charAt(pos) == ' ')
+    {
+      pos++;
+    }
+
+    // The final component must be the authValue element, containing
+    // only printable characters other than the dollar sign and space
+    // character.
+    while (pos < length)
+    {
+      final char c = authPasswordValue.charAt(pos);
+      if (c == ' ' || c == '$')
+      {
+        break;
+      }
+      else if (PrintableStringSyntaxImpl.isPrintableCharacter(c))
+      {
+        authValue.append(c);
+        pos++;
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR
+            .get(pos);
+        throw DecodeException.error(message);
+      }
+    }
+
+    // The authValue element must consist of at least one character.
+    if (scheme.length() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    // The only characters remaining must be whitespace.
+    while (pos < length)
+    {
+      final char c = authPasswordValue.charAt(pos);
+      if (c == ' ')
+      {
+        pos++;
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR
+            .get(pos);
+        throw DecodeException.error(message);
+      }
+    }
+
+    // If we've gotten here, then everything must be OK.
+    return new StringBuilder[] { scheme, authInfo, authValue };
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is encoded using the auth password
+   * syntax.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return <CODE>true</CODE> if the value appears to be encoded using the auth
+   *         password syntax, or <CODE>false</CODE> if not.
+   */
+  static boolean isEncoded(final ByteSequence value)
+  {
+    // FIXME -- Make this more efficient, and don't use exceptions for
+    // flow control.
+
+    try
+    {
+      decodeAuthPassword(value.toString());
+      return true;
+    }
+    catch (final Exception e)
+    {
+      return false;
+    }
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_AUTH_PASSWORD_EXACT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_AUTH_PASSWORD_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    try
+    {
+      decodeAuthPassword(value.toString());
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BinarySyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BinarySyntaxImpl.java
new file mode 100644
index 0000000..8eeede5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BinarySyntaxImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_BINARY_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the binary attribute syntax, which is essentially a byte
+ * array using very strict matching. Equality, ordering, and substring matching
+ * will be allowed by default.
+ */
+final class BinarySyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_BINARY_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the binary syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..d54d865
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class defines the bitStringMatch matching rule defined in X.520 and
+ * referenced in RFC 2252.
+ */
+final class BitStringEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final String valueString = value.toString().toUpperCase();
+
+    final int length = valueString.length();
+    if (length < 3)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT
+          .get(value.toString());
+      throw DecodeException.error(message);
+    }
+
+    if (valueString.charAt(0) != '\'' || valueString.charAt(length - 2) != '\''
+        || valueString.charAt(length - 1) != 'B')
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED
+          .get(value.toString());
+      throw DecodeException.error(message);
+    }
+
+    for (int i = 1; i < length - 2; i++)
+    {
+      switch (valueString.charAt(i))
+      {
+      case '0':
+      case '1':
+        // These characters are fine.
+        break;
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT
+            .get(value.toString(), String.valueOf(valueString.charAt(i)));
+        throw DecodeException.error(message);
+      }
+    }
+
+    return ByteString.valueOf(valueString);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringSyntaxImpl.java
new file mode 100644
index 0000000..5ebdfe8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BitStringSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT;
+import static org.opends.sdk.schema.SchemaConstants.EMR_BIT_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_BIT_STRING_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the bit string attribute syntax, which is comprised of a
+ * string of binary digits surrounded by single quotes and followed by a capital
+ * letter "B" (e.g., '101001'B).
+ */
+final class BitStringSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_BIT_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_BIT_STRING_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String valueString = value.toString().toUpperCase();
+
+    final int length = valueString.length();
+    if (length < 3)
+    {
+      invalidReason.append(WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT.get(value
+          .toString()));
+      return false;
+    }
+
+    if (valueString.charAt(0) != '\'' || valueString.charAt(length - 2) != '\''
+        || valueString.charAt(length - 1) != 'B')
+    {
+      invalidReason.append(WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED.get(value
+          .toString()));
+      return false;
+    }
+
+    for (int i = 1; i < length - 2; i++)
+    {
+      switch (valueString.charAt(i))
+      {
+      case '0':
+      case '1':
+        // These characters are fine.
+        break;
+      default:
+        invalidReason.append(WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT.get(value
+            .toString(), String.valueOf(valueString.charAt(i))));
+        return false;
+      }
+    }
+
+    // If we've gotten here, then everything is fine.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..a2b1e7e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleImpl.java
@@ -0,0 +1,63 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * This class defines the booleanMatch matching rule defined in X.520 and
+ * referenced in RFC 4519.
+ */
+final class BooleanEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final String valueString = value.toString().toUpperCase();
+    if (valueString.equals("TRUE") || valueString.equals("YES")
+        || valueString.equals("ON") || valueString.equals("1"))
+    {
+      return SchemaConstants.TRUE_VALUE;
+    }
+    else if (valueString.equals("FALSE") || valueString.equals("NO")
+        || valueString.equals("OFF") || valueString.equals("0"))
+    {
+      return SchemaConstants.FALSE_VALUE;
+    }
+
+    throw DecodeException.error(WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(value
+        .toString()));
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanSyntaxImpl.java
new file mode 100644
index 0000000..a882e3c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/BooleanSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN;
+import static org.opends.sdk.schema.SchemaConstants.EMR_BOOLEAN_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_BOOLEAN_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the Boolean attribute syntax, which only allows values of
+ * "TRUE" or "FALSE" (although this implementation is more flexible and will
+ * also allow "YES", "ON", or "1" instead of "TRUE", or "NO", "OFF", or "0"
+ * instead of "FALSE"). Only equality matching is allowed by default for this
+ * syntax.
+ */
+final class BooleanSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_BOOLEAN_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_BOOLEAN_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String valueString = value.toString().toUpperCase();
+
+    final boolean returnValue = valueString.equals("TRUE")
+        || valueString.equals("YES") || valueString.equals("ON")
+        || valueString.equals("1") || valueString.equals("FALSE")
+        || valueString.equals("NO") || valueString.equals("OFF")
+        || valueString.equals("0");
+
+    if (!returnValue)
+    {
+      invalidReason.append(WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(value
+          .toString()));
+    }
+
+    return returnValue;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..4c3ea6e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines the caseExactMatch matching rule defined in X.520 and
+ * referenced in RFC 4519.
+ */
+final class CaseExactEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..dc62800
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class implements the caseExactIA5Match matching rule defined in RFC
+ * 2252.
+ */
+final class CaseExactIA5EqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space and watch out
+    // for non-ASCII characters.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      final char c = buffer.charAt(pos);
+      if (c == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+      else if ((c & 0x7F) != c)
+      {
+        // This is not a valid character for an IA5 string. If strict
+        // syntax enforcement is enabled, then we'll throw an exception.
+        // Otherwise, we'll get rid of the character.
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER
+            .get(value.toString(), String.valueOf(c));
+        throw DecodeException.error(message);
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..ae72948
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class implements the caseExactIA5SubstringsMatch matching rule. This
+ * matching rule actually isn't defined in any official specification, but some
+ * directory vendors do provide an implementation using an OID from their own
+ * private namespace.
+ */
+final class CaseExactIA5SubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    return normalize(TRIM, value);
+  }
+
+
+
+  @Override
+  ByteString normalizeSubString(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    return normalize(false, value);
+  }
+
+
+
+  private ByteString normalize(final boolean trim, final ByteSequence value)
+      throws DecodeException
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, trim, NO_CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space and watch out
+    // for non-ASCII characters.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      final char c = buffer.charAt(pos);
+      if (c == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+      else if ((c & 0x7F) != c)
+      {
+        // This is not a valid character for an IA5 string. If strict
+        // syntax enforcement is enabled, then we'll throw an exception.
+        // Otherwise, we'll get rid of the character.
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER
+            .get(value.toString(), String.valueOf(c));
+        throw DecodeException.error(message);
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..e52d735
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines the caseExactOrderingMatch matching rule defined in X.520
+ * and referenced in RFC 4519.
+ */
+final class CaseExactOrderingMatchingRuleImpl extends
+    AbstractOrderingMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..2089814
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleImpl.java
@@ -0,0 +1,100 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * This class defines the caseExactSubstringsMatch matching rule defined in
+ * X.520 and referenced in RFC 2252.
+ */
+final class CaseExactSubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return normalize(TRIM, value);
+  }
+
+
+
+  @Override
+  ByteString normalizeSubString(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    return normalize(false, value);
+  }
+
+
+
+  private ByteString normalize(final boolean trim, final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, trim, NO_CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..feb9af4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines the caseIgnoreMatch matching rule defined in X.520 and
+ * referenced in RFC 2252.
+ */
+final class CaseIgnoreEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..b001604
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class implements the caseIgnoreIA5Match matching rule defined in RFC
+ * 2252.
+ */
+final class CaseIgnoreIA5EqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space and watch out
+    // for non-ASCII characters.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      final char c = buffer.charAt(pos);
+      if (c == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+      else if ((c & 0x7F) != c)
+      {
+        // This is not a valid character for an IA5 string. If strict
+        // syntax enforcement is enabled, then we'll throw an exception.
+        // Otherwise, we'll get rid of the character.
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER
+            .get(value.toString(), String.valueOf(c));
+        throw DecodeException.error(message);
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..7120311
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java
@@ -0,0 +1,114 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class implements the caseIgnoreIA5SubstringsMatch matching rule defined
+ * in RFC 2252.
+ */
+final class CaseIgnoreIA5SubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    return normalize(TRIM, value);
+  }
+
+
+
+  @Override
+  ByteString normalizeSubString(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    return normalize(false, value);
+  }
+
+
+
+  private ByteString normalize(final boolean trim, final ByteSequence value)
+      throws DecodeException
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, trim, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space and watch out
+    // for non-ASCII characters.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      final char c = buffer.charAt(pos);
+      if (c == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+      else if ((c & 0x7F) != c)
+      {
+        // This is not a valid character for an IA5 string. If strict
+        // syntax enforcement is enabled, then we'll throw an exception.
+        // Otherwise, we'll get rid of the character.
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER
+            .get(value.toString(), String.valueOf(c));
+        throw DecodeException.error(message);
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..c079eb4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListEqualityMatchingRuleImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class implements the caseIgnoreListMatch matching rule defined in X.520
+ * and referenced in RFC 2252.
+ */
+final class CaseIgnoreListEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space. Any spaces
+    // around a dollar sign will also be removed.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        final char c = buffer.charAt(pos - 1);
+        if (c == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+        else if (c == '$')
+        {
+          if (pos <= 1 || buffer.charAt(pos - 2) != '\\')
+          {
+            buffer.delete(pos, pos + 1);
+          }
+        }
+        else if (buffer.charAt(pos + 1) == '$')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListSubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListSubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..12cd2b4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreListSubstringMatchingRuleImpl.java
@@ -0,0 +1,141 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+import com.sun.opends.sdk.util.StringPrepProfile;
+
+
+
+/**
+ * This class implements the caseIgnoreListSubstringsMatch matching rule defined
+ * in X.520 and referenced in RFC 2252.
+ */
+final class CaseIgnoreListSubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, StringPrepProfile.TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space. Any spaces
+    // around a dollar sign will also be removed.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        final char c = buffer.charAt(pos - 1);
+        if (c == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+        else if (c == '$')
+        {
+          if (pos <= 1 || buffer.charAt(pos - 2) != '\\')
+          {
+            buffer.delete(pos, pos + 1);
+          }
+        }
+        else if (buffer.charAt(pos + 1) == '$')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+
+
+
+  @Override
+  ByteString normalizeSubString(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    // In this case, the process for normalizing a substring is the same
+    // as normalizing a full value with the exception that it may
+    // include an opening or trailing space.
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, false, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return value.toByteString();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..fe59961
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines the caseIgnoreOrderingMatch matching rule defined in X.520
+ * and referenced in RFC 2252.
+ */
+final class CaseIgnoreOrderingMatchingRuleImpl extends
+    AbstractOrderingMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..f9ac602
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+import com.sun.opends.sdk.util.StringPrepProfile;
+
+
+
+/**
+ * This class defines the caseIgnoreSubstringsMatch matching rule defined in
+ * X.520 and referenced in RFC 2252.
+ */
+final class CaseIgnoreSubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return normalize(TRIM, value);
+  }
+
+
+
+  @Override
+  ByteString normalizeSubString(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    return normalize(false, value);
+  }
+
+
+
+  private ByteString normalize(final boolean trim, final ByteSequence value)
+  {
+
+    final StringBuilder buffer = new StringBuilder();
+    StringPrepProfile.prepareUnicode(buffer, value, trim, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return value.toByteString();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateListSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateListSyntaxImpl.java
new file mode 100644
index 0000000..bbcde01
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateListSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_CERTLIST_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the certificate list attribute syntax. This should be
+ * restricted to holding only X.509 certificate lists, but we will accept any
+ * set of bytes. It will be treated much like the octet string attribute syntax.
+ */
+final class CertificateListSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_CERTLIST_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  @Override
+  public boolean isBEREncodingRequired()
+  {
+    return true;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the certificate list syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificatePairSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificatePairSyntaxImpl.java
new file mode 100644
index 0000000..3385048
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificatePairSyntaxImpl.java
@@ -0,0 +1,106 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_CERTPAIR_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the certificate pair attribute syntax. This should be
+ * restricted to holding only X.509 certificate pairs, but we will accept any
+ * set of bytes. It will be treated much like the octet string attribute syntax.
+ */
+final class CertificatePairSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_CERTPAIR_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  @Override
+  public boolean isBEREncodingRequired()
+  {
+    return true;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the certificate pair syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateSyntaxImpl.java
new file mode 100644
index 0000000..ed693fd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CertificateSyntaxImpl.java
@@ -0,0 +1,106 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_CERTIFICATE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the certificate attribute syntax. This should be
+ * restricted to holding only X.509 certificates, but we will accept any set of
+ * bytes. It will be treated much like the octet string attribute syntax.
+ */
+final class CertificateSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_CERTIFICATE_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  @Override
+  public boolean isBEREncodingRequired()
+  {
+    return true;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the certificate syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ConflictingSchemaElementException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ConflictingSchemaElementException.java
new file mode 100644
index 0000000..bd749e3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ConflictingSchemaElementException.java
@@ -0,0 +1,57 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+
+
+/**
+ * Thrown when addition of a schema element to a schema builder fails because
+ * the OID of the schema element conflicts with an existing schema element and
+ * the caller explicitly requested not to override existing schema elements.
+ */
+@SuppressWarnings("serial")
+public class ConflictingSchemaElementException extends
+    LocalizedIllegalArgumentException
+{
+  /**
+   * Creates a new conflicting schema element exception with the provided
+   * message.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   */
+  public ConflictingSchemaElementException(final LocalizableMessage message)
+  {
+    super(message);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchema.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchema.java
new file mode 100644
index 0000000..83f07ec
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchema.java
@@ -0,0 +1,2675 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+/**
+ * The OpenDS SDK core schema contains standard LDAP RFC schema elements. These
+ * include:
+ * <ul>
+ * <li><a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
+ * Directory Access Protocol (LDAP): Directory Information Models </a>
+ * <li><a href="http://tools.ietf.org/html/rfc4517">RFC 4517 - Lightweight
+ * Directory Access Protocol (LDAP): Syntaxes and Matching Rules </a>
+ * <li><a href="http://tools.ietf.org/html/rfc4519">RFC 4519 - Lightweight
+ * Directory Access Protocol (LDAP): Schema for User Applications </a>
+ * <li><a href="http://tools.ietf.org/html/rfc4530">RFC 4530 - Lightweight
+ * Directory Access Protocol (LDAP): entryUUID Operational Attribute </a>
+ * <li><a href="http://tools.ietf.org/html/rfc3045">RFC 3045 - Storing Vendor
+ * Information in the LDAP Root DSE </a>
+ * <li><a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
+ * Authentication Password Schema </a>
+ * </ul>
+ * <p>
+ * The core schema is non-strict: attempts to retrieve non-existent Attribute
+ * Types will return a temporary Attribute Type having the Octet String syntax.
+ */
+public final class CoreSchema
+{
+  // Core Syntaxes
+  private static final Syntax ATTRIBUTE_TYPE_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.3");
+  private static final Syntax AUTHENTICATION_PASSWORD_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.4203.1.1.2");
+  private static final Syntax BINARY_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.5");
+  private static final Syntax BIT_STRING_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.6");
+  private static final Syntax BOOLEAN_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.7");
+  private static final Syntax CERTIFICATE_LIST_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.9");
+  private static final Syntax CERTIFICATE_PAIR_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.10");
+  private static final Syntax CERTIFICATE_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.8");
+  private static final Syntax COUNTRY_STRING_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.11");
+  private static final Syntax DELIVERY_METHOD_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.14");
+  private static final Syntax DIRECTORY_STRING_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.15");
+  private static final Syntax DIT_CONTENT_RULE_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.16");
+  private static final Syntax DIT_STRUCTURE_RULE_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.17");
+  private static final Syntax DN_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.12");
+  private static final Syntax ENHANCED_GUIDE_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.21");
+  private static final Syntax FACSIMILE_TELEPHONE_NUMBER_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.22");
+  private static final Syntax FAX_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.23");
+  private static final Syntax GENERALIZED_TIME_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.24");
+  private static final Syntax GUIDE_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.25");
+  private static final Syntax IA5_STRING_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.26");
+  private static final Syntax INTEGER_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.27");
+  private static final Syntax JPEG_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.28");
+  private static final Syntax LDAP_SYNTAX_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.54");
+  private static final Syntax MATCHING_RULE_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.30");
+  private static final Syntax MATCHING_RULE_USE_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.31");
+  private static final Syntax NAME_AND_OPTIONAL_UID_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.34");
+  private static final Syntax NAME_FORM_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.35");
+  private static final Syntax NUMERIC_STRING_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.36");
+  private static final Syntax OBJECT_CLASS_DESCRIPTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.37");
+  private static final Syntax OCTET_STRING_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.40");
+  private static final Syntax OID_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.38");
+  private static final Syntax OTHER_MAILBOX_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.39");
+  private static final Syntax POSTAL_ADDRESS_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.41");
+  private static final Syntax PRESENTATION_ADDRESS_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.43");
+  private static final Syntax PRINTABLE_STRING_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.44");
+  private static final Syntax PROTOCOL_INFORMATION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.42");
+  private static final Syntax SUBSTRING_ASSERTION_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.58");
+  private static final Syntax SUPPORTED_ALGORITHM_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.49");
+  private static final Syntax TELEPHONE_NUMBER_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.50");
+  private static final Syntax TELETEX_TERMINAL_IDENTIFIER_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.51");
+  private static final Syntax TELEX_NUMBER_SYNTAX = CoreSchemaImpl
+      .getInstance().getSyntax("1.3.6.1.4.1.1466.115.121.1.52");
+  private static final Syntax UTC_TIME_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.4.1.1466.115.121.1.53");
+  private static final Syntax UUID_SYNTAX = CoreSchemaImpl.getInstance()
+      .getSyntax("1.3.6.1.1.16.1");
+
+  // Core Matching Rules
+  private static final MatchingRule AUTH_PASSWORD_EXACT_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("1.3.6.1.4.1.4203.1.2.2");
+  private static final MatchingRule BIT_STRING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.16");
+  private static final MatchingRule BOOLEAN_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.13");
+  private static final MatchingRule CASE_EXACT_IA5_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("1.3.6.1.4.1.1466.109.114.1");
+  private static final MatchingRule CASE_EXACT_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.5");
+  private static final MatchingRule CASE_EXACT_ORDERING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.6");
+  private static final MatchingRule CASE_EXACT_SUBSTRINGS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.7");
+  private static final MatchingRule CASE_IGNORE_IA5_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("1.3.6.1.4.1.1466.109.114.2");
+  private static final MatchingRule CASE_IGNORE_IA5_SUBSTRINGS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("1.3.6.1.4.1.1466.109.114.3");
+  private static final MatchingRule CASE_IGNORE_LIST_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.11");
+  private static final MatchingRule CASE_IGNORE_LIST_SUBSTRINGS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.12");
+  private static final MatchingRule CASE_IGNORE_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.2");
+  private static final MatchingRule CASE_IGNORE_ORDERING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.3");
+  private static final MatchingRule CASE_IGNORE_SUBSTRINGS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.4");
+  private static final MatchingRule DIRECTORY_STRING_FIRST_COMPONENT_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.31");
+  private static final MatchingRule DISTINGUISHED_NAME_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.1");
+  private static final MatchingRule GENERALIZED_TIME_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.27");
+  private static final MatchingRule GENERALIZED_TIME_ORDERING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.28");
+  private static final MatchingRule INTEGER_FIRST_COMPONENT_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.29");
+  private static final MatchingRule INTEGER_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.14");
+  private static final MatchingRule INTEGER_ORDERING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.15");
+  private static final MatchingRule KEYWORD_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.33");
+  private static final MatchingRule NUMERIC_STRING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.8");
+  private static final MatchingRule NUMERIC_STRING_ORDERING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.9");
+  private static final MatchingRule NUMERIC_STRING_SUBSTRINGS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.10");
+  private static final MatchingRule OBJECT_IDENTIFIER_FIRST_COMPONENT_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.30");
+  private static final MatchingRule OBJECT_IDENTIFIER_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.0");
+  private static final MatchingRule OCTET_STRING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.17");
+  private static final MatchingRule OCTET_STRING_ORDERING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.18");
+  private static final MatchingRule OCTET_STRING_SUBSTRINGS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.19");
+  private static final MatchingRule PRESENTATION_ADDRESS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.22");
+  private static final MatchingRule PROTOCOL_INFORMATION_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.24");
+  private static final MatchingRule TELEPHONE_NUMBER_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.20");
+  private static final MatchingRule TELEPHONE_NUMBER_SUBSTRINGS_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.21");
+  private static final MatchingRule UNIQUE_MEMBER_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.23");
+  private static final MatchingRule UUID_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("1.3.6.1.1.16.2");
+  private static final MatchingRule UUID_ORDERING_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("1.3.6.1.1.16.3");
+  private static final MatchingRule WORD_MATCHING_RULE = CoreSchemaImpl
+      .getInstance().getMatchingRule("2.5.13.32");
+
+  // Core Attribute Types
+  private static final AttributeType ALIASED_OBJECT_NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.1");
+  private static final AttributeType ALT_SERVER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.1466.101.120.6");
+  private static final AttributeType ATTRIBUTE_TYPES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.5");
+  private static final AttributeType AUTH_PASSWORD_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.4203.1.3.4");
+  private static final AttributeType BUSINESS_CATEGORY_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.15");
+  private static final AttributeType CN_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.3");
+  private static final AttributeType CREATE_TIMESTAMP_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.18.1");
+  private static final AttributeType CREATORS_NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.18.3");
+  private static final AttributeType C_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.6");
+  private static final AttributeType DC_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("0.9.2342.19200300.100.1.25");
+  private static final AttributeType DESCRIPTION_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.13");
+  private static final AttributeType DESTINATION_INDICATOR_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.27");
+  private static final AttributeType DISTINGUISHED_NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.49");
+  private static final AttributeType DIT_CONTENT_RULES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.2");
+  private static final AttributeType DIT_STRUCTURE_RULES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.1");
+  private static final AttributeType DN_QUALIFIER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.46");
+  private static final AttributeType ENHANCED_SEARCH_GUIDE_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.47");
+  private static final AttributeType ENTRY_UUID_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.1.16.4");
+  private static final AttributeType FACSIMILE_TELEPHONE_NUMBER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.23");
+  private static final AttributeType GENERATION_QUALIFIER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.44");
+  private static final AttributeType GIVEN_NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.42");
+  private static final AttributeType GOVERNING_STRUCTURE_RULE_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.10");
+  private static final AttributeType HOUSE_IDENTIFIER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.51");
+  private static final AttributeType INITIALS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.43");
+  private static final AttributeType INTERNATIONAL_ISDN_NUMBER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.25");
+  private static final AttributeType LDAP_SYNTAXES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.1466.101.120.16");
+  private static final AttributeType L_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.7");
+  private static final AttributeType MATCHING_RULES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.4");
+  private static final AttributeType MATCHING_RULE_USE_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.8");
+  private static final AttributeType MEMBER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.31");
+  private static final AttributeType MODIFIERS_NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.18.4");
+  private static final AttributeType MODIFY_TIMESTAMP_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.18.2");
+  private static final AttributeType NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.41");
+  private static final AttributeType NAME_FORMS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.7");
+  private static final AttributeType NAMING_CONTEXTS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.1466.101.120.5");
+  private static final AttributeType OBJECT_CLASSES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.6");
+  private static final AttributeType OBJECT_CLASS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.0");
+  private static final AttributeType OU_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.11");
+  private static final AttributeType OWNER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.32");
+  private static final AttributeType O_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.10");
+  private static final AttributeType PHYSICAL_DELIVERY_OFFICE_NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.19");
+  private static final AttributeType POSTAL_ADDRESS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.16");
+  private static final AttributeType POSTAL_CODE_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.17");
+  private static final AttributeType POST_OFFICE_BOX_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.18");
+  private static final AttributeType PREFERRED_DELIVERY_METHOD_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.28");
+  private static final AttributeType REGISTERED_ADDRESS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.26");
+  private static final AttributeType ROLE_OCCUPANT_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.33");
+  private static final AttributeType SEARCH_GUIDE_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.14");
+  private static final AttributeType SEE_ALSO_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.34");
+  private static final AttributeType SERIAL_NUMBER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.5");
+  private static final AttributeType SN_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.4");
+  private static final AttributeType STREET_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.9");
+  private static final AttributeType STRUCTURAL_OBJECT_CLASS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.21.9");
+  private static final AttributeType ST_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.8");
+  private static final AttributeType SUBSCHEMA_SUBENTRY_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.18.10");
+  private static final AttributeType SUPPORTED_AUTH_PASSWORD_SCHEMES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.4203.1.3.3");
+  private static final AttributeType SUPPORTED_CONTROL_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.1466.101.120.13");
+  private static final AttributeType SUPPORTED_EXTENSION_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.1466.101.120.7");
+  private static final AttributeType SUPPORTED_FEATURES_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.4203.1.3.5");
+  private static final AttributeType SUPPORTED_LDAP_VERSION_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.1466.101.120.15");
+  private static final AttributeType SUPPORTED_SASL_MECHANISMS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.4.1.1466.101.120.14");
+  private static final AttributeType TELEPHONE_NUMBER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.20");
+  private static final AttributeType TELETEX_TERMINAL_IDENTIFIER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.22");
+  private static final AttributeType TELEX_NUMBER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.21");
+  private static final AttributeType TITLE_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.12");
+  private static final AttributeType UID_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("0.9.2342.19200300.100.1.1");
+  private static final AttributeType UNIQUE_MEMBER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.50");
+  private static final AttributeType USER_PASSWORD_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.35");
+  private static final AttributeType VENDOR_NAME_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.1.4");
+  private static final AttributeType VENDOR_VERSION_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("1.3.6.1.1.5");
+  private static final AttributeType X121_ADDRESS_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.24");
+  private static final AttributeType X500_UNIQUE_IDENTIFIER_ATTRIBUTE_TYPE = CoreSchemaImpl
+      .getInstance().getAttributeType("2.5.4.45");
+
+  // Core Object Classes
+  private static final ObjectClass ALIAS_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.1");
+  private static final ObjectClass APPLICATION_PROCESS_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.11");
+  private static final ObjectClass AUTH_PASSWORD_OBJECT_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("1.3.6.1.4.1.4203.1.4.7");
+  private static final ObjectClass COUNTRY_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.2");
+  private static final ObjectClass DC_OBJECT_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("1.3.6.1.4.1.1466.344");
+  private static final ObjectClass DEVICE_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.14");
+  private static final ObjectClass EXTENSIBLE_OBJECT_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("1.3.6.1.4.1.1466.101.120.111");
+  private static final ObjectClass GROUP_OF_NAMES_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.9");
+  private static final ObjectClass GROUP_OF_UNIQUE_NAMES_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.17");
+  private static final ObjectClass LOCALITY_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.3");
+  private static final ObjectClass ORGANIZATIONAL_PERSON_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.7");
+  private static final ObjectClass ORGANIZATIONAL_ROLE_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.8");
+  private static final ObjectClass ORGANIZATIONAL_UNIT_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.5");
+  private static final ObjectClass ORGANIZATION_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.4");
+  private static final ObjectClass PERSON_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.6");
+  private static final ObjectClass RESIDENTIAL_PERSON_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.10");
+  private static final ObjectClass SUBSCHEMA_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.20.1");
+  private static final ObjectClass TOP_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("2.5.6.0");
+  private static final ObjectClass UID_OBJECT_OBJECT_CLASS = CoreSchemaImpl
+      .getInstance().getObjectClass("1.3.6.1.1.3.1");
+
+
+
+  /**
+   * Returns a reference to the {@code aliasedObjectName} Attribute Type which
+   * has the OID {@code 2.5.4.1}.
+   *
+   * @return A reference to the {@code aliasedObjectName} Attribute Type.
+   */
+  public static AttributeType getAliasedObjectNameAttributeType()
+  {
+    return ALIASED_OBJECT_NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code alias} Object Class which has the OID
+   * {@code 2.5.6.1}.
+   *
+   * @return A reference to the {@code alias} Object Class.
+   */
+  public static ObjectClass getAliasObjectClass()
+  {
+    return ALIAS_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code altServer} Attribute Type which has the
+   * OID {@code 1.3.6.1.4.1.1466.101.120.6}.
+   *
+   * @return A reference to the {@code altServer} Attribute Type.
+   */
+  public static AttributeType getAltServerAttributeType()
+  {
+    return ALT_SERVER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code applicationProcess} Object Class which
+   * has the OID {@code 2.5.6.11}.
+   *
+   * @return A reference to the {@code applicationProcess} Object Class.
+   */
+  public static ObjectClass getApplicationProcessObjectClass()
+  {
+    return APPLICATION_PROCESS_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Attribute Type Description Syntax} which
+   * has the OID {@code 1.3.6.1.4.1.1466.115.121.1.3}.
+   *
+   * @return A reference to the {@code Attribute Type Description Syntax}.
+   */
+  public static Syntax getAttributeTypeDescriptionSyntax()
+  {
+    return ATTRIBUTE_TYPE_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code attributeTypes} Attribute Type which has
+   * the OID {@code 2.5.21.5}.
+   *
+   * @return A reference to the {@code attributeTypes} Attribute Type.
+   */
+  public static AttributeType getAttributeTypesAttributeType()
+  {
+    return ATTRIBUTE_TYPES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Authentication Password Syntax} which has
+   * the OID {@code 1.3.6.1.4.1.4203.1.1.2}.
+   *
+   * @return A reference to the {@code Authentication Password Syntax}.
+   */
+  public static Syntax getAuthenticationPasswordSyntax()
+  {
+    return AUTHENTICATION_PASSWORD_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code authPassword} Attribute Type which has
+   * the OID {@code 1.3.6.1.4.1.4203.1.3.4}.
+   *
+   * @return A reference to the {@code authPassword} Attribute Type.
+   */
+  public static AttributeType getAuthPasswordAttributeType()
+  {
+    return AUTH_PASSWORD_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code authPasswordExactMatch} Matching Rule
+   * which has the OID {@code 1.3.6.1.4.1.4203.1.2.2}.
+   *
+   * @return A reference to the {@code authPasswordExactMatch} Matching Rule.
+   */
+  public static MatchingRule getAuthPasswordExactMatchingRule()
+  {
+    return AUTH_PASSWORD_EXACT_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code authPasswordObject} Object Class which
+   * has the OID {@code 1.3.6.1.4.1.4203.1.4.7}.
+   *
+   * @return A reference to the {@code authPasswordObject} Object Class.
+   */
+  public static ObjectClass getAuthPasswordObjectObjectClass()
+  {
+    return AUTH_PASSWORD_OBJECT_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Binary Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.5}.
+   *
+   * @return A reference to the {@code Binary Syntax}.
+   */
+  public static Syntax getBinarySyntax()
+  {
+    return BINARY_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code bitStringMatch} Matching Rule which has
+   * the OID {@code 2.5.13.16}.
+   *
+   * @return A reference to the {@code bitStringMatch} Matching Rule.
+   */
+  public static MatchingRule getBitStringMatchingRule()
+  {
+    return BIT_STRING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Bit String Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.6}.
+   *
+   * @return A reference to the {@code Bit String Syntax}.
+   */
+  public static Syntax getBitStringSyntax()
+  {
+    return BIT_STRING_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code booleanMatch} Matching Rule which has the
+   * OID {@code 2.5.13.13}.
+   *
+   * @return A reference to the {@code booleanMatch} Matching Rule.
+   */
+  public static MatchingRule getBooleanMatchingRule()
+  {
+    return BOOLEAN_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Boolean Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.7}.
+   *
+   * @return A reference to the {@code Boolean Syntax}.
+   */
+  public static Syntax getBooleanSyntax()
+  {
+    return BOOLEAN_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code businessCategory} Attribute Type which
+   * has the OID {@code 2.5.4.15}.
+   *
+   * @return A reference to the {@code businessCategory} Attribute Type.
+   */
+  public static AttributeType getBusinessCategoryAttributeType()
+  {
+    return BUSINESS_CATEGORY_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseExactIA5Match} Matching Rule which
+   * has the OID {@code 1.3.6.1.4.1.1466.109.114.1}.
+   *
+   * @return A reference to the {@code caseExactIA5Match} Matching Rule.
+   */
+  public static MatchingRule getCaseExactIA5MatchingRule()
+  {
+    return CASE_EXACT_IA5_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseExactMatch} Matching Rule which has
+   * the OID {@code 2.5.13.5}.
+   *
+   * @return A reference to the {@code caseExactMatch} Matching Rule.
+   */
+  public static MatchingRule getCaseExactMatchingRule()
+  {
+    return CASE_EXACT_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseExactOrderingMatch} Matching Rule
+   * which has the OID {@code 2.5.13.6}.
+   *
+   * @return A reference to the {@code caseExactOrderingMatch} Matching Rule.
+   */
+  public static MatchingRule getCaseExactOrderingMatchingRule()
+  {
+    return CASE_EXACT_ORDERING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseExactSubstringsMatch} Matching Rule
+   * which has the OID {@code 2.5.13.7}.
+   *
+   * @return A reference to the {@code caseExactSubstringsMatch} Matching Rule.
+   */
+  public static MatchingRule getCaseExactSubstringsMatchingRule()
+  {
+    return CASE_EXACT_SUBSTRINGS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseIgnoreIA5Match} Matching Rule which
+   * has the OID {@code 1.3.6.1.4.1.1466.109.114.2}.
+   *
+   * @return A reference to the {@code caseIgnoreIA5Match} Matching Rule.
+   */
+  public static MatchingRule getCaseIgnoreIA5MatchingRule()
+  {
+    return CASE_IGNORE_IA5_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseIgnoreIA5SubstringsMatch} Matching
+   * Rule which has the OID {@code 1.3.6.1.4.1.1466.109.114.3}.
+   *
+   * @return A reference to the {@code caseIgnoreIA5SubstringsMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getCaseIgnoreIA5SubstringsMatchingRule()
+  {
+    return CASE_IGNORE_IA5_SUBSTRINGS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseIgnoreListMatch} Matching Rule which
+   * has the OID {@code 2.5.13.11}.
+   *
+   * @return A reference to the {@code caseIgnoreListMatch} Matching Rule.
+   */
+  public static MatchingRule getCaseIgnoreListMatchingRule()
+  {
+    return CASE_IGNORE_LIST_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseIgnoreListSubstringsMatch} Matching
+   * Rule which has the OID {@code 2.5.13.12}.
+   *
+   * @return A reference to the {@code caseIgnoreListSubstringsMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getCaseIgnoreListSubstringsMatchingRule()
+  {
+    return CASE_IGNORE_LIST_SUBSTRINGS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseIgnoreMatch} Matching Rule which has
+   * the OID {@code 2.5.13.2}.
+   *
+   * @return A reference to the {@code caseIgnoreMatch} Matching Rule.
+   */
+  public static MatchingRule getCaseIgnoreMatchingRule()
+  {
+    return CASE_IGNORE_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseIgnoreOrderingMatch} Matching Rule
+   * which has the OID {@code 2.5.13.3}.
+   *
+   * @return A reference to the {@code caseIgnoreOrderingMatch} Matching Rule.
+   */
+  public static MatchingRule getCaseIgnoreOrderingMatchingRule()
+  {
+    return CASE_IGNORE_ORDERING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code caseIgnoreSubstringsMatch} Matching Rule
+   * which has the OID {@code 2.5.13.4}.
+   *
+   * @return A reference to the {@code caseIgnoreSubstringsMatch} Matching Rule.
+   */
+  public static MatchingRule getCaseIgnoreSubstringsMatchingRule()
+  {
+    return CASE_IGNORE_SUBSTRINGS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code c} Attribute Type which has the OID
+   * {@code 2.5.4.6}.
+   *
+   * @return A reference to the {@code c} Attribute Type.
+   */
+  public static AttributeType getCAttributeType()
+  {
+    return C_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Certificate List Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.9}.
+   *
+   * @return A reference to the {@code Certificate List Syntax}.
+   */
+  public static Syntax getCertificateListSyntax()
+  {
+    return CERTIFICATE_LIST_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Certificate Pair Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.10}.
+   *
+   * @return A reference to the {@code Certificate Pair Syntax}.
+   */
+  public static Syntax getCertificatePairSyntax()
+  {
+    return CERTIFICATE_PAIR_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Certificate Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.8}.
+   *
+   * @return A reference to the {@code Certificate Syntax}.
+   */
+  public static Syntax getCertificateSyntax()
+  {
+    return CERTIFICATE_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code cn} Attribute Type which has the OID
+   * {@code 2.5.4.3}.
+   *
+   * @return A reference to the {@code cn} Attribute Type.
+   */
+  public static AttributeType getCNAttributeType()
+  {
+    return CN_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code country} Object Class which has the OID
+   * {@code 2.5.6.2}.
+   *
+   * @return A reference to the {@code country} Object Class.
+   */
+  public static ObjectClass getCountryObjectClass()
+  {
+    return COUNTRY_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Country String Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.11}.
+   *
+   * @return A reference to the {@code Country String Syntax}.
+   */
+  public static Syntax getCountryStringSyntax()
+  {
+    return COUNTRY_STRING_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code createTimestamp} Attribute Type which has
+   * the OID {@code 2.5.18.1}.
+   *
+   * @return A reference to the {@code createTimestamp} Attribute Type.
+   */
+  public static AttributeType getCreateTimestampAttributeType()
+  {
+    return CREATE_TIMESTAMP_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code creatorsName} Attribute Type which has
+   * the OID {@code 2.5.18.3}.
+   *
+   * @return A reference to the {@code creatorsName} Attribute Type.
+   */
+  public static AttributeType getCreatorsNameAttributeType()
+  {
+    return CREATORS_NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code dc} Attribute Type which has the OID
+   * {@code 0.9.2342.19200300.100.1.25}.
+   *
+   * @return A reference to the {@code dc} Attribute Type.
+   */
+  public static AttributeType getDCAttributeType()
+  {
+    return DC_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code dcObject} Object Class which has the OID
+   * {@code 1.3.6.1.4.1.1466.344}.
+   *
+   * @return A reference to the {@code dcObject} Object Class.
+   */
+  public static ObjectClass getDCObjectObjectClass()
+  {
+    return DC_OBJECT_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Delivery Method Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.14}.
+   *
+   * @return A reference to the {@code Delivery Method Syntax}.
+   */
+  public static Syntax getDeliveryMethodSyntax()
+  {
+    return DELIVERY_METHOD_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code description} Attribute Type which has the
+   * OID {@code 2.5.4.13}.
+   *
+   * @return A reference to the {@code description} Attribute Type.
+   */
+  public static AttributeType getDescriptionAttributeType()
+  {
+    return DESCRIPTION_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code destinationIndicator} Attribute Type
+   * which has the OID {@code 2.5.4.27}.
+   *
+   * @return A reference to the {@code destinationIndicator} Attribute Type.
+   */
+  public static AttributeType getDestinationIndicatorAttributeType()
+  {
+    return DESTINATION_INDICATOR_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code device} Object Class which has the OID
+   * {@code 2.5.6.14}.
+   *
+   * @return A reference to the {@code device} Object Class.
+   */
+  public static ObjectClass getDeviceObjectClass()
+  {
+    return DEVICE_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code directoryStringFirstComponentMatch}
+   * Matching Rule which has the OID {@code 2.5.13.31}.
+   *
+   * @return A reference to the {@code directoryStringFirstComponentMatch}
+   *         Matching Rule.
+   */
+  public static MatchingRule getDirectoryStringFirstComponentMatchingRule()
+  {
+    return DIRECTORY_STRING_FIRST_COMPONENT_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Directory String Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.15}.
+   *
+   * @return A reference to the {@code Directory String Syntax}.
+   */
+  public static Syntax getDirectoryStringSyntax()
+  {
+    return DIRECTORY_STRING_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code distinguishedName} Attribute Type which
+   * has the OID {@code 2.5.4.49}.
+   *
+   * @return A reference to the {@code distinguishedName} Attribute Type.
+   */
+  public static AttributeType getDistinguishedNameAttributeType()
+  {
+    return DISTINGUISHED_NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code distinguishedNameMatch} Matching Rule
+   * which has the OID {@code 2.5.13.1}.
+   *
+   * @return A reference to the {@code distinguishedNameMatch} Matching Rule.
+   */
+  public static MatchingRule getDistinguishedNameMatchingRule()
+  {
+    return DISTINGUISHED_NAME_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code DIT Content Rule Description Syntax}
+   * which has the OID {@code 1.3.6.1.4.1.1466.115.121.1.16}.
+   *
+   * @return A reference to the {@code DIT Content Rule Description Syntax}.
+   */
+  public static Syntax getDITContentRuleDescriptionSyntax()
+  {
+    return DIT_CONTENT_RULE_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code ditContentRules} Attribute Type which has
+   * the OID {@code 2.5.21.2}.
+   *
+   * @return A reference to the {@code ditContentRules} Attribute Type.
+   */
+  public static AttributeType getDITContentRulesAttributeType()
+  {
+    return DIT_CONTENT_RULES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code DIT Structure Rule Description Syntax}
+   * which has the OID {@code 1.3.6.1.4.1.1466.115.121.1.17}.
+   *
+   * @return A reference to the {@code DIT Structure Rule Description Syntax}.
+   */
+  public static Syntax getDITStructureRuleDescriptionSyntax()
+  {
+    return DIT_STRUCTURE_RULE_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code ditStructureRules} Attribute Type which
+   * has the OID {@code 2.5.21.1}.
+   *
+   * @return A reference to the {@code ditStructureRules} Attribute Type.
+   */
+  public static AttributeType getDITStructureRulesAttributeType()
+  {
+    return DIT_STRUCTURE_RULES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code dnQualifier} Attribute Type which has the
+   * OID {@code 2.5.4.46}.
+   *
+   * @return A reference to the {@code dnQualifier} Attribute Type.
+   */
+  public static AttributeType getDNQualifierAttributeType()
+  {
+    return DN_QUALIFIER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code DN Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.12}.
+   *
+   * @return A reference to the {@code DN Syntax}.
+   */
+  public static Syntax getDNSyntax()
+  {
+    return DN_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Enhanced Guide Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.21}.
+   *
+   * @return A reference to the {@code Enhanced Guide Syntax}.
+   */
+  public static Syntax getEnhancedGuideSyntax()
+  {
+    return ENHANCED_GUIDE_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code enhancedSearchGuide} Attribute Type which
+   * has the OID {@code 2.5.4.47}.
+   *
+   * @return A reference to the {@code enhancedSearchGuide} Attribute Type.
+   */
+  public static AttributeType getEnhancedSearchGuideAttributeType()
+  {
+    return ENHANCED_SEARCH_GUIDE_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code entryUUID} Attribute Type which has the
+   * OID {@code 1.3.6.1.1.16.4}.
+   *
+   * @return A reference to the {@code entryUUID} Attribute Type.
+   */
+  public static AttributeType getEntryUUIDAttributeType()
+  {
+    return ENTRY_UUID_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code extensibleObject} Object Class which has
+   * the OID {@code 1.3.6.1.4.1.1466.101.120.111}.
+   *
+   * @return A reference to the {@code extensibleObject} Object Class.
+   */
+  public static ObjectClass getExtensibleObjectObjectClass()
+  {
+    return EXTENSIBLE_OBJECT_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code facsimileTelephoneNumber} Attribute Type
+   * which has the OID {@code 2.5.4.23}.
+   *
+   * @return A reference to the {@code facsimileTelephoneNumber} Attribute Type.
+   */
+  public static AttributeType getFacsimileTelephoneNumberAttributeType()
+  {
+    return FACSIMILE_TELEPHONE_NUMBER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Facsimile Telephone Number Syntax} which
+   * has the OID {@code 1.3.6.1.4.1.1466.115.121.1.22}.
+   *
+   * @return A reference to the {@code Facsimile Telephone Number Syntax}.
+   */
+  public static Syntax getFacsimileTelephoneNumberSyntax()
+  {
+    return FACSIMILE_TELEPHONE_NUMBER_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Fax Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.23}.
+   *
+   * @return A reference to the {@code Fax Syntax}.
+   */
+  public static Syntax getFaxSyntax()
+  {
+    return FAX_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code generalizedTimeMatch} Matching Rule which
+   * has the OID {@code 2.5.13.27}.
+   *
+   * @return A reference to the {@code generalizedTimeMatch} Matching Rule.
+   */
+  public static MatchingRule getGeneralizedTimeMatchingRule()
+  {
+    return GENERALIZED_TIME_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code generalizedTimeOrderingMatch} Matching
+   * Rule which has the OID {@code 2.5.13.28}.
+   *
+   * @return A reference to the {@code generalizedTimeOrderingMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getGeneralizedTimeOrderingMatchingRule()
+  {
+    return GENERALIZED_TIME_ORDERING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Generalized Time Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.24}.
+   *
+   * @return A reference to the {@code Generalized Time Syntax}.
+   */
+  public static Syntax getGeneralizedTimeSyntax()
+  {
+    return GENERALIZED_TIME_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code generationQualifier} Attribute Type which
+   * has the OID {@code 2.5.4.44}.
+   *
+   * @return A reference to the {@code generationQualifier} Attribute Type.
+   */
+  public static AttributeType getGenerationQualifierAttributeType()
+  {
+    return GENERATION_QUALIFIER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code givenName} Attribute Type which has the
+   * OID {@code 2.5.4.42}.
+   *
+   * @return A reference to the {@code givenName} Attribute Type.
+   */
+  public static AttributeType getGivenNameAttributeType()
+  {
+    return GIVEN_NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code governingStructureRule} Attribute Type
+   * which has the OID {@code 2.5.21.10}.
+   *
+   * @return A reference to the {@code governingStructureRule} Attribute Type.
+   */
+  public static AttributeType getGoverningStructureRuleAttributeType()
+  {
+    return GOVERNING_STRUCTURE_RULE_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code groupOfNames} Object Class which has the
+   * OID {@code 2.5.6.9}.
+   *
+   * @return A reference to the {@code groupOfNames} Object Class.
+   */
+  public static ObjectClass getGroupOfNamesObjectClass()
+  {
+    return GROUP_OF_NAMES_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code groupOfUniqueNames} Object Class which
+   * has the OID {@code 2.5.6.17}.
+   *
+   * @return A reference to the {@code groupOfUniqueNames} Object Class.
+   */
+  public static ObjectClass getGroupOfUniqueNamesObjectClass()
+  {
+    return GROUP_OF_UNIQUE_NAMES_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Guide Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.25}.
+   *
+   * @return A reference to the {@code Guide Syntax}.
+   */
+  public static Syntax getGuideSyntax()
+  {
+    return GUIDE_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code houseIdentifier} Attribute Type which has
+   * the OID {@code 2.5.4.51}.
+   *
+   * @return A reference to the {@code houseIdentifier} Attribute Type.
+   */
+  public static AttributeType getHouseIdentifierAttributeType()
+  {
+    return HOUSE_IDENTIFIER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code IA5 String Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.26}.
+   *
+   * @return A reference to the {@code IA5 String Syntax}.
+   */
+  public static Syntax getIA5StringSyntax()
+  {
+    return IA5_STRING_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code initials} Attribute Type which has the
+   * OID {@code 2.5.4.43}.
+   *
+   * @return A reference to the {@code initials} Attribute Type.
+   */
+  public static AttributeType getInitialsAttributeType()
+  {
+    return INITIALS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the singleton core schema.
+   *
+   * @return The core schema.
+   */
+  public static Schema getInstance()
+  {
+    return CoreSchemaImpl.getInstance();
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code integerFirstComponentMatch} Matching Rule
+   * which has the OID {@code 2.5.13.29}.
+   *
+   * @return A reference to the {@code integerFirstComponentMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getIntegerFirstComponentMatchingRule()
+  {
+    return INTEGER_FIRST_COMPONENT_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code integerMatch} Matching Rule which has the
+   * OID {@code 2.5.13.14}.
+   *
+   * @return A reference to the {@code integerMatch} Matching Rule.
+   */
+  public static MatchingRule getIntegerMatchingRule()
+  {
+    return INTEGER_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code integerOrderingMatch} Matching Rule which
+   * has the OID {@code 2.5.13.15}.
+   *
+   * @return A reference to the {@code integerOrderingMatch} Matching Rule.
+   */
+  public static MatchingRule getIntegerOrderingMatchingRule()
+  {
+    return INTEGER_ORDERING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Integer Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.27}.
+   *
+   * @return A reference to the {@code Integer Syntax}.
+   */
+  public static Syntax getIntegerSyntax()
+  {
+    return INTEGER_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code internationalISDNNumber} Attribute Type
+   * which has the OID {@code 2.5.4.25}.
+   *
+   * @return A reference to the {@code internationalISDNNumber} Attribute Type.
+   */
+  public static AttributeType getInternationalISDNNumberAttributeType()
+  {
+    return INTERNATIONAL_ISDN_NUMBER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code JPEG Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.28}.
+   *
+   * @return A reference to the {@code JPEG Syntax}.
+   */
+  public static Syntax getJPEGSyntax()
+  {
+    return JPEG_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code keywordMatch} Matching Rule which has the
+   * OID {@code 2.5.13.33}.
+   *
+   * @return A reference to the {@code keywordMatch} Matching Rule.
+   */
+  public static MatchingRule getKeywordMatchingRule()
+  {
+    return KEYWORD_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code l} Attribute Type which has the OID
+   * {@code 2.5.4.7}.
+   *
+   * @return A reference to the {@code l} Attribute Type.
+   */
+  public static AttributeType getLAttributeType()
+  {
+    return L_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code LDAP Syntax Description Syntax} which has
+   * the OID {@code 1.3.6.1.4.1.1466.115.121.1.54}.
+   *
+   * @return A reference to the {@code LDAP Syntax Description Syntax}.
+   */
+  public static Syntax getLDAPSyntaxDescriptionSyntax()
+  {
+    return LDAP_SYNTAX_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code ldapSyntaxes} Attribute Type which has
+   * the OID {@code 1.3.6.1.4.1.1466.101.120.16}.
+   *
+   * @return A reference to the {@code ldapSyntaxes} Attribute Type.
+   */
+  public static AttributeType getLDAPSyntaxesAttributeType()
+  {
+    return LDAP_SYNTAXES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code locality} Object Class which has the OID
+   * {@code 2.5.6.3}.
+   *
+   * @return A reference to the {@code locality} Object Class.
+   */
+  public static ObjectClass getLocalityObjectClass()
+  {
+    return LOCALITY_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Matching Rule Description Syntax} which
+   * has the OID {@code 1.3.6.1.4.1.1466.115.121.1.30}.
+   *
+   * @return A reference to the {@code Matching Rule Description Syntax}.
+   */
+  public static Syntax getMatchingRuleDescriptionSyntax()
+  {
+    return MATCHING_RULE_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code matchingRules} Attribute Type which has
+   * the OID {@code 2.5.21.4}.
+   *
+   * @return A reference to the {@code matchingRules} Attribute Type.
+   */
+  public static AttributeType getMatchingRulesAttributeType()
+  {
+    return MATCHING_RULES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code matchingRuleUse} Attribute Type which has
+   * the OID {@code 2.5.21.8}.
+   *
+   * @return A reference to the {@code matchingRuleUse} Attribute Type.
+   */
+  public static AttributeType getMatchingRuleUseAttributeType()
+  {
+    return MATCHING_RULE_USE_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Matching Rule Use Description Syntax}
+   * which has the OID {@code 1.3.6.1.4.1.1466.115.121.1.31}.
+   *
+   * @return A reference to the {@code Matching Rule Use Description Syntax}.
+   */
+  public static Syntax getMatchingRuleUseDescriptionSyntax()
+  {
+    return MATCHING_RULE_USE_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code member} Attribute Type which has the OID
+   * {@code 2.5.4.31}.
+   *
+   * @return A reference to the {@code member} Attribute Type.
+   */
+  public static AttributeType getMemberAttributeType()
+  {
+    return MEMBER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code modifiersName} Attribute Type which has
+   * the OID {@code 2.5.18.4}.
+   *
+   * @return A reference to the {@code modifiersName} Attribute Type.
+   */
+  public static AttributeType getModifiersNameAttributeType()
+  {
+    return MODIFIERS_NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code modifyTimestamp} Attribute Type which has
+   * the OID {@code 2.5.18.2}.
+   *
+   * @return A reference to the {@code modifyTimestamp} Attribute Type.
+   */
+  public static AttributeType getModifyTimestampAttributeType()
+  {
+    return MODIFY_TIMESTAMP_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Name and Optional UID Syntax} which has
+   * the OID {@code 1.3.6.1.4.1.1466.115.121.1.34}.
+   *
+   * @return A reference to the {@code Name and Optional UID Syntax}.
+   */
+  public static Syntax getNameAndOptionalUIDSyntax()
+  {
+    return NAME_AND_OPTIONAL_UID_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code name} Attribute Type which has the OID
+   * {@code 2.5.4.41}.
+   *
+   * @return A reference to the {@code name} Attribute Type.
+   */
+  public static AttributeType getNameAttributeType()
+  {
+    return NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Name Form Description Syntax} which has
+   * the OID {@code 1.3.6.1.4.1.1466.115.121.1.35}.
+   *
+   * @return A reference to the {@code Name Form Description Syntax}.
+   */
+  public static Syntax getNameFormDescriptionSyntax()
+  {
+    return NAME_FORM_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code nameForms} Attribute Type which has the
+   * OID {@code 2.5.21.7}.
+   *
+   * @return A reference to the {@code nameForms} Attribute Type.
+   */
+  public static AttributeType getNameFormsAttributeType()
+  {
+    return NAME_FORMS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code namingContexts} Attribute Type which has
+   * the OID {@code 1.3.6.1.4.1.1466.101.120.5}.
+   *
+   * @return A reference to the {@code namingContexts} Attribute Type.
+   */
+  public static AttributeType getNamingContextsAttributeType()
+  {
+    return NAMING_CONTEXTS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code numericStringMatch} Matching Rule which
+   * has the OID {@code 2.5.13.8}.
+   *
+   * @return A reference to the {@code numericStringMatch} Matching Rule.
+   */
+  public static MatchingRule getNumericStringMatchingRule()
+  {
+    return NUMERIC_STRING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code numericStringOrderingMatch} Matching Rule
+   * which has the OID {@code 2.5.13.9}.
+   *
+   * @return A reference to the {@code numericStringOrderingMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getNumericStringOrderingMatchingRule()
+  {
+    return NUMERIC_STRING_ORDERING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code numericStringSubstringsMatch} Matching
+   * Rule which has the OID {@code 2.5.13.10}.
+   *
+   * @return A reference to the {@code numericStringSubstringsMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getNumericStringSubstringsMatchingRule()
+  {
+    return NUMERIC_STRING_SUBSTRINGS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Numeric String Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.36}.
+   *
+   * @return A reference to the {@code Numeric String Syntax}.
+   */
+  public static Syntax getNumericStringSyntax()
+  {
+    return NUMERIC_STRING_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code o} Attribute Type which has the OID
+   * {@code 2.5.4.10}.
+   *
+   * @return A reference to the {@code o} Attribute Type.
+   */
+  public static AttributeType getOAttributeType()
+  {
+    return O_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code objectClass} Attribute Type which has the
+   * OID {@code 2.5.4.0}.
+   *
+   * @return A reference to the {@code objectClass} Attribute Type.
+   */
+  public static AttributeType getObjectClassAttributeType()
+  {
+    return OBJECT_CLASS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Object Class Description Syntax} which
+   * has the OID {@code 1.3.6.1.4.1.1466.115.121.1.37}.
+   *
+   * @return A reference to the {@code Object Class Description Syntax}.
+   */
+  public static Syntax getObjectClassDescriptionSyntax()
+  {
+    return OBJECT_CLASS_DESCRIPTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code objectClasses} Attribute Type which has
+   * the OID {@code 2.5.21.6}.
+   *
+   * @return A reference to the {@code objectClasses} Attribute Type.
+   */
+  public static AttributeType getObjectClassesAttributeType()
+  {
+    return OBJECT_CLASSES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code objectIdentifierFirstComponentMatch}
+   * Matching Rule which has the OID {@code 2.5.13.30}.
+   *
+   * @return A reference to the {@code objectIdentifierFirstComponentMatch}
+   *         Matching Rule.
+   */
+  public static MatchingRule getObjectIdentifierFirstComponentMatchingRule()
+  {
+    return OBJECT_IDENTIFIER_FIRST_COMPONENT_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code objectIdentifierMatch} Matching Rule
+   * which has the OID {@code 2.5.13.0}.
+   *
+   * @return A reference to the {@code objectIdentifierMatch} Matching Rule.
+   */
+  public static MatchingRule getObjectIdentifierMatchingRule()
+  {
+    return OBJECT_IDENTIFIER_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code octetStringMatch} Matching Rule which has
+   * the OID {@code 2.5.13.17}.
+   *
+   * @return A reference to the {@code octetStringMatch} Matching Rule.
+   */
+  public static MatchingRule getOctetStringMatchingRule()
+  {
+    return OCTET_STRING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code octetStringOrderingMatch} Matching Rule
+   * which has the OID {@code 2.5.13.18}.
+   *
+   * @return A reference to the {@code octetStringOrderingMatch} Matching Rule.
+   */
+  public static MatchingRule getOctetStringOrderingMatchingRule()
+  {
+    return OCTET_STRING_ORDERING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code octetStringSubstringsMatch} Matching Rule
+   * which has the OID {@code 2.5.13.19}.
+   *
+   * @return A reference to the {@code octetStringSubstringsMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getOctetStringSubstringsMatchingRule()
+  {
+    return OCTET_STRING_SUBSTRINGS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Octet String Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.40}.
+   *
+   * @return A reference to the {@code Octet String Syntax}.
+   */
+  public static Syntax getOctetStringSyntax()
+  {
+    return OCTET_STRING_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code OID Syntax} which has the OID {@code
+   * 1.3.6.1.4.1.1466.115.121.1.38}.
+   *
+   * @return A reference to the {@code OID Syntax}.
+   */
+  public static Syntax getOIDSyntax()
+  {
+    return OID_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code organizationalPerson} Object Class which
+   * has the OID {@code 2.5.6.7}.
+   *
+   * @return A reference to the {@code organizationalPerson} Object Class.
+   */
+  public static ObjectClass getOrganizationalPersonObjectClass()
+  {
+    return ORGANIZATIONAL_PERSON_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code organizationalRole} Object Class which
+   * has the OID {@code 2.5.6.8}.
+   *
+   * @return A reference to the {@code organizationalRole} Object Class.
+   */
+  public static ObjectClass getOrganizationalRoleObjectClass()
+  {
+    return ORGANIZATIONAL_ROLE_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code organizationalUnit} Object Class which
+   * has the OID {@code 2.5.6.5}.
+   *
+   * @return A reference to the {@code organizationalUnit} Object Class.
+   */
+  public static ObjectClass getOrganizationalUnitObjectClass()
+  {
+    return ORGANIZATIONAL_UNIT_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code organization} Object Class which has the
+   * OID {@code 2.5.6.4}.
+   *
+   * @return A reference to the {@code organization} Object Class.
+   */
+  public static ObjectClass getOrganizationObjectClass()
+  {
+    return ORGANIZATION_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Other Mailbox Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.39}.
+   *
+   * @return A reference to the {@code Other Mailbox Syntax}.
+   */
+  public static Syntax getOtherMailboxSyntax()
+  {
+    return OTHER_MAILBOX_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code ou} Attribute Type which has the OID
+   * {@code 2.5.4.11}.
+   *
+   * @return A reference to the {@code ou} Attribute Type.
+   */
+  public static AttributeType getOUAttributeType()
+  {
+    return OU_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code owner} Attribute Type which has the OID
+   * {@code 2.5.4.32}.
+   *
+   * @return A reference to the {@code owner} Attribute Type.
+   */
+  public static AttributeType getOwnerAttributeType()
+  {
+    return OWNER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code person} Object Class which has the OID
+   * {@code 2.5.6.6}.
+   *
+   * @return A reference to the {@code person} Object Class.
+   */
+  public static ObjectClass getPersonObjectClass()
+  {
+    return PERSON_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code physicalDeliveryOfficeName} Attribute
+   * Type which has the OID {@code 2.5.4.19}.
+   *
+   * @return A reference to the {@code physicalDeliveryOfficeName} Attribute
+   *         Type.
+   */
+  public static AttributeType getPhysicalDeliveryOfficeNameAttributeType()
+  {
+    return PHYSICAL_DELIVERY_OFFICE_NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code postalAddress} Attribute Type which has
+   * the OID {@code 2.5.4.16}.
+   *
+   * @return A reference to the {@code postalAddress} Attribute Type.
+   */
+  public static AttributeType getPostalAddressAttributeType()
+  {
+    return POSTAL_ADDRESS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Postal Address Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.41}.
+   *
+   * @return A reference to the {@code Postal Address Syntax}.
+   */
+  public static Syntax getPostalAddressSyntax()
+  {
+    return POSTAL_ADDRESS_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code postalCode} Attribute Type which has the
+   * OID {@code 2.5.4.17}.
+   *
+   * @return A reference to the {@code postalCode} Attribute Type.
+   */
+  public static AttributeType getPostalCodeAttributeType()
+  {
+    return POSTAL_CODE_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code postOfficeBox} Attribute Type which has
+   * the OID {@code 2.5.4.18}.
+   *
+   * @return A reference to the {@code postOfficeBox} Attribute Type.
+   */
+  public static AttributeType getPostOfficeBoxAttributeType()
+  {
+    return POST_OFFICE_BOX_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code preferredDeliveryMethod} Attribute Type
+   * which has the OID {@code 2.5.4.28}.
+   *
+   * @return A reference to the {@code preferredDeliveryMethod} Attribute Type.
+   */
+  public static AttributeType getPreferredDeliveryMethodAttributeType()
+  {
+    return PREFERRED_DELIVERY_METHOD_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code presentationAddressMatch} Matching Rule
+   * which has the OID {@code 2.5.13.22}.
+   *
+   * @return A reference to the {@code presentationAddressMatch} Matching Rule.
+   */
+  public static MatchingRule getPresentationAddressMatchingRule()
+  {
+    return PRESENTATION_ADDRESS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Presentation Address Syntax} which has
+   * the OID {@code 1.3.6.1.4.1.1466.115.121.1.43}.
+   *
+   * @return A reference to the {@code Presentation Address Syntax}.
+   */
+  public static Syntax getPresentationAddressSyntax()
+  {
+    return PRESENTATION_ADDRESS_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Printable String Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.44}.
+   *
+   * @return A reference to the {@code Printable String Syntax}.
+   */
+  public static Syntax getPrintableStringSyntax()
+  {
+    return PRINTABLE_STRING_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code protocolInformationMatch} Matching Rule
+   * which has the OID {@code 2.5.13.24}.
+   *
+   * @return A reference to the {@code protocolInformationMatch} Matching Rule.
+   */
+  public static MatchingRule getProtocolInformationMatchingRule()
+  {
+    return PROTOCOL_INFORMATION_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Protocol Information Syntax} which has
+   * the OID {@code 1.3.6.1.4.1.1466.115.121.1.42}.
+   *
+   * @return A reference to the {@code Protocol Information Syntax}.
+   */
+  public static Syntax getProtocolInformationSyntax()
+  {
+    return PROTOCOL_INFORMATION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code registeredAddress} Attribute Type which
+   * has the OID {@code 2.5.4.26}.
+   *
+   * @return A reference to the {@code registeredAddress} Attribute Type.
+   */
+  public static AttributeType getRegisteredAddressAttributeType()
+  {
+    return REGISTERED_ADDRESS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code residentialPerson} Object Class which has
+   * the OID {@code 2.5.6.10}.
+   *
+   * @return A reference to the {@code residentialPerson} Object Class.
+   */
+  public static ObjectClass getResidentialPersonObjectClass()
+  {
+    return RESIDENTIAL_PERSON_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code roleOccupant} Attribute Type which has
+   * the OID {@code 2.5.4.33}.
+   *
+   * @return A reference to the {@code roleOccupant} Attribute Type.
+   */
+  public static AttributeType getRoleOccupantAttributeType()
+  {
+    return ROLE_OCCUPANT_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code searchGuide} Attribute Type which has the
+   * OID {@code 2.5.4.14}.
+   *
+   * @return A reference to the {@code searchGuide} Attribute Type.
+   */
+  public static AttributeType getSearchGuideAttributeType()
+  {
+    return SEARCH_GUIDE_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code seeAlso} Attribute Type which has the OID
+   * {@code 2.5.4.34}.
+   *
+   * @return A reference to the {@code seeAlso} Attribute Type.
+   */
+  public static AttributeType getSeeAlsoAttributeType()
+  {
+    return SEE_ALSO_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code serialNumber} Attribute Type which has
+   * the OID {@code 2.5.4.5}.
+   *
+   * @return A reference to the {@code serialNumber} Attribute Type.
+   */
+  public static AttributeType getSerialNumberAttributeType()
+  {
+    return SERIAL_NUMBER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code sn} Attribute Type which has the OID
+   * {@code 2.5.4.4}.
+   *
+   * @return A reference to the {@code sn} Attribute Type.
+   */
+  public static AttributeType getSNAttributeType()
+  {
+    return SN_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code st} Attribute Type which has the OID
+   * {@code 2.5.4.8}.
+   *
+   * @return A reference to the {@code st} Attribute Type.
+   */
+  public static AttributeType getSTAttributeType()
+  {
+    return ST_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code street} Attribute Type which has the OID
+   * {@code 2.5.4.9}.
+   *
+   * @return A reference to the {@code street} Attribute Type.
+   */
+  public static AttributeType getStreetAttributeType()
+  {
+    return STREET_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code structuralObjectClass} Attribute Type
+   * which has the OID {@code 2.5.21.9}.
+   *
+   * @return A reference to the {@code structuralObjectClass} Attribute Type.
+   */
+  public static AttributeType getStructuralObjectClassAttributeType()
+  {
+    return STRUCTURAL_OBJECT_CLASS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code subschema} Object Class which has the OID
+   * {@code 2.5.20.1}.
+   *
+   * @return A reference to the {@code subschema} Object Class.
+   */
+  public static ObjectClass getSubschemaObjectClass()
+  {
+    return SUBSCHEMA_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code subschemaSubentry} Attribute Type which
+   * has the OID {@code 2.5.18.10}.
+   *
+   * @return A reference to the {@code subschemaSubentry} Attribute Type.
+   */
+  public static AttributeType getSubschemaSubentryAttributeType()
+  {
+    return SUBSCHEMA_SUBENTRY_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Substring Assertion Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.58}.
+   *
+   * @return A reference to the {@code Substring Assertion Syntax}.
+   */
+  public static Syntax getSubstringAssertionSyntax()
+  {
+    return SUBSTRING_ASSERTION_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Supported Algorithm Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.49}.
+   *
+   * @return A reference to the {@code Supported Algorithm Syntax}.
+   */
+  public static Syntax getSupportedAlgorithmSyntax()
+  {
+    return SUPPORTED_ALGORITHM_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code supportedAuthPasswordSchemes} Attribute
+   * Type which has the OID {@code 1.3.6.1.4.1.4203.1.3.3}.
+   *
+   * @return A reference to the {@code supportedAuthPasswordSchemes} Attribute
+   *         Type.
+   */
+  public static AttributeType getSupportedAuthPasswordSchemesAttributeType()
+  {
+    return SUPPORTED_AUTH_PASSWORD_SCHEMES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code supportedControl} Attribute Type which
+   * has the OID {@code 1.3.6.1.4.1.1466.101.120.13}.
+   *
+   * @return A reference to the {@code supportedControl} Attribute Type.
+   */
+  public static AttributeType getSupportedControlAttributeType()
+  {
+    return SUPPORTED_CONTROL_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code supportedExtension} Attribute Type which
+   * has the OID {@code 1.3.6.1.4.1.1466.101.120.7}.
+   *
+   * @return A reference to the {@code supportedExtension} Attribute Type.
+   */
+  public static AttributeType getSupportedExtensionAttributeType()
+  {
+    return SUPPORTED_EXTENSION_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code supportedFeatures} Attribute Type which
+   * has the OID {@code 1.3.6.1.4.1.4203.1.3.5}.
+   *
+   * @return A reference to the {@code supportedFeatures} Attribute Type.
+   */
+  public static AttributeType getSupportedFeaturesAttributeType()
+  {
+    return SUPPORTED_FEATURES_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code supportedLDAPVersion} Attribute Type
+   * which has the OID {@code 1.3.6.1.4.1.1466.101.120.15}.
+   *
+   * @return A reference to the {@code supportedLDAPVersion} Attribute Type.
+   */
+  public static AttributeType getSupportedLDAPVersionAttributeType()
+  {
+    return SUPPORTED_LDAP_VERSION_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code supportedSASLMechanisms} Attribute Type
+   * which has the OID {@code 1.3.6.1.4.1.1466.101.120.14}.
+   *
+   * @return A reference to the {@code supportedSASLMechanisms} Attribute Type.
+   */
+  public static AttributeType getSupportedSASLMechanismsAttributeType()
+  {
+    return SUPPORTED_SASL_MECHANISMS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code telephoneNumber} Attribute Type which has
+   * the OID {@code 2.5.4.20}.
+   *
+   * @return A reference to the {@code telephoneNumber} Attribute Type.
+   */
+  public static AttributeType getTelephoneNumberAttributeType()
+  {
+    return TELEPHONE_NUMBER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code telephoneNumberMatch} Matching Rule which
+   * has the OID {@code 2.5.13.20}.
+   *
+   * @return A reference to the {@code telephoneNumberMatch} Matching Rule.
+   */
+  public static MatchingRule getTelephoneNumberMatchingRule()
+  {
+    return TELEPHONE_NUMBER_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code telephoneNumberSubstringsMatch} Matching
+   * Rule which has the OID {@code 2.5.13.21}.
+   *
+   * @return A reference to the {@code telephoneNumberSubstringsMatch} Matching
+   *         Rule.
+   */
+  public static MatchingRule getTelephoneNumberSubstringsMatchingRule()
+  {
+    return TELEPHONE_NUMBER_SUBSTRINGS_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Telephone Number Syntax} which has the
+   * OID {@code 1.3.6.1.4.1.1466.115.121.1.50}.
+   *
+   * @return A reference to the {@code Telephone Number Syntax}.
+   */
+  public static Syntax getTelephoneNumberSyntax()
+  {
+    return TELEPHONE_NUMBER_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code teletexTerminalIdentifier} Attribute Type
+   * which has the OID {@code 2.5.4.22}.
+   *
+   * @return A reference to the {@code teletexTerminalIdentifier} Attribute
+   *         Type.
+   */
+  public static AttributeType getTeletexTerminalIdentifierAttributeType()
+  {
+    return TELETEX_TERMINAL_IDENTIFIER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Teletex Terminal Identifier Syntax} which
+   * has the OID {@code 1.3.6.1.4.1.1466.115.121.1.51}.
+   *
+   * @return A reference to the {@code Teletex Terminal Identifier Syntax}.
+   */
+  public static Syntax getTeletexTerminalIdentifierSyntax()
+  {
+    return TELETEX_TERMINAL_IDENTIFIER_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code telexNumber} Attribute Type which has the
+   * OID {@code 2.5.4.21}.
+   *
+   * @return A reference to the {@code telexNumber} Attribute Type.
+   */
+  public static AttributeType getTelexNumberAttributeType()
+  {
+    return TELEX_NUMBER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code Telex Number Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.52}.
+   *
+   * @return A reference to the {@code Telex Number Syntax}.
+   */
+  public static Syntax getTelexNumberSyntax()
+  {
+    return TELEX_NUMBER_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code title} Attribute Type which has the OID
+   * {@code 2.5.4.12}.
+   *
+   * @return A reference to the {@code title} Attribute Type.
+   */
+  public static AttributeType getTitleAttributeType()
+  {
+    return TITLE_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code top} Object Class which has the OID
+   * {@code 2.5.6.0}.
+   *
+   * @return A reference to the {@code top} Object Class.
+   */
+  public static ObjectClass getTopObjectClass()
+  {
+    return TOP_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code uid} Attribute Type which has the OID
+   * {@code 0.9.2342.19200300.100.1.1}.
+   *
+   * @return A reference to the {@code uid} Attribute Type.
+   */
+  public static AttributeType getUIDAttributeType()
+  {
+    return UID_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code uidObject} Object Class which has the OID
+   * {@code 1.3.6.1.1.3.1}.
+   *
+   * @return A reference to the {@code uidObject} Object Class.
+   */
+  public static ObjectClass getUIDObjectObjectClass()
+  {
+    return UID_OBJECT_OBJECT_CLASS;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code uniqueMember} Attribute Type which has
+   * the OID {@code 2.5.4.50}.
+   *
+   * @return A reference to the {@code uniqueMember} Attribute Type.
+   */
+  public static AttributeType getUniqueMemberAttributeType()
+  {
+    return UNIQUE_MEMBER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code uniqueMemberMatch} Matching Rule which
+   * has the OID {@code 2.5.13.23}.
+   *
+   * @return A reference to the {@code uniqueMemberMatch} Matching Rule.
+   */
+  public static MatchingRule getUniqueMemberMatchingRule()
+  {
+    return UNIQUE_MEMBER_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code userPassword} Attribute Type which has
+   * the OID {@code 2.5.4.35}.
+   *
+   * @return A reference to the {@code userPassword} Attribute Type.
+   */
+  public static AttributeType getUserPasswordAttributeType()
+  {
+    return USER_PASSWORD_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code UTC Time Syntax} which has the OID
+   * {@code 1.3.6.1.4.1.1466.115.121.1.53}.
+   *
+   * @return A reference to the {@code UTC Time Syntax}.
+   */
+  public static Syntax getUTCTimeSyntax()
+  {
+    return UTC_TIME_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code uuidMatch} Matching Rule which has the
+   * OID {@code 1.3.6.1.1.16.2}.
+   *
+   * @return A reference to the {@code uuidMatch} Matching Rule.
+   */
+  public static MatchingRule getUUIDMatchingRule()
+  {
+    return UUID_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code uuidOrderingMatch} Matching Rule which
+   * has the OID {@code 1.3.6.1.1.16.3}.
+   *
+   * @return A reference to the {@code uuidOrderingMatch} Matching Rule.
+   */
+  public static MatchingRule getUUIDOrderingMatchingRule()
+  {
+    return UUID_ORDERING_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code UUID Syntax} which has the OID {@code
+   * 1.3.6.1.1.16.1}.
+   *
+   * @return A reference to the {@code UUID Syntax}.
+   */
+  public static Syntax getUUIDSyntax()
+  {
+    return UUID_SYNTAX;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code vendorName} Attribute Type which has the
+   * OID {@code 1.3.6.1.1.4}.
+   *
+   * @return A reference to the {@code vendorName} Attribute Type.
+   */
+  public static AttributeType getVendorNameAttributeType()
+  {
+    return VENDOR_NAME_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code vendorVersion} Attribute Type which has
+   * the OID {@code 1.3.6.1.1.5}.
+   *
+   * @return A reference to the {@code vendorVersion} Attribute Type.
+   */
+  public static AttributeType getVendorVersionAttributeType()
+  {
+    return VENDOR_VERSION_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code wordMatch} Matching Rule which has the
+   * OID {@code 2.5.13.32}.
+   *
+   * @return A reference to the {@code wordMatch} Matching Rule.
+   */
+  public static MatchingRule getWordMatchingRule()
+  {
+    return WORD_MATCHING_RULE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code x121Address} Attribute Type which has the
+   * OID {@code 2.5.4.24}.
+   *
+   * @return A reference to the {@code x121Address} Attribute Type.
+   */
+  public static AttributeType getX121AddressAttributeType()
+  {
+    return X121_ADDRESS_ATTRIBUTE_TYPE;
+  }
+
+
+
+  /**
+   * Returns a reference to the {@code x500UniqueIdentifier} Attribute Type
+   * which has the OID {@code 2.5.4.45}.
+   *
+   * @return A reference to the {@code x500UniqueIdentifier} Attribute Type.
+   */
+  public static AttributeType getX500UniqueIdentifierAttributeType()
+  {
+    return X500_UNIQUE_IDENTIFIER_ATTRIBUTE_TYPE;
+  }
+
+
+
+  // Prevent instantiation
+  private CoreSchema()
+  {
+    // Nothing to do.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchemaImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchemaImpl.java
new file mode 100644
index 0000000..775be20
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CoreSchemaImpl.java
@@ -0,0 +1,1090 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import java.util.*;
+
+
+
+final class CoreSchemaImpl
+{
+  private static final Map<String, List<String>> X500_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections.singletonList("X.500"));
+
+  private static final Map<String, List<String>> RFC2252_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("RFC 2252"));
+
+  private static final Map<String, List<String>> RFC3045_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("RFC 3045"));
+
+  private static final Map<String, List<String>> RFC3112_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("RFC 3112"));
+
+  private static final Map<String, List<String>> RFC4512_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("RFC 4512"));
+
+  private static final Map<String, List<String>> RFC4517_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("RFC 4517"));
+
+  private static final Map<String, List<String>> RFC4519_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("RFC 4519"));
+
+  private static final Map<String, List<String>> RFC4530_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("RFC 4530"));
+
+  static final Map<String, List<String>> OPENDS_ORIGIN = Collections
+      .singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections
+          .singletonList("OpenDS Directory Server"));
+
+  private static final String EMPTY_STRING = "".intern();
+
+  private static final Set<String> EMPTY_STRING_SET = Collections.emptySet();
+
+  private static final Schema SINGLETON;
+
+  static
+  {
+    final SchemaBuilder builder = new SchemaBuilder("Core Schema");
+    defaultSyntaxes(builder);
+    defaultMatchingRules(builder);
+    defaultAttributeTypes(builder);
+    defaultObjectClasses(builder);
+
+    addRFC4519(builder);
+    addRFC4530(builder);
+    addRFC3045(builder);
+    addRFC3112(builder);
+    addSunProprietary(builder);
+
+    SINGLETON = builder.toSchema().nonStrict();
+  }
+
+
+
+  static Schema getInstance()
+  {
+    return SINGLETON;
+  }
+
+
+
+  private static void addRFC3045(final SchemaBuilder builder)
+  {
+    builder.addAttributeType("1.3.6.1.1.4", Collections
+        .singletonList("vendorName"), EMPTY_STRING, false, null,
+        EMR_CASE_EXACT_IA5_OID, null, null, null, SYNTAX_DIRECTORY_STRING_OID,
+        true, false, true, AttributeUsage.DSA_OPERATION, RFC3045_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.1.5", Collections
+        .singletonList("vendorVersion"), EMPTY_STRING, false, null,
+        EMR_CASE_EXACT_IA5_OID, null, null, null, SYNTAX_DIRECTORY_STRING_OID,
+        true, false, true, AttributeUsage.DSA_OPERATION, RFC3045_ORIGIN, false);
+  }
+
+
+
+  private static void addRFC3112(final SchemaBuilder builder)
+  {
+    builder.addSyntax(SYNTAX_AUTH_PASSWORD_OID,
+        SYNTAX_AUTH_PASSWORD_DESCRIPTION, RFC3112_ORIGIN,
+        new AuthPasswordSyntaxImpl(), false);
+    builder.addMatchingRule(EMR_AUTH_PASSWORD_EXACT_OID, Collections
+        .singletonList(EMR_AUTH_PASSWORD_EXACT_NAME),
+        EMR_AUTH_PASSWORD_EXACT_DESCRIPTION, false, SYNTAX_AUTH_PASSWORD_OID,
+        RFC3112_ORIGIN, new AuthPasswordExactEqualityMatchingRuleImpl(), false);
+    builder.addAttributeType("1.3.6.1.4.1.4203.1.3.3", Collections
+        .singletonList("supportedAuthPasswordSchemes"),
+        "supported password storage schemes", false, null,
+        EMR_CASE_EXACT_IA5_OID, null, null, null, SYNTAX_IA5_STRING_OID, false,
+        false, false, AttributeUsage.DSA_OPERATION, RFC3112_ORIGIN, false);
+    builder.addAttributeType("1.3.6.1.4.1.4203.1.3.4", Collections
+        .singletonList("authPassword"), "password authentication information",
+        false, null, EMR_AUTH_PASSWORD_EXACT_OID, null, null, null,
+        SYNTAX_AUTH_PASSWORD_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC3112_ORIGIN, false);
+    builder.addObjectClass("1.3.6.1.4.1.4203.1.4.7", Collections
+        .singletonList("authPasswordObject"),
+        "authentication password mix in class", false, EMPTY_STRING_SET,
+        EMPTY_STRING_SET, Collections.singleton("authPassword"),
+        ObjectClassType.AUXILIARY, RFC3112_ORIGIN, false);
+  }
+
+
+
+  private static void addRFC4519(final SchemaBuilder builder)
+  {
+    builder.addAttributeType("2.5.4.15", Collections
+        .singletonList("businessCategory"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.41", Collections.singletonList("name"),
+        EMPTY_STRING, false, null, EMR_CASE_IGNORE_OID, null,
+        SMR_CASE_IGNORE_OID, null, SYNTAX_DIRECTORY_STRING_OID, false, false,
+        false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.6", Arrays.asList("c", "countryName"),
+        EMPTY_STRING, false, "name", null, null, null, null,
+        SYNTAX_COUNTRY_STRING_OID, true, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.3", Arrays.asList("cn", "commonName"),
+        EMPTY_STRING, false, "name", null, null, null, null, null, false,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("0.9.2342.19200300.100.1.25", Arrays.asList("dc",
+        "domainComponent"), EMPTY_STRING, false, null, EMR_CASE_IGNORE_IA5_OID,
+        null, SMR_CASE_IGNORE_IA5_OID, null, SYNTAX_IA5_STRING_OID, true,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.13", Collections
+        .singletonList("description"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.27", Collections
+        .singletonList("destinationIndicator"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_PRINTABLE_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.49", Collections
+        .singletonList("distinguishedName"), EMPTY_STRING, false, null,
+        EMR_DN_OID, null, null, null, SYNTAX_DN_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.46", Collections
+        .singletonList("dnQualifier"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, OMR_CASE_IGNORE_OID, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_PRINTABLE_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.47", Collections
+        .singletonList("enhancedSearchGuide"), EMPTY_STRING, false, null, null,
+        null, null, null, SYNTAX_ENHANCED_GUIDE_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.23", Collections
+        .singletonList("facsimileTelephoneNumber"), EMPTY_STRING, false, null,
+        null, null, null, null, SYNTAX_FAXNUMBER_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.44", Collections
+        .singletonList("generationQualifier"), EMPTY_STRING, false, "name",
+        null, null, null, null, null, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.42",
+        Collections.singletonList("givenName"), EMPTY_STRING, false, "name",
+        null, null, null, null, null, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.51", Collections
+        .singletonList("houseIdentifier"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.43", Collections.singletonList("initials"),
+        EMPTY_STRING, false, "name", null, null, null, null, null, false,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.25", Collections
+        .singletonList("internationalISDNNumber"), EMPTY_STRING, false, null,
+        EMR_NUMERIC_STRING_OID, null, SMR_NUMERIC_STRING_OID, null,
+        SYNTAX_NUMERIC_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.7", Arrays.asList("l", "localityName"),
+        EMPTY_STRING, false, "name", null, null, null, null, null, false,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.31", Collections.singletonList("member"),
+        EMPTY_STRING, false, "distinguishedName", null, null, null, null, null,
+        false, false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN,
+        false);
+
+    builder.addAttributeType("2.5.4.10",
+        Arrays.asList("o", "organizationName"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.11", Arrays.asList("ou",
+        "organizationalUnitName"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.32", Collections.singletonList("owner"),
+        EMPTY_STRING, false, "distinguishedName", null, null, null, null, null,
+        false, false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN,
+        false);
+
+    builder.addAttributeType("2.5.4.19", Collections
+        .singletonList("physicalDeliveryOfficeName"), EMPTY_STRING, false,
+        null, EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.16", Collections
+        .singletonList("postalAddress"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.17", Collections
+        .singletonList("postalCode"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.18", Collections
+        .singletonList("postOfficeBox"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.28", Collections
+        .singletonList("preferredDeliveryMethod"), EMPTY_STRING, false, null,
+        null, null, null, null, SYNTAX_DELIVERY_METHOD_OID, true, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.26", Collections
+        .singletonList("registeredAddress"), EMPTY_STRING, false,
+        "postalAddress", null, null, null, null, SYNTAX_POSTAL_ADDRESS_OID,
+        false, false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN,
+        false);
+
+    builder.addAttributeType("2.5.4.33", Collections
+        .singletonList("roleOccupant"), EMPTY_STRING, false,
+        "distinguishedName", null, null, null, null, null, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.14", Collections
+        .singletonList("searchGuide"), EMPTY_STRING, false, null, null, null,
+        null, null, SYNTAX_GUIDE_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.34", Collections.singletonList("seeAlso"),
+        EMPTY_STRING, false, "distinguishedName", null, null, null, null, null,
+        false, false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN,
+        false);
+
+    builder.addAttributeType("2.5.4.5", Collections
+        .singletonList("serialNumber"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_PRINTABLE_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.4", Arrays.asList("sn", "surname"),
+        EMPTY_STRING, false, "name", null, null, null, null, null, false,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.8", Arrays.asList("st",
+        "stateOrProvinceName"), EMPTY_STRING, false, "name", null, null, null,
+        null, null, false, false, false, AttributeUsage.USER_APPLICATIONS,
+        RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.9", Arrays
+        .asList("street", "streetAddress"), EMPTY_STRING, false, null,
+        EMR_CASE_IGNORE_OID, null, SMR_CASE_IGNORE_OID, null,
+        SYNTAX_DIRECTORY_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.20", Collections
+        .singletonList("telephoneNumber"), EMPTY_STRING, false, null,
+        EMR_TELEPHONE_OID, null, SMR_TELEPHONE_OID, null, SYNTAX_TELEPHONE_OID,
+        false, false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN,
+        false);
+
+    builder.addAttributeType("2.5.4.22", Collections
+        .singletonList("teletexTerminalIdentifier"), EMPTY_STRING, false, null,
+        null, null, null, null, SYNTAX_TELETEX_TERM_ID_OID, false, false,
+        false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.21", Collections
+        .singletonList("telexNumber"), EMPTY_STRING, false, null, null, null,
+        null, null, SYNTAX_TELEX_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.12", Collections.singletonList("title"),
+        EMPTY_STRING, false, "name", null, null, null, null, null, false,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("0.9.2342.19200300.100.1.1", Arrays.asList("uid",
+        "userid"), EMPTY_STRING, false, null, EMR_CASE_IGNORE_OID, null,
+        SMR_CASE_IGNORE_OID, null, SYNTAX_DIRECTORY_STRING_OID, false, false,
+        false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.50", Collections
+        .singletonList("uniqueMember"), EMPTY_STRING, false, null,
+        EMR_UNIQUE_MEMBER_OID, null, null, null,
+        SYNTAX_NAME_AND_OPTIONAL_UID_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.35", Collections
+        .singletonList("userPassword"), EMPTY_STRING, false, null,
+        EMR_OCTET_STRING_OID, null, null, null, SYNTAX_OCTET_STRING_OID, false,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.24", Collections
+        .singletonList("x121Address"), EMPTY_STRING, false, null,
+        EMR_NUMERIC_STRING_OID, null, SMR_NUMERIC_STRING_OID, null,
+        SYNTAX_NUMERIC_STRING_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.45", Collections
+        .singletonList("x500UniqueIdentifier"), EMPTY_STRING, false, null,
+        EMR_BIT_STRING_OID, null, null, null, SYNTAX_BIT_STRING_OID, false,
+        false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false);
+
+    Set<String> attrs = new HashSet<String>();
+    attrs.add("seeAlso");
+    attrs.add("ou");
+    attrs.add("l");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.11", Collections
+        .singletonList("applicationProcess"), EMPTY_STRING, false, Collections
+        .singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("cn"), attrs,
+        ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("searchGuide");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.2", Collections.singletonList("country"),
+        EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME),
+        Collections.singleton("c"), attrs, ObjectClassType.STRUCTURAL,
+        RFC4519_ORIGIN, false);
+
+    builder.addObjectClass("1.3.6.1.4.1.1466.344", Collections
+        .singletonList("dcObject"), EMPTY_STRING, false, Collections
+        .singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("dc"),
+        EMPTY_STRING_SET, ObjectClassType.AUXILIARY, RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("serialNumber");
+    attrs.add("seeAlso");
+    attrs.add("owner");
+    attrs.add("ou");
+    attrs.add("o");
+    attrs.add("l");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.14", Collections.singletonList("device"),
+        EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME),
+        Collections.singleton("cn"), attrs, ObjectClassType.STRUCTURAL,
+        RFC4519_ORIGIN, false);
+
+    Set<String> must = new HashSet<String>();
+    must.add("member");
+    must.add("cn");
+
+    attrs = new HashSet<String>();
+    attrs.add("businessCategory");
+    attrs.add("seeAlso");
+    attrs.add("owner");
+    attrs.add("ou");
+    attrs.add("o");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.9",
+        Collections.singletonList("groupOfNames"), EMPTY_STRING, false,
+        Collections.singleton(TOP_OBJECTCLASS_NAME), must, attrs,
+        ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("businessCategory");
+    attrs.add("seeAlso");
+    attrs.add("owner");
+    attrs.add("ou");
+    attrs.add("o");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.17", Collections
+        .singletonList("groupOfUniqueNames"), EMPTY_STRING, false, Collections
+        .singleton(TOP_OBJECTCLASS_NAME), must, attrs,
+        ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("street");
+    attrs.add("seeAlso");
+    attrs.add("searchGuide");
+    attrs.add("st");
+    attrs.add("l");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.3", Collections.singletonList("locality"),
+        EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME),
+        EMPTY_STRING_SET, attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN,
+        false);
+
+    attrs = new HashSet<String>();
+    attrs.add("userPassword");
+    attrs.add("searchGuide");
+    attrs.add("seeAlso");
+    attrs.add("businessCategory");
+    attrs.add("x121Address");
+    attrs.add("registeredAddress");
+    attrs.add("destinationIndicator");
+    attrs.add("preferredDeliveryMethod");
+    attrs.add("telexNumber");
+    attrs.add("teletexTerminalIdentifier");
+    attrs.add("telephoneNumber");
+    attrs.add("internationalISDNNumber");
+    attrs.add("facsimileTelephoneNumber");
+    attrs.add("street");
+    attrs.add("postOfficeBox");
+    attrs.add("postalCode");
+    attrs.add("postalAddress");
+    attrs.add("physicalDeliveryOfficeName");
+    attrs.add("st");
+    attrs.add("l");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.4",
+        Collections.singletonList("organization"), EMPTY_STRING, false,
+        Collections.singleton(TOP_OBJECTCLASS_NAME),
+        Collections.singleton("o"), attrs, ObjectClassType.STRUCTURAL,
+        RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("title");
+    attrs.add("x121Address");
+    attrs.add("registeredAddress");
+    attrs.add("destinationIndicator");
+    attrs.add("preferredDeliveryMethod");
+    attrs.add("telexNumber");
+    attrs.add("teletexTerminalIdentifier");
+    attrs.add("telephoneNumber");
+    attrs.add("internationalISDNNumber");
+    attrs.add("facsimileTelephoneNumber");
+    attrs.add("street");
+    attrs.add("postOfficeBox");
+    attrs.add("postalCode");
+    attrs.add("postalAddress");
+    attrs.add("physicalDeliveryOfficeName");
+    attrs.add("ou");
+    attrs.add("st");
+    attrs.add("l");
+
+    builder.addObjectClass("2.5.6.7", Collections
+        .singletonList("organizationalPerson"), EMPTY_STRING, false,
+        Collections.singleton("person"), EMPTY_STRING_SET, attrs,
+        ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("x121Address");
+    attrs.add("registeredAddress");
+    attrs.add("destinationIndicator");
+    attrs.add("preferredDeliveryMethod");
+    attrs.add("telexNumber");
+    attrs.add("teletexTerminalIdentifier");
+    attrs.add("telephoneNumber");
+    attrs.add("internationalISDNNumber");
+    attrs.add("facsimileTelephoneNumber");
+    attrs.add("seeAlso");
+    attrs.add("roleOccupant");
+    attrs.add("preferredDeliveryMethod");
+    attrs.add("street");
+    attrs.add("postOfficeBox");
+    attrs.add("postalCode");
+    attrs.add("postalAddress");
+    attrs.add("physicalDeliveryOfficeName");
+    attrs.add("ou");
+    attrs.add("st");
+    attrs.add("l");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.8", Collections
+        .singletonList("organizationalRole"), EMPTY_STRING, false, Collections
+        .singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("cn"), attrs,
+        ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("businessCategory");
+    attrs.add("description");
+    attrs.add("destinationIndicator");
+    attrs.add("facsimileTelephoneNumber");
+    attrs.add("internationalISDNNumber");
+    attrs.add("l");
+    attrs.add("physicalDeliveryOfficeName");
+    attrs.add("postalAddress");
+    attrs.add("postalCode");
+    attrs.add("postOfficeBox");
+    attrs.add("preferredDeliveryMethod");
+    attrs.add("registeredAddress");
+    attrs.add("searchGuide");
+    attrs.add("seeAlso");
+    attrs.add("st");
+    attrs.add("street");
+    attrs.add("telephoneNumber");
+    attrs.add("teletexTerminalIdentifier");
+    attrs.add("telexNumber");
+    attrs.add("userPassword");
+    attrs.add("x121Address");
+
+    builder.addObjectClass("2.5.6.5", Collections
+        .singletonList("organizationalUnit"), EMPTY_STRING, false, Collections
+        .singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("ou"), attrs,
+        ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    must = new HashSet<String>();
+    must.add("sn");
+    must.add("cn");
+
+    attrs = new HashSet<String>();
+    attrs.add("userPassword");
+    attrs.add("telephoneNumber");
+    attrs.add("destinationIndicator");
+    attrs.add("seeAlso");
+    attrs.add("description");
+
+    builder.addObjectClass("2.5.6.6", Collections.singletonList("person"),
+        EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), must,
+        attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    attrs = new HashSet<String>();
+    attrs.add("businessCategory");
+    attrs.add("x121Address");
+    attrs.add("registeredAddress");
+    attrs.add("destinationIndicator");
+    attrs.add("preferredDeliveryMethod");
+    attrs.add("telexNumber");
+    attrs.add("teletexTerminalIdentifier");
+    attrs.add("telephoneNumber");
+    attrs.add("internationalISDNNumber");
+    attrs.add("facsimileTelephoneNumber");
+    attrs.add("preferredDeliveryMethod");
+    attrs.add("street");
+    attrs.add("postOfficeBox");
+    attrs.add("postalCode");
+    attrs.add("postalAddress");
+    attrs.add("physicalDeliveryOfficeName");
+    attrs.add("st");
+    attrs.add("l");
+
+    builder.addObjectClass("2.5.6.10", Collections
+        .singletonList("residentialPerson"), EMPTY_STRING, false, Collections
+        .singleton("person"), Collections.singleton("l"), attrs,
+        ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false);
+
+    builder.addObjectClass("1.3.6.1.1.3.1", Collections
+        .singletonList("uidObject"), EMPTY_STRING, false, Collections
+        .singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("uid"), attrs,
+        ObjectClassType.AUXILIARY, RFC4519_ORIGIN, false);
+  }
+
+
+
+  private static void addRFC4530(final SchemaBuilder builder)
+  {
+    builder.addSyntax(SYNTAX_UUID_OID, SYNTAX_UUID_DESCRIPTION, RFC4530_ORIGIN,
+        new UUIDSyntaxImpl(), false);
+    builder.addMatchingRule(EMR_UUID_OID, Collections
+        .singletonList(EMR_UUID_NAME), EMPTY_STRING, false, SYNTAX_UUID_OID,
+        RFC4530_ORIGIN, new UUIDEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(OMR_UUID_OID, Collections
+        .singletonList(OMR_UUID_NAME), EMPTY_STRING, false, SYNTAX_UUID_OID,
+        RFC4530_ORIGIN, new UUIDOrderingMatchingRuleImpl(), false);
+    builder.addAttributeType("1.3.6.1.1.16.4", Collections
+        .singletonList("entryUUID"), "UUID of the entry", false, null,
+        EMR_UUID_OID, OMR_UUID_OID, null, null, SYNTAX_UUID_OID, true, false,
+        true, AttributeUsage.DIRECTORY_OPERATION, RFC4530_ORIGIN, false);
+  }
+
+
+
+  private static void addSunProprietary(final SchemaBuilder builder)
+  {
+    builder.addSyntax(SYNTAX_USER_PASSWORD_OID,
+        SYNTAX_USER_PASSWORD_DESCRIPTION, OPENDS_ORIGIN,
+        new UserPasswordSyntaxImpl(), false);
+    builder.addMatchingRule(EMR_USER_PASSWORD_EXACT_OID, Collections
+        .singletonList(EMR_USER_PASSWORD_EXACT_NAME),
+        EMR_USER_PASSWORD_EXACT_DESCRIPTION, false, SYNTAX_USER_PASSWORD_OID,
+        OPENDS_ORIGIN, new UserPasswordExactEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(AMR_DOUBLE_METAPHONE_OID, Collections
+        .singletonList(AMR_DOUBLE_METAPHONE_NAME),
+        AMR_DOUBLE_METAPHONE_DESCRIPTION, false, SYNTAX_DIRECTORY_STRING_OID,
+        OPENDS_ORIGIN, new DoubleMetaphoneApproximateMatchingRuleImpl(), false);
+
+  }
+
+
+
+  private static void defaultAttributeTypes(final SchemaBuilder builder)
+  {
+    builder.addAttributeType("2.5.4.0", Collections
+        .singletonList("objectClass"), EMPTY_STRING, false, null, EMR_OID_NAME,
+        null, null, null, SYNTAX_OID_OID, false, false, false,
+        AttributeUsage.USER_APPLICATIONS, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.4.1", Collections
+        .singletonList("aliasedObjectName"), EMPTY_STRING, false, null,
+        EMR_DN_NAME, null, null, null, SYNTAX_DN_OID, true, false, false,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.18.1", Collections
+        .singletonList("createTimestamp"), EMPTY_STRING, false, null,
+        EMR_GENERALIZED_TIME_NAME, OMR_GENERALIZED_TIME_NAME, null, null,
+        SYNTAX_GENERALIZED_TIME_OID, true, false, true,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.18.2", Collections
+        .singletonList("modifyTimestamp"), EMPTY_STRING, false, null,
+        EMR_GENERALIZED_TIME_NAME, OMR_GENERALIZED_TIME_NAME, null, null,
+        SYNTAX_GENERALIZED_TIME_OID, true, false, true,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.18.3", Collections
+        .singletonList("creatorsName"), EMPTY_STRING, false, null, EMR_DN_NAME,
+        null, null, null, SYNTAX_DN_OID, true, false, true,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.18.4", Collections
+        .singletonList("modifiersName"), EMPTY_STRING, false, null,
+        EMR_DN_NAME, null, null, null, SYNTAX_DN_OID, true, false, true,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.18.10", Collections
+        .singletonList("subschemaSubentry"), EMPTY_STRING, false, null,
+        EMR_DN_NAME, null, null, null, SYNTAX_DN_OID, true, false, true,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.5", Collections
+        .singletonList("attributeTypes"), EMPTY_STRING, false, null,
+        EMR_OID_FIRST_COMPONENT_NAME, null, null, null,
+        SYNTAX_ATTRIBUTE_TYPE_OID, false, false, false,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.6", Collections
+        .singletonList("objectClasses"), EMPTY_STRING, false, null,
+        EMR_OID_FIRST_COMPONENT_NAME, null, null, null, SYNTAX_OBJECTCLASS_OID,
+        false, false, false, AttributeUsage.DIRECTORY_OPERATION,
+        RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.4", Collections
+        .singletonList("matchingRules"), EMPTY_STRING, false, null,
+        EMR_OID_FIRST_COMPONENT_NAME, null, null, null,
+        SYNTAX_MATCHING_RULE_OID, false, false, false,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.8", Collections
+        .singletonList("matchingRuleUse"), EMPTY_STRING, false, null,
+        EMR_OID_FIRST_COMPONENT_NAME, null, null, null,
+        SYNTAX_MATCHING_RULE_USE_OID, false, false, false,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.9", Collections
+        .singletonList("structuralObjectClass"), EMPTY_STRING, false, null,
+        EMR_OID_NAME, null, null, null, SYNTAX_OID_OID, true, false, true,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.10", Collections
+        .singletonList("governingStructureRule"), EMPTY_STRING, false, null,
+        EMR_INTEGER_NAME, null, null, null, SYNTAX_INTEGER_OID, true, false,
+        true, AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.1466.101.120.5", Collections
+        .singletonList("namingContexts"), EMPTY_STRING, false, null, null,
+        null, null, null, SYNTAX_DN_OID, false, false, false,
+        AttributeUsage.DSA_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.1466.101.120.6", Collections
+        .singletonList("altServer"), EMPTY_STRING, false, null, null, null,
+        null, null, SYNTAX_IA5_STRING_OID, false, false, false,
+        AttributeUsage.DSA_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.1466.101.120.7", Collections
+        .singletonList("supportedExtension"), EMPTY_STRING, false, null, null,
+        null, null, null, SYNTAX_OID_OID, false, false, false,
+        AttributeUsage.DSA_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.1466.101.120.13", Collections
+        .singletonList("supportedControl"), EMPTY_STRING, false, null, null,
+        null, null, null, SYNTAX_OID_OID, false, false, false,
+        AttributeUsage.DSA_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.1466.101.120.14", Collections
+        .singletonList("supportedSASLMechanisms"), EMPTY_STRING, false, null,
+        null, null, null, null, SYNTAX_DIRECTORY_STRING_OID, false, false,
+        false, AttributeUsage.DSA_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.4203.1.3.5", Collections
+        .singletonList("supportedFeatures"), EMPTY_STRING, false, null,
+        EMR_OID_NAME, null, null, null, SYNTAX_OID_OID, false, false, false,
+        AttributeUsage.DSA_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.1466.101.120.15", Collections
+        .singletonList("supportedLDAPVersion"), EMPTY_STRING, false, null,
+        null, null, null, null, SYNTAX_INTEGER_OID, false, false, false,
+        AttributeUsage.DSA_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("1.3.6.1.4.1.1466.101.120.16", Collections
+        .singletonList("ldapSyntaxes"), EMPTY_STRING, false, null,
+        EMR_OID_FIRST_COMPONENT_NAME, null, null, null, SYNTAX_LDAP_SYNTAX_OID,
+        false, false, false, AttributeUsage.DIRECTORY_OPERATION,
+        RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.1", Collections
+        .singletonList("ditStructureRules"), EMPTY_STRING, false, null,
+        EMR_INTEGER_FIRST_COMPONENT_NAME, null, null, null,
+        SYNTAX_DIT_STRUCTURE_RULE_OID, false, false, false,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.7",
+        Collections.singletonList("nameForms"), EMPTY_STRING, false, null,
+        EMR_OID_FIRST_COMPONENT_NAME, null, null, null, SYNTAX_NAME_FORM_OID,
+        false, false, false, AttributeUsage.DIRECTORY_OPERATION,
+        RFC4512_ORIGIN, false);
+
+    builder.addAttributeType("2.5.21.2", Collections
+        .singletonList("ditContentRules"), EMPTY_STRING, false, null,
+        EMR_OID_FIRST_COMPONENT_NAME, null, null, null,
+        SYNTAX_DIT_CONTENT_RULE_OID, false, false, false,
+        AttributeUsage.DIRECTORY_OPERATION, RFC4512_ORIGIN, false);
+  }
+
+
+
+  private static void defaultMatchingRules(final SchemaBuilder builder)
+  {
+    builder.addMatchingRule(EMR_BIT_STRING_OID, Collections
+        .singletonList(EMR_BIT_STRING_NAME), EMPTY_STRING, false,
+        SYNTAX_BIT_STRING_OID, RFC4512_ORIGIN,
+        new BitStringEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_BOOLEAN_OID, Collections
+        .singletonList(EMR_BOOLEAN_NAME), EMPTY_STRING, false,
+        SYNTAX_BOOLEAN_OID, RFC4512_ORIGIN,
+        new BooleanEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_CASE_EXACT_IA5_OID, Collections
+        .singletonList(EMR_CASE_EXACT_IA5_NAME), EMPTY_STRING, false,
+        SYNTAX_IA5_STRING_OID, RFC4512_ORIGIN,
+        new CaseExactIA5EqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(SMR_CASE_EXACT_IA5_OID, Collections
+        .singletonList(SMR_CASE_EXACT_IA5_NAME), EMPTY_STRING, false,
+        SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
+        new CaseExactIA5SubstringMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_CASE_EXACT_OID, Collections
+        .singletonList(EMR_CASE_EXACT_NAME), EMPTY_STRING, false,
+        SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
+        new CaseExactEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(OMR_CASE_EXACT_OID, Collections
+        .singletonList(OMR_CASE_EXACT_NAME), EMPTY_STRING, false,
+        SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
+        new CaseExactOrderingMatchingRuleImpl(), false);
+    builder.addMatchingRule(SMR_CASE_EXACT_OID, Collections
+        .singletonList(SMR_CASE_EXACT_NAME), EMPTY_STRING, false,
+        SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
+        new CaseExactSubstringMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_CASE_IGNORE_IA5_OID, Collections
+        .singletonList(EMR_CASE_IGNORE_IA5_NAME), EMPTY_STRING, false,
+        SYNTAX_IA5_STRING_OID, RFC4512_ORIGIN,
+        new CaseIgnoreIA5EqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(SMR_CASE_IGNORE_IA5_OID, Collections
+        .singletonList(SMR_CASE_IGNORE_IA5_NAME), EMPTY_STRING, false,
+        SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
+        new CaseIgnoreIA5SubstringMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_CASE_IGNORE_LIST_OID, Collections
+        .singletonList(EMR_CASE_IGNORE_LIST_NAME), EMPTY_STRING, false,
+        SYNTAX_POSTAL_ADDRESS_OID, RFC4512_ORIGIN,
+        new CaseIgnoreListEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(SMR_CASE_IGNORE_LIST_OID, Collections
+        .singletonList(SMR_CASE_IGNORE_LIST_NAME), EMPTY_STRING, false,
+        SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
+        new CaseIgnoreListSubstringMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_CASE_IGNORE_OID, Collections
+        .singletonList(EMR_CASE_IGNORE_NAME), EMPTY_STRING, false,
+        SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
+        new CaseIgnoreEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(OMR_CASE_IGNORE_OID, Collections
+        .singletonList(OMR_CASE_IGNORE_NAME), EMPTY_STRING, false,
+        SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
+        new CaseIgnoreOrderingMatchingRuleImpl(), false);
+    builder.addMatchingRule(SMR_CASE_IGNORE_OID, Collections
+        .singletonList(SMR_CASE_IGNORE_NAME), EMPTY_STRING, false,
+        SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
+        new CaseIgnoreSubstringMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_DIRECTORY_STRING_FIRST_COMPONENT_OID,
+        Collections.singletonList(EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME),
+        EMPTY_STRING, false, SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
+        new DirectoryStringFirstComponentEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_DN_OID, Collections.singletonList(EMR_DN_NAME),
+        EMPTY_STRING, false, SYNTAX_DN_OID, RFC4512_ORIGIN,
+        new DistinguishedNameEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_GENERALIZED_TIME_OID, Collections
+        .singletonList(EMR_GENERALIZED_TIME_NAME), EMPTY_STRING, false,
+        SYNTAX_GENERALIZED_TIME_OID, RFC4512_ORIGIN,
+        new GeneralizedTimeEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(OMR_GENERALIZED_TIME_OID, Collections
+        .singletonList(OMR_GENERALIZED_TIME_NAME), EMPTY_STRING, false,
+        SYNTAX_GENERALIZED_TIME_OID, RFC4512_ORIGIN,
+        new GeneralizedTimeOrderingMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_INTEGER_FIRST_COMPONENT_OID, Collections
+        .singletonList(EMR_INTEGER_FIRST_COMPONENT_NAME), EMPTY_STRING, false,
+        SYNTAX_INTEGER_OID, RFC4512_ORIGIN,
+        new IntegerFirstComponentEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_INTEGER_OID, Collections
+        .singletonList(EMR_INTEGER_NAME), EMPTY_STRING, false,
+        SYNTAX_INTEGER_OID, RFC4512_ORIGIN,
+        new IntegerEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(OMR_INTEGER_OID, Collections
+        .singletonList(OMR_INTEGER_NAME), EMPTY_STRING, false,
+        SYNTAX_INTEGER_OID, RFC4512_ORIGIN,
+        new IntegerOrderingMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_KEYWORD_OID, Collections
+        .singletonList(EMR_KEYWORD_NAME), EMPTY_STRING, false,
+        SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
+        new KeywordEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_NUMERIC_STRING_OID, Collections
+        .singletonList(EMR_NUMERIC_STRING_NAME), EMPTY_STRING, false,
+        SYNTAX_NUMERIC_STRING_OID, RFC4512_ORIGIN,
+        new NumericStringEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(OMR_NUMERIC_STRING_OID, Collections
+        .singletonList(OMR_NUMERIC_STRING_NAME), EMPTY_STRING, false,
+        SYNTAX_NUMERIC_STRING_OID, RFC4512_ORIGIN,
+        new NumericStringOrderingMatchingRuleImpl(), false);
+    builder.addMatchingRule(SMR_NUMERIC_STRING_OID, Collections
+        .singletonList(SMR_NUMERIC_STRING_NAME), EMPTY_STRING, false,
+        SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
+        new NumericStringSubstringMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_OID_FIRST_COMPONENT_OID, Collections
+        .singletonList(EMR_OID_FIRST_COMPONENT_NAME), EMPTY_STRING, false,
+        SYNTAX_OID_OID, RFC4512_ORIGIN,
+        new ObjectIdentifierFirstComponentEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_OID_OID, Collections
+        .singletonList(EMR_OID_NAME), EMPTY_STRING, false, SYNTAX_OID_OID,
+        RFC4512_ORIGIN, new ObjectIdentifierEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_OCTET_STRING_OID, Collections
+        .singletonList(EMR_OCTET_STRING_NAME), EMPTY_STRING, false,
+        SYNTAX_OCTET_STRING_OID, RFC4512_ORIGIN,
+        new OctetStringEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(OMR_OCTET_STRING_OID, Collections
+        .singletonList(OMR_OCTET_STRING_NAME), EMPTY_STRING, false,
+        SYNTAX_OCTET_STRING_OID, RFC4512_ORIGIN,
+        new OctetStringOrderingMatchingRuleImpl(), false);
+    // SMR octet string is not in any LDAP RFC and its from X.500
+    builder.addMatchingRule(SMR_OCTET_STRING_OID, Collections
+        .singletonList(SMR_OCTET_STRING_NAME), EMPTY_STRING, false,
+        SYNTAX_OCTET_STRING_OID, X500_ORIGIN,
+        new OctetStringSubstringMatchingRuleImpl(), false);
+    // Depreciated in RFC 4512
+    builder.addMatchingRule(EMR_PROTOCOL_INFORMATION_OID, Collections
+        .singletonList(EMR_PROTOCOL_INFORMATION_NAME), EMPTY_STRING, false,
+        SYNTAX_PROTOCOL_INFORMATION_OID, RFC2252_ORIGIN,
+        new ProtocolInformationEqualityMatchingRuleImpl(), false);
+    // Depreciated in RFC 4512
+    builder.addMatchingRule(EMR_PRESENTATION_ADDRESS_OID, Collections
+        .singletonList(EMR_PRESENTATION_ADDRESS_NAME), EMPTY_STRING, false,
+        SYNTAX_PRESENTATION_ADDRESS_OID, RFC2252_ORIGIN,
+        new PresentationAddressEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_TELEPHONE_OID, Collections
+        .singletonList(EMR_TELEPHONE_NAME), EMPTY_STRING, false,
+        SYNTAX_TELEPHONE_OID, RFC4512_ORIGIN,
+        new TelephoneNumberEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(SMR_TELEPHONE_OID, Collections
+        .singletonList(SMR_TELEPHONE_NAME), EMPTY_STRING, false,
+        SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
+        new TelephoneNumberSubstringMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_UNIQUE_MEMBER_OID, Collections
+        .singletonList(EMR_UNIQUE_MEMBER_NAME), EMPTY_STRING, false,
+        SYNTAX_NAME_AND_OPTIONAL_UID_OID, RFC4512_ORIGIN,
+        new UniqueMemberEqualityMatchingRuleImpl(), false);
+    builder.addMatchingRule(EMR_WORD_OID, Collections
+        .singletonList(EMR_WORD_NAME), EMPTY_STRING, false,
+        SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
+        new WordEqualityMatchingRuleImpl(), false);
+  }
+
+
+
+  private static void defaultObjectClasses(final SchemaBuilder builder)
+  {
+    builder.addObjectClass(TOP_OBJECTCLASS_OID, Collections
+        .singletonList(TOP_OBJECTCLASS_NAME), TOP_OBJECTCLASS_DESCRIPTION,
+        false, EMPTY_STRING_SET, Collections.singleton("objectClass"),
+        EMPTY_STRING_SET, ObjectClassType.ABSTRACT, RFC4512_ORIGIN, false);
+
+    builder.addObjectClass("2.5.6.1", Collections.singletonList("alias"),
+        EMPTY_STRING, false, Collections.singleton("top"), Collections
+            .singleton("aliasedObjectName"), EMPTY_STRING_SET,
+        ObjectClassType.STRUCTURAL, RFC4512_ORIGIN, false);
+
+    builder.addObjectClass(EXTENSIBLE_OBJECT_OBJECTCLASS_OID, Collections
+        .singletonList(EXTENSIBLE_OBJECT_OBJECTCLASS_NAME), EMPTY_STRING,
+        false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET,
+        EMPTY_STRING_SET, ObjectClassType.AUXILIARY, RFC4512_ORIGIN, false);
+
+    final Set<String> subschemaAttrs = new HashSet<String>();
+    subschemaAttrs.add("dITStructureRules");
+    subschemaAttrs.add("nameForms");
+    subschemaAttrs.add("ditContentRules");
+    subschemaAttrs.add("objectClasses");
+    subschemaAttrs.add("attributeTypes");
+    subschemaAttrs.add("matchingRules");
+    subschemaAttrs.add("matchingRuleUse");
+
+    builder.addObjectClass("2.5.20.1", Collections.singletonList("subschema"),
+        EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME),
+        EMPTY_STRING_SET, subschemaAttrs, ObjectClassType.AUXILIARY,
+        RFC4512_ORIGIN, false);
+  }
+
+
+
+  private static void defaultSyntaxes(final SchemaBuilder builder)
+  {
+    // All RFC 4512 / 4517
+    builder.addSyntax(SYNTAX_ATTRIBUTE_TYPE_OID,
+        SYNTAX_ATTRIBUTE_TYPE_DESCRIPTION, RFC4512_ORIGIN,
+        new AttributeTypeSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_BINARY_OID, SYNTAX_BINARY_DESCRIPTION,
+        RFC4512_ORIGIN, new BinarySyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_BIT_STRING_OID, SYNTAX_BIT_STRING_DESCRIPTION,
+        RFC4512_ORIGIN, new BitStringSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_BOOLEAN_OID, SYNTAX_BOOLEAN_DESCRIPTION,
+        RFC4512_ORIGIN, new BooleanSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_CERTLIST_OID, SYNTAX_CERTLIST_DESCRIPTION,
+        RFC4512_ORIGIN, new CertificateListSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_CERTPAIR_OID, SYNTAX_CERTPAIR_DESCRIPTION,
+        RFC4512_ORIGIN, new CertificatePairSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_CERTIFICATE_OID, SYNTAX_CERTIFICATE_DESCRIPTION,
+        RFC4512_ORIGIN, new CertificateSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_COUNTRY_STRING_OID,
+        SYNTAX_COUNTRY_STRING_DESCRIPTION, RFC4512_ORIGIN,
+        new CountryStringSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_DELIVERY_METHOD_OID,
+        SYNTAX_DELIVERY_METHOD_DESCRIPTION, RFC4512_ORIGIN,
+        new DeliveryMethodSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_DIRECTORY_STRING_OID,
+        SYNTAX_DIRECTORY_STRING_DESCRIPTION, RFC4512_ORIGIN,
+        new DirectoryStringSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_DIT_CONTENT_RULE_OID,
+        SYNTAX_DIT_CONTENT_RULE_DESCRIPTION, RFC4512_ORIGIN,
+        new DITContentRuleSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_DIT_STRUCTURE_RULE_OID,
+        SYNTAX_DIT_STRUCTURE_RULE_DESCRIPTION, RFC4512_ORIGIN,
+        new DITStructureRuleSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_DN_OID, SYNTAX_DN_DESCRIPTION, RFC4512_ORIGIN,
+        new DistinguishedNameSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_ENHANCED_GUIDE_OID,
+        SYNTAX_ENHANCED_GUIDE_DESCRIPTION, RFC4512_ORIGIN,
+        new EnhancedGuideSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_FAXNUMBER_OID, SYNTAX_FAXNUMBER_DESCRIPTION,
+        RFC4512_ORIGIN, new FacsimileNumberSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_FAX_OID, SYNTAX_FAX_DESCRIPTION, RFC4512_ORIGIN,
+        new FaxSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_GENERALIZED_TIME_OID,
+        SYNTAX_GENERALIZED_TIME_DESCRIPTION, RFC4512_ORIGIN,
+        new GeneralizedTimeSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_GUIDE_OID, SYNTAX_GUIDE_DESCRIPTION,
+        RFC4512_ORIGIN, new GuideSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_IA5_STRING_OID, SYNTAX_IA5_STRING_DESCRIPTION,
+        RFC4512_ORIGIN, new IA5StringSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_INTEGER_OID, SYNTAX_INTEGER_DESCRIPTION,
+        RFC4512_ORIGIN, new IntegerSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_JPEG_OID, SYNTAX_JPEG_DESCRIPTION, RFC4512_ORIGIN,
+        new JPEGSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_MATCHING_RULE_OID,
+        SYNTAX_MATCHING_RULE_DESCRIPTION, RFC4512_ORIGIN,
+        new MatchingRuleSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_MATCHING_RULE_USE_OID,
+        SYNTAX_MATCHING_RULE_USE_DESCRIPTION, RFC4512_ORIGIN,
+        new MatchingRuleUseSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_LDAP_SYNTAX_OID, SYNTAX_LDAP_SYNTAX_DESCRIPTION,
+        RFC4512_ORIGIN, new LDAPSyntaxDescriptionSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_NAME_AND_OPTIONAL_UID_OID,
+        SYNTAX_NAME_AND_OPTIONAL_UID_DESCRIPTION, RFC4517_ORIGIN,
+        new NameAndOptionalUIDSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_NAME_FORM_OID, SYNTAX_NAME_FORM_DESCRIPTION,
+        RFC4512_ORIGIN, new NameFormSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_NUMERIC_STRING_OID,
+        SYNTAX_NUMERIC_STRING_DESCRIPTION, RFC4512_ORIGIN,
+        new NumericStringSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_OBJECTCLASS_OID, SYNTAX_OBJECTCLASS_DESCRIPTION,
+        RFC4512_ORIGIN, new ObjectClassSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_OCTET_STRING_OID, SYNTAX_OCTET_STRING_DESCRIPTION,
+        RFC4512_ORIGIN, new OctetStringSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_OID_OID, SYNTAX_OID_DESCRIPTION, RFC4512_ORIGIN,
+        new OIDSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_OTHER_MAILBOX_OID,
+        SYNTAX_OTHER_MAILBOX_DESCRIPTION, RFC4512_ORIGIN,
+        new OtherMailboxSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_POSTAL_ADDRESS_OID,
+        SYNTAX_POSTAL_ADDRESS_DESCRIPTION, RFC4512_ORIGIN,
+        new PostalAddressSyntaxImpl(), false);
+    // Depreciated in RFC 4512
+    builder.addSyntax(SYNTAX_PRESENTATION_ADDRESS_OID,
+        SYNTAX_PRESENTATION_ADDRESS_DESCRIPTION, RFC2252_ORIGIN,
+        new PresentationAddressSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_PRINTABLE_STRING_OID,
+        SYNTAX_PRINTABLE_STRING_DESCRIPTION, RFC4512_ORIGIN,
+        new PrintableStringSyntaxImpl(), false);
+    // Depreciated in RFC 4512
+    builder.addSyntax(SYNTAX_PROTOCOL_INFORMATION_OID,
+        SYNTAX_PROTOCOL_INFORMATION_DESCRIPTION, RFC2252_ORIGIN,
+        new ProtocolInformationSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_SUBSTRING_ASSERTION_OID,
+        SYNTAX_SUBSTRING_ASSERTION_DESCRIPTION, RFC4512_ORIGIN,
+        new SubstringAssertionSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_SUPPORTED_ALGORITHM_OID,
+        SYNTAX_SUPPORTED_ALGORITHM_DESCRIPTION, RFC4512_ORIGIN,
+        new SupportedAlgorithmSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_TELEPHONE_OID, SYNTAX_TELEPHONE_DESCRIPTION,
+        RFC4512_ORIGIN, new TelephoneNumberSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_TELETEX_TERM_ID_OID,
+        SYNTAX_TELETEX_TERM_ID_DESCRIPTION, RFC4512_ORIGIN,
+        new TeletexTerminalIdentifierSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_TELEX_OID, SYNTAX_TELEX_DESCRIPTION,
+        RFC4512_ORIGIN, new TelexNumberSyntaxImpl(), false);
+    builder.addSyntax(SYNTAX_UTC_TIME_OID, SYNTAX_UTC_TIME_DESCRIPTION,
+        RFC4512_ORIGIN, new UTCTimeSyntaxImpl(), false);
+  }
+
+
+
+  private CoreSchemaImpl()
+  {
+    // Prevent instantiation.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CountryStringSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CountryStringSyntaxImpl.java
new file mode 100644
index 0000000..a8969a1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/CountryStringSyntaxImpl.java
@@ -0,0 +1,133 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the country string attribute syntax, which should be a
+ * two-character ISO 3166 country code. However, for maintainability, it will
+ * accept any value consisting entirely of two printable characters. In most
+ * ways, it will behave like the directory string attribute syntax.
+ */
+final class CountryStringSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_COUNTRY_STRING_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String stringValue = toLowerCase(value.toString());
+    if (stringValue.length() != 2)
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH
+          .get(stringValue));
+      return false;
+    }
+
+    if (!PrintableStringSyntaxImpl.isPrintableCharacter(stringValue.charAt(0))
+        || !PrintableStringSyntaxImpl.isPrintableCharacter(stringValue
+            .charAt(1)))
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE
+          .get(stringValue));
+      return false;
+    }
+
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRule.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRule.java
new file mode 100644
index 0000000..5949956
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRule.java
@@ -0,0 +1,616 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.*;
+
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a DIT content rule, which defines the set of allowed,
+ * required, and prohibited attributes for entries with a given structural
+ * objectclass, and also indicates which auxiliary classes that may be included
+ * in the entry.
+ */
+public final class DITContentRule extends SchemaElement
+{
+  // The structural objectclass for this DIT content rule.
+  private final String structuralClassOID;
+
+  // The set of user defined names for this definition.
+  private final List<String> names;
+
+  // Indicates whether this definition is declared "obsolete".
+  private final boolean isObsolete;
+
+  // The set of auxiliary objectclasses that entries with this content
+  // rule may contain, in a mapping between the objectclass and the
+  // user-defined name for that class.
+  private final Set<String> auxiliaryClassOIDs;
+
+  // The set of optional attribute types for this DIT content rule.
+  private final Set<String> optionalAttributeOIDs;
+
+  // The set of prohibited attribute types for this DIT content rule.
+  private final Set<String> prohibitedAttributeOIDs;
+
+  // The set of required attribute types for this DIT content rule.
+  private final Set<String> requiredAttributeOIDs;
+
+  // The definition string used to create this objectclass.
+  private final String definition;
+
+  private ObjectClass structuralClass;
+  private Set<ObjectClass> auxiliaryClasses = Collections.emptySet();
+  private Set<AttributeType> optionalAttributes = Collections.emptySet();
+  private Set<AttributeType> prohibitedAttributes = Collections.emptySet();
+  private Set<AttributeType> requiredAttributes = Collections.emptySet();
+
+
+
+  DITContentRule(final String structuralClassOID, final List<String> names,
+      final String description, final boolean obsolete,
+      final Set<String> auxiliaryClassOIDs,
+      final Set<String> optionalAttributeOIDs,
+      final Set<String> prohibitedAttributeOIDs,
+      final Set<String> requiredAttributeOIDs,
+      final Map<String, List<String>> extraProperties, final String definition)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(structuralClassOID, names);
+    Validator.ensureNotNull(auxiliaryClassOIDs, optionalAttributeOIDs,
+        prohibitedAttributeOIDs, requiredAttributeOIDs);
+    this.names = names;
+    this.isObsolete = obsolete;
+    this.structuralClassOID = structuralClassOID;
+    this.auxiliaryClassOIDs = auxiliaryClassOIDs;
+    this.optionalAttributeOIDs = optionalAttributeOIDs;
+    this.prohibitedAttributeOIDs = prohibitedAttributeOIDs;
+    this.requiredAttributeOIDs = requiredAttributeOIDs;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the auxiliary objectclasses that may
+   * be used for entries associated with this DIT content rule.
+   *
+   * @return An unmodifiable set containing the auxiliary objectclasses that may
+   *         be used for entries associated with this DIT content rule.
+   */
+  public Set<ObjectClass> getAuxiliaryClasses()
+  {
+    return auxiliaryClasses;
+  }
+
+
+
+  /**
+   * Returns the name or structural class OID for this schema definition. If it
+   * has one or more names, then the primary name will be returned. If it does
+   * not have any names, then the OID will be returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public String getNameOrOID()
+  {
+    if (names.isEmpty())
+    {
+      return structuralClassOID;
+    }
+    return names.get(0);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the user-defined names that may be
+   * used to reference this schema definition.
+   *
+   * @return Returns an unmodifiable list containing the user-defined names that
+   *         may be used to reference this schema definition.
+   */
+  public List<String> getNames()
+  {
+    return names;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the optional attributes for this DIT
+   * content rule.
+   *
+   * @return An unmodifiable set containing the optional attributes for this DIT
+   *         content rule.
+   */
+  public Set<AttributeType> getOptionalAttributes()
+  {
+    return optionalAttributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the prohibited attributes for this
+   * DIT content rule.
+   *
+   * @return An unmodifiable set containing the prohibited attributes for this
+   *         DIT content rule.
+   */
+  public Set<AttributeType> getProhibitedAttributes()
+  {
+    return prohibitedAttributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the required attributes for this DIT
+   * content rule.
+   *
+   * @return An unmodifiable set containing the required attributes for this DIT
+   *         content rule.
+   */
+  public Set<AttributeType> getRequiredAttributes()
+  {
+    return requiredAttributes;
+  }
+
+
+
+  /**
+   * Returns the structural objectclass for this DIT content rule.
+   *
+   * @return The structural objectclass for this DIT content rule.
+   */
+  public ObjectClass getStructuralClass()
+  {
+    return structuralClass;
+  }
+
+
+
+  /**
+   * Returns the structural class OID for this schema definition.
+   *
+   * @return The structural class OID for this schema definition.
+   */
+  public String getStructuralClassOID()
+  {
+    return structuralClassOID;
+  }
+
+
+
+  @Override
+  public int hashCode()
+  {
+    return structuralClassOID.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name.
+   *
+   * @param name
+   *          The name for which to make the determination.
+   * @return <code>true</code> if the specified name is assigned to this schema
+   *         definition, or <code>false</code> if not.
+   */
+  public boolean hasName(final String name)
+  {
+    for (final String n : names)
+    {
+      if (n.equalsIgnoreCase(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name or
+   * structural class OID.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return <code>true</code> if the provided value matches the OID or one of
+   *         the names assigned to this schema definition, or <code>false</code>
+   *         if not.
+   */
+  public boolean hasNameOrOID(final String value)
+  {
+    return hasName(value) || structuralClassOID.equals(value);
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition is declared "obsolete".
+   *
+   * @return <code>true</code> if this schema definition is declared "obsolete",
+   *         or <code>false</code> if not.
+   */
+  public boolean isObsolete()
+  {
+    return isObsolete;
+  }
+
+
+
+  /**
+   * Returns the string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  DITContentRule duplicate()
+  {
+    return new DITContentRule(structuralClassOID, names, description,
+        isObsolete, auxiliaryClassOIDs, optionalAttributeOIDs,
+        prohibitedAttributeOIDs, requiredAttributeOIDs, extraProperties,
+        definition);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(structuralClassOID);
+
+    if (!names.isEmpty())
+    {
+      final Iterator<String> iterator = names.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NAME ( '");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append("' '");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append("' )");
+      }
+      else
+      {
+        buffer.append(" NAME '");
+        buffer.append(firstName);
+        buffer.append("'");
+      }
+    }
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+
+    if (isObsolete)
+    {
+      buffer.append(" OBSOLETE");
+    }
+
+    if (!auxiliaryClassOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = auxiliaryClassOIDs.iterator();
+
+      final String firstClass = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" AUX (");
+        buffer.append(firstClass);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" AUX ");
+        buffer.append(firstClass);
+      }
+    }
+
+    if (!requiredAttributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = requiredAttributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" MUST ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" MUST ");
+        buffer.append(firstName);
+      }
+    }
+
+    if (!optionalAttributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = optionalAttributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" MAY ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" MAY ");
+        buffer.append(firstName);
+      }
+    }
+
+    if (!prohibitedAttributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = prohibitedAttributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NOT ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" NOT ");
+        buffer.append(firstName);
+      }
+    }
+  }
+
+
+
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    // Get the objectclass with the specified OID. If it does not exist
+    // or is not structural, then fail.
+    if (structuralClassOID != null)
+    {
+      try
+      {
+        structuralClass = schema.getObjectClass(structuralClassOID);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS
+            .get(definition, structuralClassOID);
+        throw new SchemaException(message, e);
+      }
+      if (structuralClass.getObjectClassType() != ObjectClassType.STRUCTURAL)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL
+            .get(definition, structuralClass.getOID(), structuralClass
+                .getNameOrOID(), structuralClass.getObjectClassType()
+                .toString());
+        warnings.add(message);
+      }
+    }
+
+    if (!auxiliaryClassOIDs.isEmpty())
+    {
+      auxiliaryClasses = new HashSet<ObjectClass>(auxiliaryClassOIDs.size());
+      ObjectClass objectClass;
+      for (final String oid : auxiliaryClassOIDs)
+      {
+        try
+        {
+          objectClass = schema.getObjectClass(oid);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          // This isn't good because it is an unknown auxiliary class.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS
+              .get(definition, oid);
+          throw new SchemaException(message, e);
+        }
+        if (objectClass.getObjectClassType() != ObjectClassType.AUXILIARY)
+        {
+          // This isn't good because it isn't an auxiliary class.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY
+              .get(definition, structuralClass.getOID(), structuralClass
+                  .getObjectClassType().toString());
+          throw new SchemaException(message);
+        }
+        auxiliaryClasses.add(objectClass);
+      }
+    }
+
+    if (!requiredAttributeOIDs.isEmpty())
+    {
+      requiredAttributes = new HashSet<AttributeType>(requiredAttributeOIDs
+          .size());
+      AttributeType attributeType;
+      for (final String oid : requiredAttributeOIDs)
+      {
+        try
+        {
+          attributeType = schema.getAttributeType(oid);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          // This isn't good because it means that the DIT content rule
+          // requires an attribute type that we don't know anything
+          // about.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR
+              .get(definition, oid);
+          throw new SchemaException(message, e);
+        }
+        requiredAttributes.add(attributeType);
+      }
+    }
+
+    if (!optionalAttributeOIDs.isEmpty())
+    {
+      optionalAttributes = new HashSet<AttributeType>(optionalAttributeOIDs
+          .size());
+      AttributeType attributeType;
+      for (final String oid : optionalAttributeOIDs)
+      {
+        try
+        {
+          attributeType = schema.getAttributeType(oid);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          // This isn't good because it means that the DIT content rule
+          // requires an attribute type that we don't know anything
+          // about.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR
+              .get(definition, oid);
+          throw new SchemaException(message, e);
+        }
+        optionalAttributes.add(attributeType);
+      }
+    }
+
+    if (!prohibitedAttributeOIDs.isEmpty())
+    {
+      prohibitedAttributes = new HashSet<AttributeType>(prohibitedAttributeOIDs
+          .size());
+      AttributeType attributeType;
+      for (final String oid : prohibitedAttributeOIDs)
+      {
+        try
+        {
+          attributeType = schema.getAttributeType(oid);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          // This isn't good because it means that the DIT content rule
+          // requires an attribute type that we don't know anything
+          // about.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR
+              .get(definition, oid);
+          throw new SchemaException(message, e);
+        }
+        prohibitedAttributes.add(attributeType);
+      }
+    }
+
+    // Make sure that none of the prohibited attributes is required by
+    // the structural or any of the auxiliary classes.
+    for (final AttributeType t : prohibitedAttributes)
+    {
+      if (structuralClass.isRequired(t))
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL
+            .get(definition, t.getNameOrOID(), structuralClass.getNameOrOID());
+        throw new SchemaException(message);
+      }
+
+      for (final ObjectClass oc : auxiliaryClasses)
+      {
+        if (oc.isRequired(t))
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY
+              .get(definition, t.getNameOrOID(), oc.getNameOrOID());
+          throw new SchemaException(message);
+        }
+      }
+    }
+
+    auxiliaryClasses = Collections.unmodifiableSet(auxiliaryClasses);
+    optionalAttributes = Collections.unmodifiableSet(optionalAttributes);
+    prohibitedAttributes = Collections.unmodifiableSet(prohibitedAttributes);
+    requiredAttributes = Collections.unmodifiableSet(requiredAttributes);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRuleSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRuleSyntaxImpl.java
new file mode 100644
index 0000000..6d892bb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITContentRuleSyntaxImpl.java
@@ -0,0 +1,204 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_ILLEGAL_TOKEN;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_DIT_CONTENT_RULE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the DIT content rule description syntax, which is used
+ * to hold DIT content rule definitions in the server schema. The format of this
+ * syntax is defined in RFC 2252.
+ */
+final class DITContentRuleSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_DIT_CONTENT_RULE_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll use the decodeDITContentRule method to determine if the
+    // value is acceptable.
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE
+            .get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("DITConentRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("DITContentRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      SchemaUtils.readOID(reader);
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("aux"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("must"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("may"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("not"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          SchemaUtils.readExtensions(reader);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("DITContentRuleSyntax",
+              "valueIsAcceptable", e);
+          throw e;
+        }
+      }
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRule.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRule.java
new file mode 100644
index 0000000..2f35eac
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRule.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID;
+
+import java.util.*;
+
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a DIT structure rule, which is used to indicate the types
+ * of children that entries may have.
+ */
+public final class DITStructureRule extends SchemaElement
+{
+  // The rule ID for this DIT structure rule.
+  private final Integer ruleID;
+
+  // The set of user defined names for this definition.
+  private final List<String> names;
+
+  // Indicates whether this definition is declared "obsolete".
+  private final boolean isObsolete;
+
+  // The name form for this DIT structure rule.
+  private final String nameFormOID;
+
+  // The set of superior DIT structure rules.
+  private final Set<Integer> superiorRuleIDs;
+
+  // The definition string used to create this objectclass.
+  private final String definition;
+
+  private NameForm nameForm;
+  private Set<DITStructureRule> superiorRules = Collections.emptySet();
+
+
+
+  DITStructureRule(final Integer ruleID, final List<String> names,
+      final String description, final boolean obsolete,
+      final String nameFormOID, final Set<Integer> superiorRuleIDs,
+      final Map<String, List<String>> extraProperties, final String definition)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(ruleID, nameFormOID, superiorRuleIDs);
+    this.ruleID = ruleID;
+    this.names = names;
+    this.isObsolete = obsolete;
+    this.nameFormOID = nameFormOID;
+    this.superiorRuleIDs = superiorRuleIDs;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+  }
+
+
+
+  /**
+   * Retrieves the name form for this DIT structure rule.
+   *
+   * @return The name form for this DIT structure rule.
+   */
+  public NameForm getNameForm()
+  {
+    return nameForm;
+  }
+
+
+
+  /**
+   * Retrieves the name or rule ID for this schema definition. If it has one or
+   * more names, then the primary name will be returned. If it does not have any
+   * names, then the OID will be returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public String getNameOrRuleID()
+  {
+    if (names.isEmpty())
+    {
+      return ruleID.toString();
+    }
+    return names.get(0);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the user-defined names that may be
+   * used to reference this schema definition.
+   *
+   * @return Returns an unmodifiable list containing the user-defined names that
+   *         may be used to reference this schema definition.
+   */
+  public List<String> getNames()
+  {
+    return names;
+  }
+
+
+
+  /**
+   * Retrieves the rule ID for this DIT structure rule.
+   *
+   * @return The rule ID for this DIT structure rule.
+   */
+  public Integer getRuleID()
+  {
+    return ruleID;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the superior rules for this DIT
+   * structure rule.
+   *
+   * @return An unmodifiable set containing the superior rules for this DIT
+   *         structure rule.
+   */
+  public Set<DITStructureRule> getSuperiorRules()
+  {
+    return superiorRules;
+  }
+
+
+
+  @Override
+  public int hashCode()
+  {
+    return ruleID.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name.
+   *
+   * @param name
+   *          The name for which to make the determination.
+   * @return <code>true</code> if the specified name is assigned to this schema
+   *         definition, or <code>false</code> if not.
+   */
+  public boolean hasName(final String name)
+  {
+    for (final String n : names)
+    {
+      if (n.equalsIgnoreCase(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition is declared "obsolete".
+   *
+   * @return <code>true</code> if this schema definition is declared "obsolete",
+   *         or <code>false</code> if not.
+   */
+  public boolean isObsolete()
+  {
+    return isObsolete;
+  }
+
+
+
+  /**
+   * Retrieves the string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  DITStructureRule duplicate()
+  {
+    return new DITStructureRule(ruleID, names, description, isObsolete,
+        nameFormOID, superiorRuleIDs, extraProperties, definition);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(ruleID);
+
+    if (!names.isEmpty())
+    {
+      final Iterator<String> iterator = names.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NAME ( '");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append("' '");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append("' )");
+      }
+      else
+      {
+        buffer.append(" NAME '");
+        buffer.append(firstName);
+        buffer.append("'");
+      }
+    }
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+
+    if (isObsolete)
+    {
+      buffer.append(" OBSOLETE");
+    }
+
+    buffer.append(" FORM ");
+    buffer.append(nameFormOID);
+
+    if (superiorRuleIDs != null && !superiorRuleIDs.isEmpty())
+    {
+      final Iterator<Integer> iterator = superiorRuleIDs.iterator();
+
+      final Integer firstRule = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" SUP ( ");
+        buffer.append(firstRule);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" SUP ");
+        buffer.append(firstRule);
+      }
+    }
+  }
+
+
+
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    try
+    {
+      nameForm = schema.getNameForm(nameFormOID);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM
+          .get(definition, nameFormOID);
+      throw new SchemaException(message, e);
+    }
+
+    if (!superiorRuleIDs.isEmpty())
+    {
+      superiorRules = new HashSet<DITStructureRule>(superiorRuleIDs.size());
+      DITStructureRule rule;
+      for (final Integer id : superiorRuleIDs)
+      {
+        try
+        {
+          rule = schema.getDITStructureRule(id);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID
+              .get(definition, id);
+          throw new SchemaException(message, e);
+        }
+        superiorRules.add(rule);
+      }
+    }
+    superiorRules = Collections.unmodifiableSet(superiorRules);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRuleSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRuleSyntaxImpl.java
new file mode 100644
index 0000000..4100f6c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DITStructureRuleSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_ILLEGAL_TOKEN;
+import static org.opends.sdk.schema.SchemaConstants.EMR_INTEGER_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_DIT_STRUCTURE_RULE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the DIT structure rule description syntax, which is
+ * used to hold DIT structure rule definitions in the server schema. The format
+ * of this syntax is defined in RFC 2252.
+ */
+final class DITStructureRuleSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_INTEGER_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_DIT_STRUCTURE_RULE_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll use the decodeDITStructureRule method to determine if the
+    // value is acceptable.
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE
+            .get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("DITStructureRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("DITStructureRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      SchemaUtils.readRuleID(reader);
+
+      String nameForm = null;
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("form"))
+        {
+          nameForm = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("sup"))
+        {
+          SchemaUtils.readRuleIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          SchemaUtils.readExtensions(reader);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("DITStructureRuleSyntax",
+              "valueIsAcceptable", e);
+          throw e;
+        }
+      }
+
+      if (nameForm == null)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM
+            .get(definition);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("DITStructureRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DeliveryMethodSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DeliveryMethodSyntaxImpl.java
new file mode 100644
index 0000000..bb621a9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DeliveryMethodSyntaxImpl.java
@@ -0,0 +1,169 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the delivery method attribute syntax. This contains one or
+ * more of a fixed set of values. If there are multiple values, then they are
+ * separated by spaces with a dollar sign between them. The allowed values
+ * include:
+ * <UL>
+ * <LI>any</LI>
+ * <LI>mhs</LI>
+ * <LI>physical</LI>
+ * <LI>telex</LI>
+ * <LI>teletex</LI>
+ * <LI>g3fax</LI>
+ * <LI>g4fax</LI>
+ * <LI>ia5</LI>
+ * <LI>videotex</LI>
+ * <LI>telephone</LI>
+ * </UL>
+ */
+final class DeliveryMethodSyntaxImpl extends AbstractSyntaxImpl
+{
+  /**
+   * The set of values that may be used as delivery methods.
+   */
+  private static final HashSet<String> ALLOWED_VALUES = new HashSet<String>();
+  {
+    ALLOWED_VALUES.add("any");
+    ALLOWED_VALUES.add("mhs");
+    ALLOWED_VALUES.add("physical");
+    ALLOWED_VALUES.add("telex");
+    ALLOWED_VALUES.add("teletex");
+    ALLOWED_VALUES.add("g3fax");
+    ALLOWED_VALUES.add("g4fax");
+    ALLOWED_VALUES.add("ia5");
+    ALLOWED_VALUES.add("videotex");
+    ALLOWED_VALUES.add("telephone");
+  }
+
+
+
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_DELIVERY_METHOD_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String stringValue = toLowerCase(value.toString());
+    final StringTokenizer tokenizer = new StringTokenizer(stringValue, " $");
+    if (!tokenizer.hasMoreTokens())
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS
+          .get(value.toString()));
+      return false;
+    }
+
+    while (tokenizer.hasMoreTokens())
+    {
+      final String token = tokenizer.nextToken();
+      if (!ALLOWED_VALUES.contains(token))
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT
+            .get(value.toString(), token));
+        return false;
+      }
+    }
+
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..e601b54
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
@@ -0,0 +1,133 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS;
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the directoryStringFirstComponentMatch matching rule
+ * defined in X.520 and referenced in RFC 2252. This rule is intended for use
+ * with attributes whose values contain a set of parentheses enclosing a
+ * space-delimited set of names and/or name-value pairs (like attribute type or
+ * objectclass descriptions) in which the "first component" is the first item
+ * after the opening parenthesis.
+ */
+final class DirectoryStringFirstComponentEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return new DefaultEqualityAssertion(SchemaConstants.SINGLE_SPACE_VALUE);
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return new DefaultEqualityAssertion(ByteString.empty());
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return new DefaultEqualityAssertion(ByteString.valueOf(buffer.toString()));
+  }
+
+
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final String definition = value.toString();
+    final SubstringReader reader = new SubstringReader(definition);
+
+    // We'll do this a character at a time. First, skip over any leading
+    // whitespace.
+    reader.skipWhitespaces();
+
+    if (reader.remaining() <= 0)
+    {
+      // This means that the value was empty or contained only
+      // whitespace.
+      // That is illegal.
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_EMPTY_VALUE.get();
+      throw DecodeException.error(message);
+    }
+
+    // The next character must be an open parenthesis. If it is not,
+    // then
+    // that is an error.
+    final char c = reader.read();
+    if (c != '(')
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS
+          .get(definition, (reader.pos() - 1), String.valueOf(c));
+      throw DecodeException.error(message);
+    }
+
+    // Skip over any spaces immediately following the opening
+    // parenthesis.
+    reader.skipWhitespaces();
+
+    // The next set of characters must be the OID.
+    final String string = SchemaUtils.readQuotedString(reader);
+
+    // Grab the substring between the start pos and the current pos
+    return ByteString.valueOf(string);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringSyntaxImpl.java
new file mode 100644
index 0000000..e971310
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DirectoryStringSyntaxImpl.java
@@ -0,0 +1,126 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE;
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the directory string attribute syntax, which is simply a
+ * set of UTF-8 characters. By default, they will be treated in a
+ * case-insensitive manner, and equality, ordering, substring, and approximate
+ * matching will be allowed.
+ */
+final class DirectoryStringSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_DIRECTORY_STRING_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    if (value.length() > 0
+        || schema.getSchemaCompatOptions()
+            .isZeroLengthDirectoryStringsAllowed())
+    {
+      return true;
+    }
+    else
+    {
+      invalidReason
+          .append(ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE
+              .get());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..eb0a820
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
@@ -0,0 +1,217 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import java.util.TreeSet;
+import java.util.Iterator;
+
+import org.opends.sdk.*;
+import com.sun.opends.sdk.util.StaticUtils;
+import static com.sun.opends.sdk.util.StaticUtils.getBytes;
+
+
+/**
+ * This class defines the distinguishedNameMatch matching rule defined in X.520
+ * and referenced in RFC 2252.
+ */
+final class DistinguishedNameEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    try
+    {
+      DN dn = DN.valueOf(value.toString(), schema.nonStrict());
+      StringBuilder builder = new StringBuilder(value.length());
+      return ByteString.valueOf(normalizeDN(builder, dn));
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      throw DecodeException.error(e.getMessageObject());
+    }
+    catch (final Exception e)
+    {
+      throw DecodeException.error(LocalizableMessage.raw(e.toString()));
+    }
+  }
+
+  /**
+   * Returns the normalized string representation of a DN.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param dn The DN.
+   * @return The normalized string representation of the provided DN.
+   */
+  private static StringBuilder normalizeDN(final StringBuilder builder,
+                                          final DN dn)
+  {
+    if(dn.rdn() == null)
+    {
+      return builder;
+    }
+
+    int i = dn.size() - 1;
+    normalizeRDN(builder, dn.parent(i).rdn());
+    for (i--; i >= 0; i--)
+    {
+      builder.append('\u0000');
+      normalizeRDN(builder, dn.parent(i).rdn());
+    }
+    return builder;
+  }
+
+  /**
+   * Returns the normalized string representation of a RDN.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param rdn The RDN.
+   * @return The normalized string representation of the provided RDN.
+   */
+  private static StringBuilder normalizeRDN(final StringBuilder builder,
+                                           final RDN rdn)
+  {
+    final int sz = rdn.size();
+    if (sz == 1)
+    {
+      return normalizeAVA(builder, rdn.getFirstAVA());
+    }
+    else
+    {
+      // Need to sort the AVAs before comparing.
+      TreeSet<AVA> a = new TreeSet<AVA>();
+      for(AVA ava : rdn)
+      {
+        a.add(ava);
+      }
+      Iterator<AVA> i = a.iterator();
+      // Normalize the first AVA.
+      normalizeAVA(builder, i.next());
+      while(i.hasNext())
+      {
+        builder.append('\u0001');
+        normalizeAVA(builder, i.next());
+      }
+
+      return builder;
+    }
+  }
+
+  /**
+   * Returns the normalized string representation of an AVA.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param ava The AVA.
+   * @return The normalized string representation of the provided AVA.
+   */
+  private static StringBuilder normalizeAVA(final StringBuilder builder,
+                                           final AVA ava)
+  {
+    ByteString value = ava.getAttributeValue();
+    final MatchingRule matchingRule =
+        ava.getAttributeType().getEqualityMatchingRule();
+    if (matchingRule != null)
+    {
+      try
+      {
+        value =
+            matchingRule.normalizeAttributeValue(ava.getAttributeValue());
+      }
+      catch (final DecodeException de)
+      {
+        // Ignore - we'll drop back to the user provided value.
+      }
+    }
+
+    if (!ava.getAttributeType().getNames().iterator().hasNext())
+    {
+      builder.append(ava.getAttributeType().getOID());
+      builder.append("=#");
+      StaticUtils.toHex(value, builder);
+    }
+    else
+    {
+      final String name = ava.getAttributeType().getNameOrOID();
+      // Normalizing.
+      StaticUtils.toLowerCase(name, builder);
+
+      builder.append("=");
+
+      final Syntax syntax = ava.getAttributeType().getSyntax();
+      if (!syntax.isHumanReadable())
+      {
+        builder.append("#");
+        StaticUtils.toHex(value, builder);
+      }
+      else
+      {
+        final String str = value.toString();
+        if (str.length() == 0)
+        {
+          return builder;
+        }
+        char c = str.charAt(0);
+        int startPos = 0;
+        if ((c == ' ') || (c == '#'))
+        {
+          builder.append('\\');
+          builder.append(c);
+          startPos = 1;
+        }
+        final int length = str.length();
+        for (int si = startPos; si < length; si++)
+        {
+          c = str.charAt(si);
+          if (c < ' ')
+          {
+            for (final byte b : getBytes(String.valueOf(c)))
+            {
+              builder.append('\\');
+              builder.append(StaticUtils.byteToLowerHex(b));
+            }
+          }
+          else
+          {
+            if ((c == ' ' && si == length - 1)
+                || (c == '"' || c == '+' || c == ',' || c == ';' || c == '<'
+                    || c == '=' || c == '>' || c == '\\' || c == '\u0000'))
+            {
+              builder.append('\\');
+            }
+            builder.append(c);
+          }
+        }
+      }
+    }
+    return builder;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameSyntaxImpl.java
new file mode 100644
index 0000000..5b80627
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DistinguishedNameSyntaxImpl.java
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_DN_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_DN_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizableMessageBuilder;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+
+
+/**
+ * This class defines the distinguished name attribute syntax, which is used for
+ * attributes that hold distinguished names (DNs). Equality and substring
+ * matching will be allowed by default.
+ */
+final class DistinguishedNameSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_DN_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_DN_NAME;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    try
+    {
+      DN.valueOf(value.toString(), schema);
+    }
+    catch (final LocalizedIllegalArgumentException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java
new file mode 100644
index 0000000..f047a4e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java
@@ -0,0 +1,1105 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class defines an approximate matching rule based on the Double Metaphone
+ * algorithm. The Metaphone and Double Metaphone algorithms were originally
+ * devised by Lawrence Philips (published in the December 1990 issue of
+ * <I>Computer Language</I> and the <A
+ * HREF="http://www.cuj.com/documents/s=8038/cuj0006philips/">June 2000 issue of
+ * <I>C/C++ Users Journal</I></A>, respectively), and this version of the
+ * algorithm is based on a version modified by Kevin Atkinson to include
+ * bugfixes and additional functionality (source is available <A
+ * HREF="http://aspell.net/metaphone/dmetaph.cpp">here</A> and additional
+ * Metaphone and Double Metaphone information is available at <A
+ * HREF="http://aspell.net/metaphone/">http://aspell.net/ metaphone/</A>). This
+ * implementation is largely the same as the one provided by Kevin Atkinson, but
+ * it has been re-written for better readability, for more efficiency, to get
+ * rid of checks for conditions that can't possibly happen, and to get rid of
+ * redundant checks that aren't needed. It has also been updated to always only
+ * generate a single value rather than one or possibly two values.
+ */
+final class DoubleMetaphoneApproximateMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    String valueString = value.toString();
+    final int length = valueString.length();
+    if (length == 0)
+    {
+      // The value is empty, so it is already normalized.
+      return ByteString.empty();
+    }
+
+    final int last = length - 1;
+
+    // Pad the value to allow for checks to go past the end of the
+    // value.
+    valueString = valueString.toUpperCase() + "     ";
+
+    // The metaphone value that is being constructed.
+    final StringBuilder metaphone = new StringBuilder(4);
+
+    // Skip over GN, KN, PN, WR, and PS at the beginning of a word.
+    int pos = 0;
+    String substring = valueString.substring(0, 2);
+    if (substring.equals("GN") || substring.equals("KN")
+        || substring.equals("PN") || substring.equals("WR")
+        || substring.equals("PS"))
+    {
+      pos++;
+    }
+
+    // 'X' at the beginning of a word will sound like Z, but Z will
+    // always be mapped to S.
+    else if (valueString.charAt(0) == 'X')
+    {
+      metaphone.append("S");
+      pos++;
+    }
+
+    // Loop until we have at least four metaphone characters or have
+    // reached the end of the string.
+    while (metaphone.length() < 4 && pos < length)
+    {
+      // Check the character at the current position against various
+      // targets.
+      char posMinusFour;
+      char posMinusThree;
+      char posMinusTwo;
+      char posMinusOne;
+      char posPlusOne;
+      char posPlusTwo;
+      switch (valueString.charAt(pos))
+      {
+      case 'A':
+      case 'E':
+      case 'I':
+      case 'O':
+      case 'U':
+      case 'Y':
+        // All initial vowels map to 'A'. All others will be ignored.
+        if (pos == 0)
+        {
+          metaphone.append("A");
+        }
+
+        pos++;
+        break;
+
+      case 'B':
+        // B and BB will be mapped to P, with the exception of "MB" as
+        // in "crumb", but that will be handled elsewhere.
+        metaphone.append("P");
+
+        if (valueString.charAt(++pos) == 'B')
+        {
+          pos++;
+        }
+
+        break;
+
+      case 'C':
+        // Check for various Germanic sequences, which will be mapped to
+        // 'K'. This basically includes all occurrences of "ACH" where
+        // the preceding character is not a vowel and the following
+        // character is neither an 'E' nor an 'I' except in "BACHER" and
+        // "MACHER".
+        if (pos > 1
+            && !isVowel(posMinusTwo = valueString.charAt(pos - 2))
+            && hasSubstring(valueString, pos - 1, "ACH")
+            && (posPlusTwo = valueString.charAt(pos + 2)) != 'I'
+            && (posPlusTwo != 'E' || valueString.charAt(pos + 3) == 'R'
+                && (posMinusTwo == 'B' || posMinusTwo == 'M')))
+        {
+          metaphone.append("K");
+          pos += 2;
+          break;
+        }
+
+        // Check for a special case of "caesar", which will be maped to
+        // 'S'.
+        if (pos == 0 && hasSubstring(valueString, pos + 1, "AESAR"))
+        {
+          metaphone.append("S");
+          pos += 2;
+          break;
+        }
+
+        // CH can be treated in lots of different ways.
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'H')
+        {
+          // Check for "chia" as in "chianti" and map to 'K'.
+          if (hasSubstring(valueString, pos + 2, "IA"))
+          {
+            metaphone.append("K");
+            pos += 2;
+            break;
+          }
+
+          // Check for "chae" as in "michael" and map to 'K'.
+          if (hasSubstring(valueString, pos + 2, "AE"))
+          {
+            metaphone.append("K");
+            pos += 2;
+            break;
+          }
+
+          // Check for a Greek root at the beginning of the value like
+          // chemistry or chorus and map to 'K'.
+          if (pos == 0
+              && !hasSubstring(valueString, 2, "ORE")
+              && (hasSubstring(valueString, 2, "ARAC")
+                  || hasSubstring(valueString, 2, "ARIS")
+                  || hasSubstring(valueString, 2, "OR")
+                  || hasSubstring(valueString, 2, "YM")
+                  || hasSubstring(valueString, 2, "IA") || hasSubstring(
+                  valueString, 2, "EM")))
+          {
+            metaphone.append("K");
+            pos += 2;
+            break;
+          }
+
+          // Check for "CH" values that produce a "KH" sound that will
+          // be mapped to 'K'.
+          if (isGermanic(valueString)
+              || hasSubstring(valueString, pos - 2, "ORCHES")
+              || hasSubstring(valueString, pos - 2, "ARCHIT")
+              || hasSubstring(valueString, pos - 2, "ORCHID")
+              || (posPlusTwo = valueString.charAt(pos + 2)) == 'T'
+              || posPlusTwo == 'S'
+              || (pos == 0
+                  || (posMinusOne = valueString.charAt(pos - 1)) == 'A'
+                  || posMinusOne == 'O' || posMinusOne == 'U' || posMinusOne == 'E')
+              && (posPlusTwo == 'L' || posPlusTwo == 'R' || posPlusTwo == 'N'
+                  || posPlusTwo == 'M' || posPlusTwo == 'B'
+                  || posPlusTwo == 'H' || posPlusTwo == 'F'
+                  || posPlusTwo == 'V' || posPlusTwo == 'W'))
+          {
+            metaphone.append("K");
+            pos += 2;
+            break;
+          }
+
+          // All other "CH" values.
+          if (pos > 0)
+          {
+            if (hasSubstring(valueString, 0, "MC"))
+            {
+              metaphone.append("K");
+            }
+            else
+            {
+              metaphone.append("X");
+            }
+          }
+          else
+          {
+            metaphone.append("X");
+          }
+
+          pos += 2;
+          break;
+        }
+
+        // Check for "CZ" as in "czerny" but not "wicz" and map to 'S'.
+        if (posPlusOne == 'Z' && !hasSubstring(valueString, pos - 2, "WI"))
+        {
+          metaphone.append("S");
+          pos += 2;
+          break;
+        }
+
+        // Check for "CIA" as in "focaccia" and map to 'X'.
+        if (posPlusOne == 'I' && valueString.charAt(pos + 2) == 'A')
+        {
+          metaphone.append("X");
+          pos += 3;
+          break;
+        }
+
+        // Check for a double C but not in values that start with "McC"
+        if (posPlusOne == 'C' && !(pos == 1 && valueString.charAt(0) == 'M'))
+        {
+          if (((posPlusTwo = valueString.charAt(pos + 2)) == 'I'
+              || posPlusTwo == 'E' || posPlusTwo == 'H')
+              && !(posPlusTwo == 'H' && valueString.charAt(pos + 3) == 'U'))
+          {
+            if (pos == 1 && valueString.charAt(pos - 1) == 'A'
+                || hasSubstring(valueString, pos - 1, "UCCEE")
+                || hasSubstring(valueString, pos - 1, "UCCES"))
+            {
+              // Values like "accident", "accede", and "succeed".
+              metaphone.append("K");
+              pos += 2;
+              break;
+            }
+            else
+            {
+              // Values like "bacci" or "bertucci".
+              metaphone.append("X");
+              pos += 3;
+              break;
+            }
+          }
+          else
+          {
+            // This is Pierce's Rule, whatever that means.
+            metaphone.append("K");
+            pos += 2;
+            break;
+          }
+        }
+
+        // Check for CK, CG, or CQ and map to 'K'. Check for CI, CE, and
+        // CY and map to "S".
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'K'
+            || posPlusOne == 'G' || posPlusOne == 'Q')
+        {
+          metaphone.append("K");
+          pos += 2;
+          break;
+        }
+
+        // Check for CI, CE, or CY and map to 'S'.
+        if (posPlusOne == 'I' || posPlusOne == 'E' || posPlusOne == 'Y')
+        {
+          metaphone.append("S");
+          pos += 2;
+          break;
+        }
+
+        // All other cases of "C" will be mapped to 'K'. However, the
+        // number of positions that we skip ahead may vary. If there is
+        // a value that consists of two words like "mac caffrey", then
+        // skip ahead three. For the character combinations of "CK" and
+        // "CQ", then skip ahead two. For the character combinations of
+        // "CC" except "CCE" and "CCI", then skip ahead two. For all
+        // other cases, skip ahead one.
+        metaphone.append("K");
+        switch (valueString.charAt(pos + 1))
+        {
+        case ' ':
+          switch (valueString.charAt(pos + 2))
+          {
+          case 'C':
+          case 'Q':
+          case 'G':
+            pos += 3;
+            break;
+          default:
+            pos++;
+            break;
+          }
+          break;
+
+        case 'K':
+        case 'Q':
+          pos += 2;
+          break;
+
+        case 'C':
+          switch (valueString.charAt(pos + 2))
+          {
+          case 'E':
+          case 'I':
+            pos++;
+            break;
+          default:
+            pos += 2;
+            break;
+          }
+          break;
+        default:
+          pos++;
+        }
+        break;
+
+      case 'D':
+        // DG will be mapped to either 'J' (in cases like edge) or 'TK'
+        // (in cases like Edgar).
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'G')
+        {
+          if ((posPlusTwo = valueString.charAt(pos + 2)) == 'I'
+              || posPlusTwo == 'E' || posPlusTwo == 'Y')
+          {
+            metaphone.append("J");
+            pos += 3;
+            break;
+          }
+          else
+          {
+            metaphone.append("TK");
+            pos += 2;
+            break;
+          }
+        }
+
+        // DT and DD will be mapped to 'T'.
+        if (posPlusOne == 'T' || posPlusOne == 'D')
+        {
+          metaphone.append("T");
+          pos += 2;
+          break;
+        }
+
+        // All other cases will be mapped to 'T'.
+        metaphone.append("T");
+        pos++;
+        break;
+
+      case 'F':
+        // F always maps to F. If there is a double F, then skip the
+        // second one.
+        metaphone.append("F");
+        pos++;
+        if (valueString.charAt(pos) == 'F')
+        {
+          pos++;
+        }
+        break;
+
+      case 'G':
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'H')
+        {
+          // A "GH" that is not preceded by a vowel will be mapped to
+          // 'K'.
+          if (pos > 0 && !isVowel(valueString.charAt(pos - 1)))
+          {
+            metaphone.append("K");
+            pos += 2;
+            break;
+          }
+
+          if (pos == 0)
+          {
+            if (valueString.charAt(pos + 2) == 'I')
+            {
+              // Words like ghislane or ghiradelli
+              metaphone.append("J");
+            }
+            else
+            {
+              metaphone.append("K");
+            }
+
+            pos += 2;
+            break;
+          }
+
+          // A refined version of Parker's Rule.
+          if (pos > 1
+              && ((posMinusTwo = valueString.charAt(pos - 2)) == 'B'
+                  || posMinusTwo == 'H' || posMinusTwo == 'D')
+              || pos > 2
+              && ((posMinusThree = valueString.charAt(pos - 3)) == 'B'
+                  || posMinusThree == 'H' || posMinusThree == 'D')
+              || pos > 3
+              && ((posMinusFour = valueString.charAt(pos - 4)) == 'B' || posMinusFour == 'H'))
+          {
+            pos += 2;
+            break;
+          }
+          else
+          {
+            if (pos > 2
+                && valueString.charAt(pos - 1) == 'U'
+                && ((posMinusThree = valueString.charAt(pos - 3)) == 'C'
+                    || posMinusThree == 'G' || posMinusThree == 'L'
+                    || posMinusThree == 'R' || posMinusThree == 'T'))
+            {
+              // Words like laugh, McLaughlin, cough, rough are mapped
+              // to 'F'.
+              metaphone.append("F");
+            }
+            else if (pos > 0 && valueString.charAt(pos - 1) != 'I')
+            {
+              metaphone.append("K");
+            }
+
+            pos += 2;
+            break;
+          }
+        }
+
+        if (posPlusOne == 'N')
+        {
+          if (pos == 1 && isVowel(valueString.charAt(0))
+              && !isSlavoGermanic(valueString))
+          {
+            metaphone.append("KN");
+            pos += 2;
+            break;
+          }
+          else
+          {
+            if (!hasSubstring(valueString, pos + 2, "EY")
+                && !isSlavoGermanic(valueString))
+            {
+              metaphone.append("N");
+            }
+            else
+            {
+              metaphone.append("KN");
+            }
+
+            pos += 2;
+            break;
+          }
+        }
+
+        // GLI as in tagliaro will be mapped to "KL".
+        if (posPlusOne == 'L' && valueString.charAt(pos + 2) == 'I')
+        {
+          metaphone.append("KL");
+          pos += 2;
+          break;
+        }
+
+        // Forms of GY, GE, and GI at the beginning of a word will map
+        // to 'K'.
+        if (pos == 0
+            && (posPlusOne == 'Y'
+                || (substring = valueString.substring(pos + 1, pos + 3))
+                    .equals("ES") || substring.equals("EP")
+                || substring.equals("EB") || substring.equals("EL")
+                || substring.equals("EY") || substring.equals("IB")
+                || substring.equals("IL") || substring.equals("IN")
+                || substring.equals("IE") || substring.equals("EI") || substring
+                .equals("ER")))
+        {
+          metaphone.append("K");
+          pos += 2;
+          break;
+        }
+
+        // Some occurrences of GER and GY in a word will be mapped to
+        // 'K'.
+        posPlusTwo = valueString.charAt(pos + 2);
+        if ((posPlusOne == 'E' && posPlusTwo == 'R' || posPlusOne == 'Y')
+            && (posMinusOne = valueString.charAt(pos - 1)) != 'E'
+            && posMinusOne != 'I' && !hasSubstring(valueString, 0, "DANGER")
+            && !hasSubstring(valueString, 0, "RANGER")
+            && !hasSubstring(valueString, 0, "MANGER")
+            && !hasSubstring(valueString, pos - 1, "RGY")
+            && !hasSubstring(valueString, pos - 1, "OGY"))
+        {
+          metaphone.append("K");
+          pos += 2;
+          break;
+        }
+
+        // Check for Italian uses like 'biaggi" and map to 'J'.
+        if (posPlusOne == 'E' || posPlusOne == 'I' || posPlusOne == 'Y'
+            || hasSubstring(valueString, pos - 1, "AGGI")
+            || hasSubstring(valueString, pos - 1, "OGGI"))
+        {
+          // Germanic uses will be mapped to 'K'.
+          if (isGermanic(valueString)
+              || hasSubstring(valueString, pos + 1, "ET"))
+          {
+            metaphone.append("K");
+          }
+          else
+          {
+            metaphone.append("J");
+          }
+
+          pos += 2;
+          break;
+        }
+
+        // All other cases will be mapped to 'K'. If there is a double
+        // G, then skip two. Otherwise, just skip one.
+        metaphone.append("K");
+        pos++;
+
+        if (posPlusOne == 'G')
+        {
+          pos++;
+        }
+
+        break;
+
+      case 'H':
+        // The letter 'H' will only be processed if it is immediately
+        // followed by a vowel and is either the start of the word or
+        // preceded by a vowel.
+        if (isVowel(valueString.charAt(pos + 1)))
+        {
+          if (pos == 0 || isVowel(valueString.charAt(pos - 1)))
+          {
+            metaphone.append("H");
+            pos++;
+          }
+        }
+
+        pos++;
+        break;
+
+      case 'J':
+        // Take care of obvious Spanish uses that should map to 'H'.
+        if (hasSubstring(valueString, 0, "SAN "))
+        {
+          metaphone.append("H");
+          pos++;
+          break;
+        }
+
+        if (hasSubstring(valueString, pos, "JOSE"))
+        {
+          if (pos == 0 && valueString.charAt(pos + 4) == ' ')
+          {
+            metaphone.append("H");
+          }
+          else
+          {
+            metaphone.append("J");
+          }
+
+          pos++;
+          break;
+        }
+
+        // All other cases will be mapped to 'J'.
+        metaphone.append("J");
+
+        if (valueString.charAt(pos + 1) == 'J')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'K':
+        // 'K' will always be mapped to 'K'. KK will be treated like K.
+        metaphone.append("K");
+
+        if (valueString.charAt(pos + 1) == 'K')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'L':
+        // 'L' will always be mapped to 'L'. LL will be treated like L,
+        // even for potential Spanish uses.
+        metaphone.append("L");
+
+        if (valueString.charAt(pos + 1) == 'L')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'M':
+        // 'M' will always be mapped to 'M'. MM will be treated like M.
+        // UMB in cases like "dumb" and "thumb" will be treated like M.
+        metaphone.append("M");
+
+        if (valueString.charAt(pos + 1) == 'M')
+        {
+          pos++;
+        }
+        else if (hasSubstring(valueString, pos - 1, "UMB"))
+        {
+          if (pos + 1 == last || hasSubstring(valueString, pos + 2, "ER"))
+          {
+            pos++;
+          }
+        }
+
+        pos++;
+        break;
+
+      case 'N':
+        // 'N' will always be mapped to 'N'. NN will be treated like N.
+        metaphone.append("N");
+
+        if (valueString.charAt(pos + 1) == 'N')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'P':
+        // PH will be mapped to 'F'.
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'H')
+        {
+          metaphone.append("F");
+          pos += 2;
+          break;
+        }
+
+        // All other cases will be mapped to 'P', with PP and PB being
+        // treated like P.
+        metaphone.append("P");
+
+        if (posPlusOne == 'P' || posPlusOne == 'B')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'Q':
+        // 'Q' will always be mapped to 'K'. QQ will be treated like Q.
+        metaphone.append("K");
+
+        if (valueString.charAt(pos + 1) == 'Q')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'R':
+        // Ignore R at the end of French words.
+        if (pos == last && !isSlavoGermanic(valueString)
+            && hasSubstring(valueString, pos - 2, "IE")
+            && !hasSubstring(valueString, pos - 4, "ME")
+            && !hasSubstring(valueString, pos - 4, "MA"))
+        {
+          pos++;
+          break;
+        }
+
+        // All other cases will be mapped to 'R', with RR treated like
+        // R.
+        metaphone.append("R");
+
+        if (valueString.charAt(pos + 1) == 'R')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'S':
+        // Special cases like isle and carlysle will be silent.
+        if (hasSubstring(valueString, pos - 1, "ISL")
+            || hasSubstring(valueString, pos - 1, "YSL"))
+        {
+          pos++;
+          break;
+        }
+
+        // Special case of sugar mapped to 'X'.
+        if (hasSubstring(valueString, pos + 1, "UGAR"))
+        {
+          metaphone.append("X");
+          pos++;
+          break;
+        }
+
+        // SH is generally mapped to 'X', but not in Germanic cases.
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'H')
+        {
+          if (hasSubstring(valueString, pos + 1, "HEIM")
+              || hasSubstring(valueString, pos + 1, "HOEK")
+              || hasSubstring(valueString, pos + 1, "HOLM")
+              || hasSubstring(valueString, pos + 1, "HOLZ"))
+          {
+            metaphone.append("S");
+          }
+          else
+          {
+            metaphone.append("X");
+          }
+
+          pos += 2;
+          break;
+        }
+
+        // Italian and Armenian cases will map to "S".
+        if (hasSubstring(valueString, pos + 1, "IO")
+            || hasSubstring(valueString, pos + 1, "IA"))
+        {
+          metaphone.append("S");
+          pos += 3;
+          break;
+        }
+
+        // SZ should be mapped to 'S'.
+        if (posPlusOne == 'Z')
+        {
+          metaphone.append("S");
+          pos += 2;
+          break;
+        }
+
+        // Various combinations at the beginning of words will be mapped
+        // to 'S'.
+        if (pos == 0
+            && (posPlusOne == 'M' || posPlusOne == 'N' || posPlusOne == 'L' || posPlusOne == 'W'))
+        {
+          metaphone.append("S");
+          pos++;
+          break;
+        }
+
+        // SC should be mapped to either SK, X, or S.
+        if (posPlusOne == 'C')
+        {
+          if ((posPlusTwo = valueString.charAt(pos + 2)) == 'H')
+          {
+            if (hasSubstring(valueString, pos + 3, "OO")
+                || hasSubstring(valueString, pos + 3, "UY")
+                || hasSubstring(valueString, pos + 3, "ED")
+                || hasSubstring(valueString, pos + 3, "EM"))
+            {
+              metaphone.append("SK");
+            }
+            else
+            {
+              metaphone.append("X");
+            }
+
+            pos += 3;
+            break;
+          }
+
+          if (posPlusTwo == 'I' || posPlusTwo == 'E' || posPlusTwo == 'Y')
+          {
+            metaphone.append("S");
+            pos += 3;
+            break;
+          }
+
+          metaphone.append("SK");
+          pos += 3;
+          break;
+        }
+
+        // Ignore a trailing S in French words. All others will be
+        // mapped to 'S'.
+        if (!(pos == last && (hasSubstring(valueString, pos - 2, "AI") || hasSubstring(
+            valueString, pos - 2, "OI"))))
+        {
+          metaphone.append("S");
+        }
+
+        if (posPlusOne == 'S' || posPlusOne == 'Z')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'T':
+        // "TION", "TIA", and "TCH" will be mapped to 'X'.
+        if (hasSubstring(valueString, pos, "TION")
+            || hasSubstring(valueString, pos, "TIA")
+            || hasSubstring(valueString, pos, "TCH"))
+        {
+          metaphone.append("X");
+          pos += 3;
+          break;
+        }
+
+        // TH or TTH will be mapped to either T (for Germanic cases) or
+        // 0 (zero) for the rest.
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'H'
+            || posPlusOne == 'T' && valueString.charAt(pos + 2) == 'H')
+        {
+          if (isGermanic(valueString)
+              || hasSubstring(valueString, pos + 2, "OM")
+              || hasSubstring(valueString, pos + 2, "AM"))
+          {
+            metaphone.append("T");
+          }
+          else
+          {
+            metaphone.append("0");
+          }
+
+          pos += 2;
+          break;
+        }
+
+        // All other cases will map to T, with TT and TD being treated
+        // like T.
+        metaphone.append("T");
+
+        if (posPlusOne == 'T' || posPlusOne == 'D')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'V':
+        // 'V' will always be mapped to 'F', with VV treated like V.
+        metaphone.append("F");
+
+        if (valueString.charAt(pos + 1) == 'V')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'W':
+        // WR should always map to R.
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'R')
+        {
+          metaphone.append("R");
+          pos += 2;
+          break;
+        }
+
+        // W[AEIOUYH] at the beginning of the word should be mapped to
+        // A.
+        if (pos == 0 && (isVowel(posPlusOne) || posPlusOne == 'H'))
+        {
+          metaphone.append("A");
+
+          // FIXME -- This isn't in the algorithm as written. Should it
+          // be?
+          pos += 2;
+          break;
+        }
+
+        // A Polish value like WICZ or WITZ should be mapped to TS.
+        if (hasSubstring(valueString, pos + 1, "WICZ")
+            || hasSubstring(valueString, pos + 1, "WITZ"))
+        {
+          metaphone.append("TS");
+          pos += 4;
+          break;
+        }
+
+        // Otherwise, we'll just skip it.
+        pos++;
+        break;
+
+      case 'X':
+        // X maps to KS except at the end of French words.
+        if (!(pos == last && (hasSubstring(valueString, pos - 3, "IAU")
+            || hasSubstring(valueString, pos - 3, "EAU")
+            || hasSubstring(valueString, pos - 2, "AU") || hasSubstring(
+            valueString, pos - 2, "OU"))))
+        {
+          metaphone.append("KS");
+        }
+
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'C'
+            || posPlusOne == 'X')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case 'Z':
+        // Chinese usages like zhao will map to J.
+        if ((posPlusOne = valueString.charAt(pos + 1)) == 'H')
+        {
+          metaphone.append("J");
+          pos += 2;
+          break;
+        }
+
+        // All other cases map to "S". ZZ will be treated like Z.
+        metaphone.append("S");
+
+        if (posPlusOne == 'Z')
+        {
+          pos++;
+        }
+
+        pos++;
+        break;
+
+      case '\u00C7': // C with a cedilla
+        // This will always be mapped to 'S'.
+        metaphone.append("S");
+        pos++;
+        break;
+
+      case '\u00D1': // N with a tilde
+        // This will always be mapped to 'N'.
+        metaphone.append("N");
+        pos++;
+        break;
+
+      default:
+        // We don't have any special treatment for this character, so
+        // skip it.
+        pos++;
+        break;
+      }
+    }
+
+    return ByteString.valueOf(metaphone.toString());
+  }
+
+
+
+  /**
+   * Indicates whether the provided value has the given substring at the
+   * specified position.
+   *
+   * @param value
+   *          The value containing the range for which to make the
+   *          determination.
+   * @param start
+   *          The position in the value at which to start the comparison.
+   * @param substring
+   *          The substring to compare against the specified value range.
+   * @return <CODE>true</CODE> if the specified portion of the value matches the
+   *         given substring, or <CODE>false</CODE> if it does not.
+   */
+  private boolean hasSubstring(final String value, final int start,
+      final String substring)
+  {
+    try
+    {
+      // This can happen since a lot of the rules "look behind" and
+      // rightfully don't check if it's the first character
+      if (start < 0)
+      {
+        return false;
+      }
+
+      final int end = start + substring.length();
+
+      // value isn't big enough to do the comparison
+      if (end > value.length())
+      {
+        return false;
+      }
+
+      for (int i = 0, pos = start; pos < end; i++, pos++)
+      {
+        if (value.charAt(pos) != substring.charAt(i))
+        {
+          return false;
+        }
+      }
+
+      return true;
+    }
+    catch (final Exception e)
+    {
+      StaticUtils.DEBUG_LOG.throwing("DoubleMetaphoneApproximateMatchingRule",
+          "hasSubstring", e);
+
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Indicates whether the provided string appears Germanic (starts with "VAN ",
+   * "VON ", or "SCH").
+   *
+   * @param s
+   *          The string for which to make the determination.
+   * @return <CODE>true</CODE> if the provided string appears Germanic, or
+   *         <CODE>false</CODE> if not.
+   */
+  private boolean isGermanic(final String s)
+  {
+    return s.startsWith("VAN ") || s.startsWith("VON ") || s.startsWith("SCH");
+  }
+
+
+
+  /**
+   * Indicates whether the provided string appears to be Slavo-Germanic.
+   *
+   * @param s
+   *          The string for which to make the determination.
+   * @return <CODE>true</CODE> if the provided string appears to be
+   *         Slavo-Germanic, or <CODE>false</CODE> if not.
+   */
+  private boolean isSlavoGermanic(final String s)
+  {
+    return s.contains("W") || s.contains("K") || s.contains("CZ")
+        || s.contains("WITZ");
+  }
+
+
+
+  /**
+   * Indicates whether the provided character is a vowel (including "Y").
+   *
+   * @param c
+   *          The character for which to make the determination.
+   * @return <CODE>true</CODE> if the provided character is a vowel, or
+   *         <CODE>false</CODE> if not.
+   */
+  private boolean isVowel(final char c)
+  {
+    switch (c)
+    {
+    case 'A':
+    case 'E':
+    case 'I':
+    case 'O':
+    case 'U':
+    case 'Y':
+      return true;
+
+    default:
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnhancedGuideSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnhancedGuideSyntaxImpl.java
new file mode 100644
index 0000000..2a8914f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnhancedGuideSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_ENHANCED_GUIDE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the enhanced guide attribute syntax, which may be used
+ * to provide criteria for generating search filters for entries of a given
+ * objectclass.
+ */
+final class EnhancedGuideSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_ENHANCED_GUIDE_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Get a lowercase string version of the provided value.
+    final String valueStr = toLowerCase(value.toString());
+
+    // Find the position of the first octothorpe. It should denote the
+    // end of the objectclass.
+    final int sharpPos = valueStr.indexOf('#');
+    if (sharpPos < 0)
+    {
+
+      invalidReason
+          .append(ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP.get(valueStr));
+      return false;
+    }
+
+    // Get the objectclass and see if it is a valid name or OID.
+    final String ocName = valueStr.substring(0, sharpPos).trim();
+    final int ocLength = ocName.length();
+    if (ocLength == 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC.get(valueStr));
+      return false;
+    }
+
+    try
+    {
+      SchemaUtils.readOID(new SubstringReader(ocName.substring(ocLength)));
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+
+    // Find the last octothorpe and make sure it is followed by a valid
+    // scope.
+    final int lastSharpPos = valueStr.lastIndexOf('#');
+    if (lastSharpPos == sharpPos)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP
+          .get(valueStr));
+      return false;
+    }
+
+    final String scopeStr = valueStr.substring(lastSharpPos + 1).trim();
+    if (!(scopeStr.equals("baseobject") || scopeStr.equals("onelevel")
+        || scopeStr.equals("wholesubtree") || scopeStr
+        .equals("subordinatesubtree")))
+    {
+      if (scopeStr.length() == 0)
+      {
+
+        invalidReason.append(ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE
+            .get(valueStr));
+      }
+      else
+      {
+
+        invalidReason.append(ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE.get(
+            valueStr, scopeStr));
+      }
+
+      return false;
+    }
+
+    // Everything between the two octothorpes must be the criteria. Make
+    // sure it is valid.
+    final String criteria = valueStr.substring(sharpPos + 1, lastSharpPos)
+        .trim();
+    final int criteriaLength = criteria.length();
+    if (criteriaLength == 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA
+          .get(valueStr));
+      return false;
+    }
+
+    return GuideSyntaxImpl.criteriaIsValid(criteria, valueStr, invalidReason);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumOrderingMatchingRule.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumOrderingMatchingRule.java
new file mode 100644
index 0000000..3d1c62d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumOrderingMatchingRule.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class is the ordering matching rule implementation for an enum syntax
+ * implmentation. The ordering is determined by the order of the entries in the
+ * X-ENUM extension value.
+ */
+final class EnumOrderingMatchingRule extends AbstractOrderingMatchingRuleImpl
+{
+  private final EnumSyntaxImpl syntax;
+
+
+
+  EnumOrderingMatchingRule(final EnumSyntaxImpl syntax)
+  {
+    Validator.ensureNotNull(syntax);
+    this.syntax = syntax;
+  }
+
+
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final int index = syntax.indexOf(value);
+    if (index < 0)
+    {
+      throw DecodeException
+          .error(WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE.get(value
+              .toString(), syntax.getName()));
+    }
+    return ByteString.valueOf(index);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumSyntaxImpl.java
new file mode 100644
index 0000000..69c2256
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EnumSyntaxImpl.java
@@ -0,0 +1,192 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE;
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+import static org.opends.sdk.schema.SchemaConstants.AMR_DOUBLE_METAPHONE_OID;
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OID_GENERIC_ENUM;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class provides an enumeration-based mechanism where a new syntax and its
+ * corresponding matching rules can be created on-the-fly. An enum syntax is an
+ * LDAPSyntaxDescriptionSyntax with X-ENUM extension.
+ */
+final class EnumSyntaxImpl extends AbstractSyntaxImpl
+{
+  private final String oid;
+  // Set of read-only enum entries.
+  private final List<String> entries;
+
+
+
+  EnumSyntaxImpl(final String oid, final List<String> entries)
+  {
+    Validator.ensureNotNull(oid, entries);
+    this.oid = oid;
+    final List<String> entryStrings = new ArrayList<String>(entries.size());
+
+    for (final String entry : entries)
+    {
+      final String normalized = normalize(ByteString.valueOf(entry));
+      if (!entryStrings.contains(normalized))
+      {
+        entryStrings.add(normalized);
+      }
+    }
+    this.entries = Collections.unmodifiableList(entryStrings);
+  }
+
+
+
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return oid;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OID_GENERIC_ENUM + "." + oid;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public int indexOf(final ByteSequence value)
+  {
+    return entries.indexOf(normalize(value));
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // The value is acceptable if it belongs to the set.
+    final boolean isAllowed = entries.contains(normalize(value));
+
+    if (!isAllowed)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE
+          .get(value.toString(), oid);
+      invalidReason.append(message);
+    }
+
+    return isAllowed;
+  }
+
+
+
+  private String normalize(final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return " ";
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return "";
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return buffer.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EqualLengthApproximateMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EqualLengthApproximateMatchingRuleImpl.java
new file mode 100644
index 0000000..f071f70
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/EqualLengthApproximateMatchingRuleImpl.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.*;
+
+
+
+/**
+ * This class implements an extremely simple approximate matching rule that will
+ * consider two values approximately equal only if they have the same length. It
+ * is intended purely for testing purposes.
+ */
+final class EqualLengthApproximateMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    return new Assertion()
+    {
+      public ConditionResult matches(final ByteSequence attributeValue)
+      {
+        return attributeValue.length() == value.length() ? ConditionResult.TRUE
+            : ConditionResult.FALSE;
+      }
+    };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return value.toByteString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FacsimileNumberSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FacsimileNumberSyntaxImpl.java
new file mode 100644
index 0000000..ed8a331
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FacsimileNumberSyntaxImpl.java
@@ -0,0 +1,238 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_FAXNUMBER_NAME;
+
+import java.util.HashSet;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the facsimile telephone number attribute syntax, which
+ * contains a printable string (the number) followed by zero or more parameters.
+ * Those parameters should start with a dollar sign may be any of the following
+ * strings:
+ * <UL>
+ * <LI>twoDimensional</LI>
+ * <LI>fineResolution</LI>
+ * <LI>unlimitedLength</LI>
+ * <LI>b4Length</LI>
+ * <LI>a3Width</LI>
+ * <LI>b4Width</LI>
+ * <LI>uncompressed</LI>
+ * </UL>
+ */
+final class FacsimileNumberSyntaxImpl extends AbstractSyntaxImpl
+{
+  /**
+   * The set of allowed fax parameter values, formatted entirely in lowercase
+   * characters.
+   */
+  public static final HashSet<String> ALLOWED_FAX_PARAMETERS = new HashSet<String>(
+      7);
+
+  static
+  {
+    ALLOWED_FAX_PARAMETERS.add("twodimensional");
+    ALLOWED_FAX_PARAMETERS.add("fineresolution");
+    ALLOWED_FAX_PARAMETERS.add("unlimitedlength");
+    ALLOWED_FAX_PARAMETERS.add("b4length");
+    ALLOWED_FAX_PARAMETERS.add("a3width");
+    ALLOWED_FAX_PARAMETERS.add("b4width");
+    ALLOWED_FAX_PARAMETERS.add("uncompressed");
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_FAXNUMBER_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Get a lowercase string representation of the value and find its
+    // length.
+    final String valueString = toLowerCase(value.toString());
+    final int valueLength = valueString.length();
+
+    // The value must contain at least one character.
+    if (valueLength == 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY.get());
+      return false;
+    }
+
+    // The first character must be a printable string character.
+    char c = valueString.charAt(0);
+    if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE.get(
+          valueString, String.valueOf(c), 0));
+      return false;
+    }
+
+    // Continue reading until we find a dollar sign or the end of the
+    // string. Every intermediate character must be a printable string
+    // character.
+    int pos = 1;
+    for (; pos < valueLength; pos++)
+    {
+      c = valueString.charAt(pos);
+      if (c == '$')
+      {
+        pos++;
+        break;
+      }
+      else
+      {
+        if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE.get(
+              valueString, String.valueOf(c), pos));
+        }
+      }
+    }
+
+    if (pos >= valueLength)
+    {
+      // We're at the end of the value, so it must be valid unless the
+      // last character was a dollar sign.
+      if (c == '$')
+      {
+
+        invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR
+            .get(valueString));
+        return false;
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    // Continue reading until we find the end of the string. Each
+    // substring must be a valid fax parameter.
+    int paramStartPos = pos;
+    while (pos < valueLength)
+    {
+      c = valueString.charAt(pos++);
+      if (c == '$')
+      {
+        final String paramStr = valueString.substring(paramStartPos, pos);
+        if (!ALLOWED_FAX_PARAMETERS.contains(paramStr))
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER.get(
+              valueString, paramStr, paramStartPos, (pos - 1)));
+          return false;
+        }
+
+        paramStartPos = pos;
+      }
+    }
+
+    // We must be at the end of the value. Read the last parameter and
+    // make sure it is valid.
+    final String paramStr = valueString.substring(paramStartPos);
+    if (!ALLOWED_FAX_PARAMETERS.contains(paramStr))
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER.get(
+          valueString, paramStr, paramStartPos, (pos - 1)));
+      return false;
+    }
+
+    // If we've gotten here, then the value must be valid.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FaxSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FaxSyntaxImpl.java
new file mode 100644
index 0000000..5e08a5d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/FaxSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_FAX_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the fax attribute syntax. This should be restricted to
+ * holding only fax message contents, but we will accept any set of bytes. It
+ * will be treated much like the octet string attribute syntax.
+ */
+final class FaxSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_FAX_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the fax syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..32ab6e1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeEqualityMatchingRuleImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * This class defines the generalizedTimeMatch matching rule defined in X.520
+ * and referenced in RFC 2252.
+ */
+final class GeneralizedTimeEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    return ByteString.valueOf(GeneralizedTimeSyntaxImpl
+        .decodeGeneralizedTimeValue(value));
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..7b92d0b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeOrderingMatchingRuleImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * This class defines the generalizedTimeOrderingMatch matching rule defined in
+ * X.520 and referenced in RFC 2252.
+ */
+final class GeneralizedTimeOrderingMatchingRuleImpl extends
+    AbstractOrderingMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    return ByteString.valueOf(GeneralizedTimeSyntaxImpl
+        .decodeGeneralizedTimeValue(value));
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeSyntaxImpl.java
new file mode 100644
index 0000000..08ea880
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GeneralizedTimeSyntaxImpl.java
@@ -0,0 +1,1411 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class implements the fax attribute syntax. This should be restricted to
+ * holding only fax message contents, but we will accept any set of bytes. It
+ * will be treated much like the octet string attribute syntax.
+ */
+final class GeneralizedTimeSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  // UTC TimeZone is assumed to never change over JVM lifetime
+  private static final TimeZone TIME_ZONE_UTC_OBJ = TimeZone
+      .getTimeZone(TIME_ZONE_UTC);
+
+
+
+  /**
+   * Decodes the provided normalized value as a generalized time value and
+   * retrieves a timestamp containing its representation.
+   *
+   * @param value
+   *          The normalized value to decode using the generalized time syntax.
+   * @return The timestamp created from the provided generalized time value.
+   * @throws DecodeException
+   *           If the provided value cannot be parsed as a valid generalized
+   *           time string.
+   */
+  static long decodeGeneralizedTimeValue(final ByteSequence value)
+      throws DecodeException
+  {
+    int year = 0;
+    int month = 0;
+    int day = 0;
+    int hour = 0;
+    int minute = 0;
+    int second = 0;
+
+    // Get the value as a string and verify that it is at least long
+    // enough for "YYYYMMDDhhZ", which is the shortest allowed value.
+    final String valueString = value.toString().toUpperCase();
+    final int length = valueString.length();
+    if (length < 11)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT
+          .get(valueString);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", e);
+      throw e;
+    }
+
+    // The first four characters are the century and year, and they must
+    // be numeric digits between 0 and 9.
+    for (int i = 0; i < 4; i++)
+    {
+      switch (valueString.charAt(i))
+      {
+      case '0':
+        year = year * 10;
+        break;
+
+      case '1':
+        year = year * 10 + 1;
+        break;
+
+      case '2':
+        year = year * 10 + 2;
+        break;
+
+      case '3':
+        year = year * 10 + 3;
+        break;
+
+      case '4':
+        year = year * 10 + 4;
+        break;
+
+      case '5':
+        year = year * 10 + 5;
+        break;
+
+      case '6':
+        year = year * 10 + 6;
+        break;
+
+      case '7':
+        year = year * 10 + 7;
+        break;
+
+      case '8':
+        year = year * 10 + 8;
+        break;
+
+      case '9':
+        year = year * 10 + 9;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR
+            .get(valueString, String.valueOf(valueString.charAt(i)));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+    }
+
+    // The next two characters are the month, and they must form the
+    // string representation of an integer between 01 and 12.
+    char m1 = valueString.charAt(4);
+    final char m2 = valueString.charAt(5);
+    switch (m1)
+    {
+    case '0':
+      // m2 must be a digit between 1 and 9.
+      switch (m2)
+      {
+      case '1':
+        month = Calendar.JANUARY;
+        break;
+
+      case '2':
+        month = Calendar.FEBRUARY;
+        break;
+
+      case '3':
+        month = Calendar.MARCH;
+        break;
+
+      case '4':
+        month = Calendar.APRIL;
+        break;
+
+      case '5':
+        month = Calendar.MAY;
+        break;
+
+      case '6':
+        month = Calendar.JUNE;
+        break;
+
+      case '7':
+        month = Calendar.JULY;
+        break;
+
+      case '8':
+        month = Calendar.AUGUST;
+        break;
+
+      case '9':
+        month = Calendar.SEPTEMBER;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH
+            .get(valueString, valueString.substring(4, 6));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+    case '1':
+      // m2 must be a digit between 0 and 2.
+      switch (m2)
+      {
+      case '0':
+        month = Calendar.OCTOBER;
+        break;
+
+      case '1':
+        month = Calendar.NOVEMBER;
+        break;
+
+      case '2':
+        month = Calendar.DECEMBER;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH
+            .get(valueString, valueString.substring(4, 6));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH
+          .get(valueString, valueString.substring(4, 6));
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", e);
+      throw e;
+    }
+
+    // The next two characters should be the day of the month, and they
+    // must form the string representation of an integer between 01 and
+    // 31. This doesn't do any validation against the year or month, so
+    // it will allow dates like April 31, or February 29 in a non-leap
+    // year, but we'll let those slide.
+    final char d1 = valueString.charAt(6);
+    final char d2 = valueString.charAt(7);
+    switch (d1)
+    {
+    case '0':
+      // d2 must be a digit between 1 and 9.
+      switch (d2)
+      {
+      case '1':
+        day = 1;
+        break;
+
+      case '2':
+        day = 2;
+        break;
+
+      case '3':
+        day = 3;
+        break;
+
+      case '4':
+        day = 4;
+        break;
+
+      case '5':
+        day = 5;
+        break;
+
+      case '6':
+        day = 6;
+        break;
+
+      case '7':
+        day = 7;
+        break;
+
+      case '8':
+        day = 8;
+        break;
+
+      case '9':
+        day = 9;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY
+            .get(valueString, valueString.substring(6, 8));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+
+    case '1':
+      // d2 must be a digit between 0 and 9.
+      switch (d2)
+      {
+      case '0':
+        day = 10;
+        break;
+
+      case '1':
+        day = 11;
+        break;
+
+      case '2':
+        day = 12;
+        break;
+
+      case '3':
+        day = 13;
+        break;
+
+      case '4':
+        day = 14;
+        break;
+
+      case '5':
+        day = 15;
+        break;
+
+      case '6':
+        day = 16;
+        break;
+
+      case '7':
+        day = 17;
+        break;
+
+      case '8':
+        day = 18;
+        break;
+
+      case '9':
+        day = 19;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY
+            .get(valueString, valueString.substring(6, 8));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+
+    case '2':
+      // d2 must be a digit between 0 and 9.
+      switch (d2)
+      {
+      case '0':
+        day = 20;
+        break;
+
+      case '1':
+        day = 21;
+        break;
+
+      case '2':
+        day = 22;
+        break;
+
+      case '3':
+        day = 23;
+        break;
+
+      case '4':
+        day = 24;
+        break;
+
+      case '5':
+        day = 25;
+        break;
+
+      case '6':
+        day = 26;
+        break;
+
+      case '7':
+        day = 27;
+        break;
+
+      case '8':
+        day = 28;
+        break;
+
+      case '9':
+        day = 29;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY
+            .get(valueString, valueString.substring(6, 8));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+
+    case '3':
+      // d2 must be either 0 or 1.
+      switch (d2)
+      {
+      case '0':
+        day = 30;
+        break;
+
+      case '1':
+        day = 31;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY
+            .get(valueString, valueString.substring(6, 8));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY
+          .get(valueString, valueString.substring(6, 8));
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", e);
+      throw e;
+    }
+
+    // The next two characters must be the hour, and they must form the
+    // string representation of an integer between 00 and 23.
+    final char h1 = valueString.charAt(8);
+    final char h2 = valueString.charAt(9);
+    switch (h1)
+    {
+    case '0':
+      switch (h2)
+      {
+      case '0':
+        hour = 0;
+        break;
+
+      case '1':
+        hour = 1;
+        break;
+
+      case '2':
+        hour = 2;
+        break;
+
+      case '3':
+        hour = 3;
+        break;
+
+      case '4':
+        hour = 4;
+        break;
+
+      case '5':
+        hour = 5;
+        break;
+
+      case '6':
+        hour = 6;
+        break;
+
+      case '7':
+        hour = 7;
+        break;
+
+      case '8':
+        hour = 8;
+        break;
+
+      case '9':
+        hour = 9;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR
+            .get(valueString, valueString.substring(8, 10));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+
+    case '1':
+      switch (h2)
+      {
+      case '0':
+        hour = 10;
+        break;
+
+      case '1':
+        hour = 11;
+        break;
+
+      case '2':
+        hour = 12;
+        break;
+
+      case '3':
+        hour = 13;
+        break;
+
+      case '4':
+        hour = 14;
+        break;
+
+      case '5':
+        hour = 15;
+        break;
+
+      case '6':
+        hour = 16;
+        break;
+
+      case '7':
+        hour = 17;
+        break;
+
+      case '8':
+        hour = 18;
+        break;
+
+      case '9':
+        hour = 19;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR
+            .get(valueString, valueString.substring(8, 10));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+
+    case '2':
+      switch (h2)
+      {
+      case '0':
+        hour = 20;
+        break;
+
+      case '1':
+        hour = 21;
+        break;
+
+      case '2':
+        hour = 22;
+        break;
+
+      case '3':
+        hour = 23;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR
+            .get(valueString, valueString.substring(8, 10));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      break;
+
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR
+          .get(valueString, valueString.substring(8, 10));
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", e);
+      throw e;
+    }
+
+    // Next, there should be either two digits comprising an integer
+    // between 00 and 59 (for the minute), a letter 'Z' (for the UTC
+    // specifier), a plus or minus sign followed by two or four digits
+    // (for the UTC offset), or a period or comma representing the
+    // fraction.
+    m1 = valueString.charAt(10);
+    switch (m1)
+    {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+      // There must be at least two more characters, and the next one
+      // must be a digit between 0 and 9.
+      if (length < 13)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(m1), 10);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      minute = 10 * (m1 - '0');
+
+      switch (valueString.charAt(11))
+      {
+      case '0':
+        break;
+
+      case '1':
+        minute += 1;
+        break;
+
+      case '2':
+        minute += 2;
+        break;
+
+      case '3':
+        minute += 3;
+        break;
+
+      case '4':
+        minute += 4;
+        break;
+
+      case '5':
+        minute += 5;
+        break;
+
+      case '6':
+        minute += 6;
+        break;
+
+      case '7':
+        minute += 7;
+        break;
+
+      case '8':
+        minute += 8;
+        break;
+
+      case '9':
+        minute += 9;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE
+            .get(valueString, valueString.substring(10, 12));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      break;
+
+    case 'Z':
+      // This is fine only if we are at the end of the value.
+      if (length == 11)
+      {
+        try
+        {
+          final GregorianCalendar calendar = new GregorianCalendar();
+          calendar.setLenient(false);
+          calendar.setTimeZone(TIME_ZONE_UTC_OBJ);
+          calendar.set(year, month, day, hour, minute, second);
+          calendar.set(Calendar.MILLISECOND, 0);
+          return calendar.getTimeInMillis();
+        }
+        catch (final Exception e)
+        {
+          // This should only happen if the provided date wasn't legal
+          // (e.g., September 31).
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME
+              .get(valueString, String.valueOf(e));
+          final DecodeException de = DecodeException.error(message, e);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "valueIsAcceptable", de);
+          throw de;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(m1), 10);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+    case '+':
+    case '-':
+      // These are fine only if there are exactly two or four more
+      // digits that specify a valid offset.
+      if (length == 13 || length == 15)
+      {
+        try
+        {
+          final GregorianCalendar calendar = new GregorianCalendar();
+          calendar.setLenient(false);
+          calendar.setTimeZone(getTimeZoneForOffset(valueString, 10));
+          calendar.set(year, month, day, hour, minute, second);
+          calendar.set(Calendar.MILLISECOND, 0);
+          return calendar.getTimeInMillis();
+        }
+        catch (final Exception e)
+        {
+
+          // This should only happen if the provided date wasn't legal
+          // (e.g., September 31).
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME
+              .get(valueString, String.valueOf(e));
+          final DecodeException de = DecodeException.error(message, e);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "valueIsAcceptable", de);
+          throw de;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(m1), 10);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+    case '.':
+    case ',':
+      return finishDecodingFraction(valueString, 11, year, month, day, hour,
+          minute, second, 3600000);
+
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+          .get(valueString, String.valueOf(m1), 10);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", e);
+      throw e;
+    }
+
+    // Next, there should be either two digits comprising an integer
+    // between 00 and 60 (for the second, including a possible leap
+    // second), a letter 'Z' (for the UTC specifier), a plus or minus
+    // sign followed by two or four digits (for the UTC offset), or a
+    // period or comma to start the fraction.
+    final char s1 = valueString.charAt(12);
+    switch (s1)
+    {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+      // There must be at least two more characters, and the next one
+      // must be a digit between 0 and 9.
+      if (length < 15)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 12);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      second = 10 * (s1 - '0');
+
+      switch (valueString.charAt(13))
+      {
+      case '0':
+        break;
+
+      case '1':
+        second += 1;
+        break;
+
+      case '2':
+        second += 2;
+        break;
+
+      case '3':
+        second += 3;
+        break;
+
+      case '4':
+        second += 4;
+        break;
+
+      case '5':
+        second += 5;
+        break;
+
+      case '6':
+        second += 6;
+        break;
+
+      case '7':
+        second += 7;
+        break;
+
+      case '8':
+        second += 8;
+        break;
+
+      case '9':
+        second += 9;
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE
+            .get(valueString, valueString.substring(12, 14));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      break;
+
+    case '6':
+      // There must be at least two more characters and the next one
+      // must be a 0.
+      if (length < 15)
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 12);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      if (valueString.charAt(13) != '0')
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND
+            .get(valueString, valueString.substring(12, 14));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      second = 60;
+      break;
+
+    case 'Z':
+      // This is fine only if we are at the end of the value.
+      if (length == 13)
+      {
+        try
+        {
+          final GregorianCalendar calendar = new GregorianCalendar();
+          calendar.setLenient(false);
+          calendar.setTimeZone(TIME_ZONE_UTC_OBJ);
+          calendar.set(year, month, day, hour, minute, second);
+          calendar.set(Calendar.MILLISECOND, 0);
+          return calendar.getTimeInMillis();
+        }
+        catch (final Exception e)
+        {
+
+          // This should only happen if the provided date wasn't legal
+          // (e.g., September 31).
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME
+              .get(valueString, String.valueOf(e));
+          final DecodeException de = DecodeException.error(message, e);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "valueIsAcceptable", de);
+          throw de;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 12);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+    case '+':
+    case '-':
+      // These are fine only if there are exactly two or four more
+      // digits that specify a valid offset.
+      if (length == 15 || length == 17)
+      {
+        try
+        {
+          final GregorianCalendar calendar = new GregorianCalendar();
+          calendar.setLenient(false);
+          calendar.setTimeZone(getTimeZoneForOffset(valueString, 12));
+          calendar.set(year, month, day, hour, minute, second);
+          calendar.set(Calendar.MILLISECOND, 0);
+          return calendar.getTimeInMillis();
+        }
+        catch (final Exception e)
+        {
+
+          // This should only happen if the provided date wasn't legal
+          // (e.g., September 31).
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME
+              .get(valueString, String.valueOf(e));
+          final DecodeException de = DecodeException.error(message, e);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "valueIsAcceptable", de);
+          throw de;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 12);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+    case '.':
+    case ',':
+      return finishDecodingFraction(valueString, 13, year, month, day, hour,
+          minute, second, 60000);
+
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+          .get(valueString, String.valueOf(s1), 12);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", e);
+      throw e;
+    }
+
+    // Next, there should be either a period or comma followed by
+    // between one and three digits (to specify the sub-second), a
+    // letter 'Z' (for the UTC specifier), or a plus or minus sign
+    // followed by two our four digits (for the UTC offset).
+    switch (valueString.charAt(14))
+    {
+    case '.':
+    case ',':
+      return finishDecodingFraction(valueString, 15, year, month, day, hour,
+          minute, second, 1000);
+
+    case 'Z':
+      // This is fine only if we are at the end of the value.
+      if (length == 15)
+      {
+        try
+        {
+          final GregorianCalendar calendar = new GregorianCalendar();
+          calendar.setLenient(false);
+          calendar.setTimeZone(TIME_ZONE_UTC_OBJ);
+          calendar.set(year, month, day, hour, minute, second);
+          calendar.set(Calendar.MILLISECOND, 0);
+          return calendar.getTimeInMillis();
+        }
+        catch (final Exception e)
+        {
+          // This should only happen if the provided date wasn't legal
+          // (e.g., September 31).
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME
+              .get(valueString, String.valueOf(e));
+          final DecodeException de = DecodeException.error(message, e);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "valueIsAcceptable", de);
+          throw de;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(valueString.charAt(14)), 14);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+    case '+':
+    case '-':
+      // These are fine only if there are exactly two or four more
+      // digits that specify a valid offset.
+      if (length == 17 || length == 19)
+      {
+        try
+        {
+          final GregorianCalendar calendar = new GregorianCalendar();
+          calendar.setLenient(false);
+          calendar.setTimeZone(getTimeZoneForOffset(valueString, 14));
+          calendar.set(year, month, day, hour, minute, second);
+          calendar.set(Calendar.MILLISECOND, 0);
+          return calendar.getTimeInMillis();
+        }
+        catch (final Exception e)
+        {
+          // This should only happen if the provided date wasn't legal
+          // (e.g., September 31).
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME
+              .get(valueString, String.valueOf(e));
+          final DecodeException de = DecodeException.error(message, e);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "valueIsAcceptable", de);
+          throw de;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(valueString.charAt(14)), 14);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR
+          .get(valueString, String.valueOf(valueString.charAt(14)), 14);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", e);
+      throw e;
+    }
+  }
+
+
+
+  /**
+   * Completes decoding the generalized time value containing a fractional
+   * component. It will also decode the trailing 'Z' or offset.
+   *
+   * @param value
+   *          The whole value, including the fractional component and time zone
+   *          information.
+   * @param startPos
+   *          The position of the first character after the period in the value
+   *          string.
+   * @param year
+   *          The year decoded from the provided value.
+   * @param month
+   *          The month decoded from the provided value.
+   * @param day
+   *          The day decoded from the provided value.
+   * @param hour
+   *          The hour decoded from the provided value.
+   * @param minute
+   *          The minute decoded from the provided value.
+   * @param second
+   *          The second decoded from the provided value.
+   * @param multiplier
+   *          The multiplier value that should be used to scale the fraction
+   *          appropriately. If it's a fraction of an hour, then it should be
+   *          3600000 (60*60*1000). If it's a fraction of a minute, then it
+   *          should be 60000. If it's a fraction of a second, then it should be
+   *          1000.
+   * @return The timestamp created from the provided generalized time value
+   *         including the fractional element.
+   * @throws DecodeException
+   *           If the provided value cannot be parsed as a valid generalized
+   *           time string.
+   */
+  private static long finishDecodingFraction(final String value,
+      final int startPos, final int year, final int month, final int day,
+      final int hour, final int minute, final int second, final int multiplier)
+      throws DecodeException
+  {
+    final int length = value.length();
+    final StringBuilder fractionBuffer = new StringBuilder(2 + length
+        - startPos);
+    fractionBuffer.append("0.");
+
+    TimeZone timeZone = null;
+
+    outerLoop: for (int i = startPos; i < length; i++)
+    {
+      final char c = value.charAt(i);
+      switch (c)
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        fractionBuffer.append(c);
+        break;
+
+      case 'Z':
+        // This is only acceptable if we're at the end of the value.
+        if (i != value.length() - 1)
+        {
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR
+              .get(value, String.valueOf(c));
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "finishDecodingFraction", e);
+          throw e;
+        }
+
+        timeZone = TIME_ZONE_UTC_OBJ;
+        break outerLoop;
+
+      case '+':
+      case '-':
+        timeZone = getTimeZoneForOffset(value, i);
+        break outerLoop;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR
+            .get(value, String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "finishDecodingFraction", e);
+        throw e;
+      }
+    }
+
+    if (fractionBuffer.length() == 2)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION
+          .get(value);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "finishDecodingFraction", e);
+      throw e;
+    }
+
+    if (timeZone == null)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO
+          .get(value);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "finishDecodingFraction", e);
+      throw e;
+    }
+
+    final Double fractionValue = Double.parseDouble(fractionBuffer.toString());
+    final long additionalMilliseconds = Math.round(fractionValue * multiplier);
+
+    try
+    {
+      final GregorianCalendar calendar = new GregorianCalendar();
+      calendar.setLenient(false);
+      calendar.setTimeZone(timeZone);
+      calendar.set(year, month, day, hour, minute, second);
+      calendar.set(Calendar.MILLISECOND, 0);
+      return calendar.getTimeInMillis() + additionalMilliseconds;
+    }
+    catch (final Exception e)
+    {
+
+      // This should only happen if the provided date wasn't legal
+      // (e.g., September 31).
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME
+          .get(value, String.valueOf(e));
+      final DecodeException de = DecodeException.error(message, e);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "valueIsAcceptable", de);
+      throw de;
+    }
+  }
+
+
+
+  /**
+   * Decodes a time zone offset from the provided value.
+   *
+   * @param value
+   *          The whole value, including the offset.
+   * @param startPos
+   *          The position of the first character that is contained in the
+   *          offset. This should be the position of the plus or minus
+   *          character.
+   * @return The {@code TimeZone} object representing the decoded time zone.
+   * @throws DecodeException
+   *           If the provided value does not contain a valid offset.
+   */
+  private static TimeZone getTimeZoneForOffset(final String value,
+      final int startPos) throws DecodeException
+  {
+    final String offSetStr = value.substring(startPos);
+    if (offSetStr.length() != 3 && offSetStr.length() != 5)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET
+          .get(value, offSetStr);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "getTimeZoneForOffset", e);
+      throw e;
+    }
+
+    // The first character must be either a plus or minus.
+    switch (offSetStr.charAt(0))
+    {
+    case '+':
+    case '-':
+      // These are OK.
+      break;
+
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET
+          .get(value, offSetStr);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "getTimeZoneForOffset", e);
+      throw e;
+    }
+
+    // The first two characters must be an integer between 00 and 23.
+    switch (offSetStr.charAt(1))
+    {
+    case '0':
+    case '1':
+      switch (offSetStr.charAt(2))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET
+            .get(value, offSetStr);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "getTimeZoneForOffset", e);
+        throw e;
+      }
+      break;
+
+    case '2':
+      switch (offSetStr.charAt(2))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+        // These are all fine.
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET
+            .get(value, offSetStr);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "getTimeZoneForOffset", e);
+        throw e;
+      }
+      break;
+
+    default:
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET
+          .get(value, offSetStr);
+      final DecodeException e = DecodeException.error(message);
+      StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+          "getTimeZoneForOffset", e);
+      throw e;
+    }
+
+    // If there are two more characters, then they must be an integer
+    // between 00 and 59.
+    if (offSetStr.length() == 5)
+    {
+      switch (offSetStr.charAt(3))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+        switch (offSetStr.charAt(4))
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+          // These are all fine.
+          break;
+
+        default:
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET
+              .get(value, offSetStr);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+              "getTimeZoneForOffset", e);
+          throw e;
+        }
+        break;
+
+      default:
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET
+            .get(value, offSetStr);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("GeneralizedTimeSyntax",
+            "getTimeZoneForOffset", e);
+        throw e;
+      }
+    }
+
+    // If we've gotten here, then it looks like a valid offset. We can
+    // create a time zone by using "GMT" followed by the offset.
+    return TimeZone.getTimeZone("GMT" + offSetStr);
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_GENERALIZED_TIME_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_GENERALIZED_TIME_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_GENERALIZED_TIME_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    try
+    {
+      decodeGeneralizedTimeValue(value);
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GenerateCoreSchema.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GenerateCoreSchema.java
new file mode 100644
index 0000000..9e2db8c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GenerateCoreSchema.java
@@ -0,0 +1,407 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import java.util.*;
+
+
+
+/**
+ * Tool for generating CoreSchema.java.
+ */
+final class GenerateCoreSchema
+{
+  private static final Set<String> ABBREVIATIONS = new HashSet<String>(Arrays
+      .asList("SASL", "LDAP", "DN", "DIT", "RDN", "JPEG", "OID", "UUID", "IA5",
+          "UID", "UTC", "X500", "X121", "C", "CN", "O", "OU", "L", "DC",
+          "ISDN", "SN", "ST"));
+
+
+
+  /**
+   * Tool for generating CoreSchema.java.
+   *
+   * @param args
+   *          The command line arguments (none required).
+   */
+  public static void main(final String[] args)
+  {
+    testSplitNameIntoWords();
+
+    final Schema schema = Schema.getCoreSchema();
+
+    final SortedMap<String, Syntax> syntaxes = new TreeMap<String, Syntax>();
+    for (final Syntax syntax : schema.getSyntaxes())
+    {
+      if (isOpenDSOID(syntax.getOID()))
+      {
+        continue;
+      }
+
+      final String name = syntax.getDescription().replaceAll(" Syntax$", "");
+      final String fieldName = name.replace(" ", "_").toUpperCase(
+          Locale.ENGLISH).concat("_SYNTAX");
+      syntaxes.put(fieldName, syntax);
+    }
+
+    final SortedMap<String, MatchingRule> matchingRules = new TreeMap<String, MatchingRule>();
+    for (final MatchingRule matchingRule : schema.getMatchingRules())
+    {
+      if (isOpenDSOID(matchingRule.getOID()))
+      {
+        continue;
+      }
+
+      final String name = matchingRule.getNameOrOID().replaceAll("Match$", "");
+      final String fieldName = splitNameIntoWords(name)
+          .concat("_MATCHING_RULE");
+      matchingRules.put(fieldName, matchingRule);
+    }
+
+    final SortedMap<String, AttributeType> attributeTypes = new TreeMap<String, AttributeType>();
+    for (final AttributeType attributeType : schema.getAttributeTypes())
+    {
+      if (isOpenDSOID(attributeType.getOID()))
+      {
+        continue;
+      }
+      final String name = attributeType.getNameOrOID();
+      final String fieldName = splitNameIntoWords(name).concat(
+          "_ATTRIBUTE_TYPE");
+      attributeTypes.put(fieldName, attributeType);
+    }
+
+    final SortedMap<String, ObjectClass> objectClasses = new TreeMap<String, ObjectClass>();
+    for (final ObjectClass objectClass : schema.getObjectClasses())
+    {
+      if (isOpenDSOID(objectClass.getOID()))
+      {
+        continue;
+      }
+      final String name = objectClass.getNameOrOID();
+      final String fieldName = splitNameIntoWords(name).concat("_OBJECT_CLASS");
+
+      objectClasses.put(fieldName, objectClass);
+    }
+
+    System.out.println();
+    System.out.println();
+    System.out.println();
+    System.out.println("package org.opends.sdk.schema;");
+    System.out.println();
+    System.out.println();
+    System.out.println();
+    System.out.println("/**");
+    System.out.println(" * The OpenDS SDK core schema contains standard LDAP "
+        + "RFC schema elements. These include:");
+    System.out.println(" * <ul>");
+    System.out
+        .println(" * <li><a href=\"http://tools.ietf.org/html/rfc4512\">RFC 4512 -");
+    System.out
+        .println(" * Lightweight Directory Access Protocol (LDAP): Directory Information");
+    System.out.println(" * Models </a>");
+    System.out
+        .println(" * <li><a href=\"http://tools.ietf.org/html/rfc4517\">RFC 4517 -");
+    System.out
+        .println(" * Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching");
+    System.out.println(" * Rules </a>");
+    System.out
+        .println(" * <li><a href=\"http://tools.ietf.org/html/rfc4519\">RFC 4519 -");
+    System.out
+        .println(" * Lightweight Directory Access Protocol (LDAP): Schema for User");
+    System.out.println(" * Applications </a>");
+    System.out
+        .println(" * <li><a href=\"http://tools.ietf.org/html/rfc4530\">RFC 4530 -");
+    System.out
+        .println(" * Lightweight Directory Access Protocol (LDAP): entryUUID Operational");
+    System.out.println(" * Attribute </a>");
+    System.out
+        .println(" * <li><a href=\"http://tools.ietf.org/html/rfc3045\">RFC 3045 - Storing");
+    System.out.println(" * Vendor Information in the LDAP Root DSE </a>");
+    System.out
+        .println(" * <li><a href=\"http://tools.ietf.org/html/rfc3112\">RFC 3112 - LDAP");
+    System.out.println(" * Authentication Password Schema </a>");
+    System.out.println(" * </ul>");
+    System.out.println(" * <p>");
+    System.out
+        .println(" * The core schema is non-strict: attempts to retrieve");
+    System.out
+        .println(" * non-existent Attribute Types will return a temporary");
+    System.out.println(" * Attribute Type having the Octet String syntax.");
+    System.out.println(" */");
+    System.out.println("public final class CoreSchema");
+    System.out.println("{");
+
+    System.out.println("  // Core Syntaxes");
+    for (final Map.Entry<String, Syntax> syntax : syntaxes.entrySet())
+    {
+      System.out.println("  private static final Syntax " + syntax.getKey()
+          + " =");
+      System.out.println("    CoreSchemaImpl.getInstance().getSyntax(\""
+          + syntax.getValue().getOID() + "\");");
+    }
+
+    System.out.println();
+    System.out.println("  // Core Matching Rules");
+    for (final Map.Entry<String, MatchingRule> matchingRule : matchingRules
+        .entrySet())
+    {
+      System.out.println("  private static final MatchingRule "
+          + matchingRule.getKey() + " =");
+      System.out.println("    CoreSchemaImpl.getInstance().getMatchingRule(\""
+          + matchingRule.getValue().getOID() + "\");");
+    }
+
+    System.out.println();
+    System.out.println("  // Core Attribute Types");
+    for (final Map.Entry<String, AttributeType> attributeType : attributeTypes
+        .entrySet())
+    {
+      System.out.println("  private static final AttributeType "
+          + attributeType.getKey() + " =");
+      System.out.println("    CoreSchemaImpl.getInstance().getAttributeType(\""
+          + attributeType.getValue().getOID() + "\");");
+    }
+
+    System.out.println();
+    System.out.println("  // Core Object Classes");
+    for (final Map.Entry<String, ObjectClass> objectClass : objectClasses
+        .entrySet())
+    {
+      System.out.println("  private static final ObjectClass "
+          + objectClass.getKey() + " =");
+      System.out.println("    CoreSchemaImpl.getInstance().getObjectClass(\""
+          + objectClass.getValue().getOID() + "\");");
+    }
+
+    System.out.println();
+    System.out.println();
+    System.out.println();
+    System.out.println("  // Prevent instantiation");
+    System.out.println("  private CoreSchema()");
+    System.out.println("  {");
+    System.out.println("    // Nothing to do.");
+    System.out.println("  }");
+
+    System.out.println();
+    System.out.println();
+    System.out.println();
+    System.out.println("  /**");
+    System.out
+        .println("   * Returns a reference to the singleton core schema.");
+    System.out.println("   *");
+    System.out.println("   * @return The core schema.");
+    System.out.println("   */");
+    System.out.println("  public static Schema getInstance()");
+    System.out.println("  {");
+    System.out.println("    return CoreSchemaImpl.getInstance();");
+    System.out.println("  }");
+
+    for (final Map.Entry<String, Syntax> syntax : syntaxes.entrySet())
+    {
+      System.out.println();
+      System.out.println();
+      System.out.println();
+
+      final String description = toCodeJavaDoc(syntax.getValue()
+          .getDescription().replaceAll(" Syntax$", "")
+          + " Syntax");
+      System.out.println("  /**");
+      System.out.println("   * Returns a reference to the " + description);
+      System.out.println("   * which has the OID "
+          + toCodeJavaDoc(syntax.getValue().getOID()) + ".");
+      System.out.println("   *");
+      System.out
+          .println("   * @return A reference to the " + description + ".");
+
+      System.out.println("   */");
+      System.out.println("  public static Syntax get"
+          + toJavaName(syntax.getKey()) + "()");
+      System.out.println("  {");
+      System.out.println("    return " + syntax.getKey() + ";");
+      System.out.println("  }");
+    }
+
+    for (final Map.Entry<String, MatchingRule> matchingRule : matchingRules
+        .entrySet())
+    {
+      System.out.println();
+      System.out.println();
+      System.out.println();
+
+      final String description = toCodeJavaDoc(matchingRule.getValue()
+          .getNameOrOID());
+      System.out.println("  /**");
+      System.out.println("   * Returns a reference to the " + description
+          + " Matching Rule");
+      System.out.println("   * which has the OID "
+          + toCodeJavaDoc(matchingRule.getValue().getOID()) + ".");
+      System.out.println("   *");
+      System.out.println("   * @return A reference to the " + description
+          + " Matching Rule.");
+
+      System.out.println("   */");
+      System.out.println("  public static MatchingRule get"
+          + toJavaName(matchingRule.getKey()) + "()");
+      System.out.println("  {");
+      System.out.println("    return " + matchingRule.getKey() + ";");
+      System.out.println("  }");
+    }
+
+    for (final Map.Entry<String, AttributeType> attributeType : attributeTypes
+        .entrySet())
+    {
+      System.out.println();
+      System.out.println();
+      System.out.println();
+
+      final String description = toCodeJavaDoc(attributeType.getValue()
+          .getNameOrOID());
+      System.out.println("  /**");
+      System.out.println("   * Returns a reference to the " + description
+          + " Attribute Type");
+      System.out.println("   * which has the OID "
+          + toCodeJavaDoc(attributeType.getValue().getOID()) + ".");
+      System.out.println("   *");
+      System.out.println("   * @return A reference to the " + description
+          + " Attribute Type.");
+
+      System.out.println("   */");
+      System.out.println("  public static AttributeType get"
+          + toJavaName(attributeType.getKey()) + "()");
+      System.out.println("  {");
+      System.out.println("    return " + attributeType.getKey() + ";");
+      System.out.println("  }");
+    }
+
+    for (final Map.Entry<String, ObjectClass> objectClass : objectClasses
+        .entrySet())
+    {
+      System.out.println();
+      System.out.println();
+      System.out.println();
+
+      final String description = toCodeJavaDoc(objectClass.getValue()
+          .getNameOrOID());
+      System.out.println("  /**");
+      System.out.println("   * Returns a reference to the " + description
+          + " Object Class");
+      System.out.println("   * which has the OID "
+          + toCodeJavaDoc(objectClass.getValue().getOID()) + ".");
+      System.out.println("   *");
+      System.out.println("   * @return A reference to the " + description
+          + " Object Class.");
+
+      System.out.println("   */");
+      System.out.println("  public static ObjectClass get"
+          + toJavaName(objectClass.getKey()) + "()");
+      System.out.println("  {");
+      System.out.println("    return " + objectClass.getKey() + ";");
+      System.out.println("  }");
+    }
+
+    System.out.println("}");
+  }
+
+
+
+  private static boolean isOpenDSOID(final String oid)
+  {
+    return oid.startsWith(SchemaConstants.OID_OPENDS_SERVER_BASE + ".");
+  }
+
+
+
+  private static String splitNameIntoWords(final String name)
+  {
+    String splitName = name.replaceAll("([A-Z][a-z])", "_$1");
+    splitName = splitName.replaceAll("([a-z])([A-Z])", "$1_$2");
+
+    return splitName.toUpperCase(Locale.ENGLISH);
+  }
+
+
+
+  private static void testSplitNameIntoWords()
+  {
+    final String[][] values = new String[][] {
+        { "oneTwoThree", "ONE_TWO_THREE" }, { "oneTWOThree", "ONE_TWO_THREE" },
+        { "oneX500Three", "ONE_X500_THREE" }, { "oneTwoX500", "ONE_TWO_X500" },
+        { "oneTwoX500", "ONE_TWO_X500" }, { "x500TwoThree", "X500_TWO_THREE" }, };
+
+    for (final String[] test : values)
+    {
+      final String actual = splitNameIntoWords(test[0]);
+      final String expected = test[1];
+      if (!actual.equals(expected))
+      {
+        System.out.println("Test Split Failure: " + test[0] + " -> " + actual
+            + " != " + expected);
+      }
+    }
+  }
+
+
+
+  private static String toCodeJavaDoc(final String text)
+  {
+    return String.format("{@code %s}", text);
+  }
+
+
+
+  private static String toJavaName(final String splitName)
+  {
+    final StringBuilder builder = new StringBuilder();
+    for (final String word : splitName.split("_"))
+    {
+      if (ABBREVIATIONS.contains(word))
+      {
+        builder.append(word);
+      }
+      else
+      {
+        builder.append(word.charAt(0));
+        if (word.length() > 1)
+        {
+          builder.append(word.substring(1).toLowerCase(Locale.ENGLISH));
+        }
+      }
+    }
+    return builder.toString();
+  }
+
+
+
+  private GenerateCoreSchema()
+  {
+    // Prevent instantiation.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GuideSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GuideSyntaxImpl.java
new file mode 100644
index 0000000..09c3ed8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/GuideSyntaxImpl.java
@@ -0,0 +1,427 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_GUIDE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the guide attribute syntax, which may be used to
+ * provide criteria for generating search filters for entries, optionally tied
+ * to a specified objectclass.
+ */
+final class GuideSyntaxImpl extends AbstractSyntaxImpl
+{
+  /**
+   * Determines whether the provided string represents a valid criteria
+   * according to the guide syntax.
+   *
+   * @param criteria
+   *          The portion of the criteria for which to make the determination.
+   * @param valueStr
+   *          The complete guide value provided by the client.
+   * @param invalidReason
+   *          The buffer to which to append the reason that the criteria is
+   *          invalid if a problem is found.
+   * @return <CODE>true</CODE> if the provided string does contain a valid
+   *         criteria, or <CODE>false</CODE> if not.
+   */
+  static boolean criteriaIsValid(final String criteria, final String valueStr,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    // See if the criteria starts with a '!'. If so, then just evaluate
+    // everything after that as a criteria.
+    char c = criteria.charAt(0);
+    if (c == '!')
+    {
+      return criteriaIsValid(criteria.substring(1), valueStr, invalidReason);
+    }
+
+    // See if the criteria starts with a '('. If so, then find the
+    // corresponding ')' and parse what's in between as a criteria.
+    if (c == '(')
+    {
+      final int length = criteria.length();
+      int depth = 1;
+
+      for (int i = 1; i < length; i++)
+      {
+        c = criteria.charAt(i);
+        if (c == ')')
+        {
+          depth--;
+          if (depth == 0)
+          {
+            final String subCriteria = criteria.substring(1, i);
+            if (!criteriaIsValid(subCriteria, valueStr, invalidReason))
+            {
+              return false;
+            }
+
+            // If we are at the end of the value, then it was valid.
+            // Otherwise, the next character must be a pipe or an
+            // ampersand followed by another set of criteria.
+            if (i == length - 1)
+            {
+              return true;
+            }
+            else
+            {
+              c = criteria.charAt(i + 1);
+              if (c == '|' || c == '&')
+              {
+                return criteriaIsValid(criteria.substring(i + 2), valueStr,
+                    invalidReason);
+              }
+              else
+              {
+
+                invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR.get(
+                    valueStr, criteria, c, (i + 1)));
+                return false;
+              }
+            }
+          }
+        }
+        else if (c == '(')
+        {
+          depth++;
+        }
+      }
+
+      // If we've gotten here, then we went through the entire value
+      // without finding the appropriate closing parenthesis.
+
+      invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN.get(
+          valueStr, criteria));
+      return false;
+    }
+
+    // See if the criteria starts with a '?'. If so, then it must be
+    // either "?true" or "?false".
+    if (c == '?')
+    {
+      if (criteria.startsWith("?true"))
+      {
+        if (criteria.length() == 5)
+        {
+          return true;
+        }
+        else
+        {
+          // The only characters allowed next are a pipe or an
+          // ampersand.
+          c = criteria.charAt(5);
+          if (c == '|' || c == '&')
+          {
+            return criteriaIsValid(criteria.substring(6), valueStr,
+                invalidReason);
+          }
+          else
+          {
+            invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR.get(
+                valueStr, criteria, c, 5));
+            return false;
+          }
+        }
+      }
+      else if (criteria.startsWith("?false"))
+      {
+        if (criteria.length() == 6)
+        {
+          return true;
+        }
+        else
+        {
+          // The only characters allowed next are a pipe or an
+          // ampersand.
+          c = criteria.charAt(6);
+          if (c == '|' || c == '&')
+          {
+            return criteriaIsValid(criteria.substring(7), valueStr,
+                invalidReason);
+          }
+          else
+          {
+            invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR.get(
+                valueStr, criteria, c, 6));
+            return false;
+          }
+        }
+      }
+      else
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK.get(
+            valueStr, criteria));
+        return false;
+      }
+    }
+
+    // See if the criteria is either "true" or "false". If so, then it
+    // is valid.
+    if (criteria.equals("true") || criteria.equals("false"))
+    {
+      return true;
+    }
+
+    // The only thing that will be allowed is an attribute type name or
+    // OID followed by a dollar sign and a match type. Find the dollar
+    // sign and verify whether the value before it is a valid attribute
+    // type name or OID.
+    final int dollarPos = criteria.indexOf('$');
+    if (dollarPos < 0)
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR.get(valueStr,
+          criteria));
+      return false;
+    }
+    else if (dollarPos == 0)
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_NO_ATTR
+          .get(valueStr, criteria));
+      return false;
+    }
+    else if (dollarPos == criteria.length() - 1)
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE.get(valueStr,
+          criteria));
+      return false;
+    }
+    else
+    {
+      try
+      {
+        SchemaUtils.readOID(new SubstringReader(criteria
+            .substring(0, dollarPos)));
+      }
+      catch (final DecodeException de)
+      {
+        invalidReason.append(de.getMessageObject());
+        return false;
+      }
+    }
+
+    // The substring immediately after the dollar sign must be one of
+    // "eq", "substr", "ge", "le", or "approx". It may be followed by
+    // the end of the value, a pipe, or an ampersand.
+    int endPos;
+    c = criteria.charAt(dollarPos + 1);
+    switch (c)
+    {
+    case 'e':
+      if (criteria.startsWith("eq", dollarPos + 1))
+      {
+        endPos = dollarPos + 3;
+        break;
+      }
+      else
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE.get(
+            valueStr, criteria, dollarPos + 1));
+        return false;
+      }
+
+    case 's':
+      if (criteria.startsWith("substr", dollarPos + 1))
+      {
+        endPos = dollarPos + 7;
+        break;
+      }
+      else
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE.get(
+            valueStr, criteria, dollarPos + 1));
+        return false;
+      }
+
+    case 'g':
+      if (criteria.startsWith("ge", dollarPos + 1))
+      {
+        endPos = dollarPos + 3;
+        break;
+      }
+      else
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE.get(
+            valueStr, criteria, dollarPos + 1));
+        return false;
+      }
+
+    case 'l':
+      if (criteria.startsWith("le", dollarPos + 1))
+      {
+        endPos = dollarPos + 3;
+        break;
+      }
+      else
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE.get(
+            valueStr, criteria, dollarPos + 1));
+        return false;
+      }
+
+    case 'a':
+      if (criteria.startsWith("approx", dollarPos + 1))
+      {
+        endPos = dollarPos + 7;
+        break;
+      }
+      else
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE.get(
+            valueStr, criteria, dollarPos + 1));
+        return false;
+      }
+
+    default:
+      invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE.get(
+          valueStr, criteria, dollarPos + 1));
+      return false;
+    }
+
+    // See if we are at the end of the value. If so, then it is valid.
+    // Otherwise, the next character must be a pipe or an ampersand.
+    if (endPos >= criteria.length())
+    {
+      return true;
+    }
+    else
+    {
+      c = criteria.charAt(endPos);
+      if (c == '|' || c == '&')
+      {
+        return criteriaIsValid(criteria.substring(endPos + 1), valueStr,
+            invalidReason);
+      }
+      else
+      {
+        invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR.get(valueStr,
+            criteria, c, endPos));
+        return false;
+      }
+    }
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_GUIDE_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Get a lowercase string version of the provided value.
+    final String valueStr = toLowerCase(value.toString());
+
+    // Find the position of the octothorpe. If there isn't one, then the
+    // entire value should be the criteria.
+    final int sharpPos = valueStr.indexOf('#');
+    if (sharpPos < 0)
+    {
+      return criteriaIsValid(valueStr, valueStr, invalidReason);
+    }
+
+    // Get the objectclass and see if it is a valid name or OID.
+    final String ocName = valueStr.substring(0, sharpPos).trim();
+    final int ocLength = ocName.length();
+    if (ocLength == 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_GUIDE_NO_OC.get(valueStr));
+      return false;
+    }
+
+    try
+    {
+      SchemaUtils.readOID(new SubstringReader(ocName.substring(0, ocLength)));
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+
+    // The rest of the value must be the criteria.
+    return criteriaIsValid(valueStr.substring(sharpPos + 1), valueStr,
+        invalidReason);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IA5StringSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IA5StringSyntaxImpl.java
new file mode 100644
index 0000000..93a50db
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IA5StringSyntaxImpl.java
@@ -0,0 +1,130 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the IA5 string attribute syntax, which is simply a set
+ * of ASCII characters. By default, they will be treated in a case-insensitive
+ * manner, and equality, ordering, substring, and approximate matching will be
+ * allowed.
+ */
+final class IA5StringSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_IA5_STRING_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We will allow any value that does not contain any non-ASCII
+    // characters. Empty values are acceptable as well.
+    byte b;
+    for (int i = 0; i < value.length(); i++)
+    {
+      b = value.byteAt(i);
+      if ((b & 0x7F) != b)
+      {
+
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER
+            .get(value.toString(), String.valueOf(b));
+        invalidReason.append(message);
+        return false;
+      }
+    }
+
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..4044bb4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_ILLEGAL_INTEGER;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class defines the integerMatch matching rule defined in X.520 and
+ * referenced in RFC 2252.
+ */
+final class IntegerEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    try
+    {
+      return ByteString.valueOf(Integer.parseInt(value.toString()));
+    }
+    catch (final Exception e)
+    {
+      StaticUtils.DEBUG_LOG.throwing("IntegerEqualityMatchingRule",
+          "normalizeAttributeValue", e);
+
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_ILLEGAL_INTEGER
+          .get(value.toString());
+      throw DecodeException.error(message);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerFirstComponentEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerFirstComponentEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..34cad39
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerFirstComponentEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS;
+import static com.sun.opends.sdk.messages.Messages.ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the integerFirstComponentMatch matching rule defined in
+ * X.520 and referenced in RFC 2252. This rule is intended for use with
+ * attributes whose values contain a set of parentheses enclosing a
+ * space-delimited set of names and/or name-value pairs (like attribute type or
+ * objectclass descriptions) in which the "first component" is the first item
+ * after the opening parenthesis.
+ */
+final class IntegerFirstComponentEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+      final int intValue = SchemaUtils.readRuleID(reader);
+
+      return new Assertion()
+      {
+        public ConditionResult matches(final ByteSequence attributeValue)
+        {
+          final int actualIntValue = attributeValue.toByteString().toInt();
+          return intValue == actualIntValue ? ConditionResult.TRUE
+              : ConditionResult.FALSE;
+        }
+      };
+    }
+    catch (final Exception e)
+    {
+      StaticUtils.DEBUG_LOG.throwing(
+          "IntegerFirstComponentEqualityMatchingRule", "getAssertion", e);
+
+      final LocalizableMessage message = ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT
+          .get(value.toString());
+      throw DecodeException.error(message);
+    }
+
+  }
+
+
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final String definition = value.toString();
+    final SubstringReader reader = new SubstringReader(definition);
+
+    // We'll do this a character at a time. First, skip over any leading
+    // whitespace.
+    reader.skipWhitespaces();
+
+    if (reader.remaining() <= 0)
+    {
+      // This means that the value was empty or contained only
+      // whitespace. That is illegal.
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_EMPTY_VALUE.get();
+      throw DecodeException.error(message);
+    }
+
+    // The next character must be an open parenthesis. If it is not,
+    // then that is an error.
+    final char c = reader.read();
+    if (c != '(')
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS
+          .get(definition, (reader.pos() - 1), String.valueOf(c));
+      throw DecodeException.error(message);
+    }
+
+    // Skip over any spaces immediately following the opening
+    // parenthesis.
+    reader.skipWhitespaces();
+
+    // The next set of characters must be the OID.
+    return ByteString.valueOf(SchemaUtils.readRuleID(reader));
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..a8257d3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerOrderingMatchingRuleImpl.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_ILLEGAL_INTEGER;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class defines the integerOrderingMatch matching rule defined in X.520
+ * and referenced in RFC 4519.
+ */
+final class IntegerOrderingMatchingRuleImpl extends
+    AbstractOrderingMatchingRuleImpl
+{
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    try
+    {
+      return ByteString.valueOf(Integer.parseInt(value.toString()));
+    }
+    catch (final Exception e)
+    {
+      StaticUtils.DEBUG_LOG.throwing("IntegerOrderingMatchingRule",
+          "normalizeAttributeValue", e);
+
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_ILLEGAL_INTEGER
+          .get(value.toString());
+      throw DecodeException.error(message);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerSyntaxImpl.java
new file mode 100644
index 0000000..754f921
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/IntegerSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER;
+import static org.opends.sdk.schema.SchemaConstants.EMR_INTEGER_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_INTEGER_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_EXACT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_INTEGER_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines the integer attribute syntax, which holds an
+ * arbitrarily-long integer value. Equality, ordering, and substring matching
+ * will be allowed by default.
+ */
+final class IntegerSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_INTEGER_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_INTEGER_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_INTEGER_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_EXACT_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String valueString = value.toString();
+    final int length = valueString.length();
+
+    if (length == 0)
+    {
+      invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE
+          .get(valueString));
+      return false;
+    }
+    else if (length == 1)
+    {
+      switch (valueString.charAt(0))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        return true;
+      case '-':
+        invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE
+            .get(valueString));
+        return false;
+      default:
+        invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
+            valueString, valueString.charAt(0), 0));
+        return false;
+      }
+    }
+    else
+    {
+      boolean negative = false;
+
+      switch (valueString.charAt(0))
+      {
+      case '0':
+        invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO
+            .get(valueString));
+        return false;
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      case '-':
+        // This is fine too.
+        negative = true;
+        break;
+      default:
+        invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
+            valueString, valueString.charAt(0), 0));
+        return false;
+      }
+
+      switch (valueString.charAt(1))
+      {
+      case '0':
+        // This is fine as long as the value isn't negative.
+        if (negative)
+        {
+          invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO
+              .get(valueString));
+          return false;
+        }
+        break;
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
+            valueString, valueString.charAt(0), 0));
+        return false;
+      }
+
+      for (int i = 2; i < length; i++)
+      {
+        switch (valueString.charAt(i))
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+          // These are all fine.
+          break;
+        default:
+          invalidReason.append(WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER.get(
+              valueString, valueString.charAt(0), 0));
+          return false;
+        }
+      }
+
+      return true;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/JPEGSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/JPEGSyntaxImpl.java
new file mode 100644
index 0000000..fe514ba
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/JPEGSyntaxImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_JPEG_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the JPEG attribute syntax. This should be restricted to
+ * holding only JPEG image contents, but we will accept any set of bytes. It
+ * will be treated much like the octet string attribute syntax.
+ */
+final class JPEGSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_JPEG_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the fax syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/KeywordEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/KeywordEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..9dbc99c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/KeywordEqualityMatchingRuleImpl.java
@@ -0,0 +1,179 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.*;
+
+
+
+/**
+ * This class implements the keywordMatch matching rule defined in X.520. That
+ * document defines "keyword" as implementation-specific, but in this case we
+ * will consider it a match if the assertion value is contained within the
+ * attribute value and is bounded by the edge of the value or any of the
+ * following characters: <BR>
+ * <UL>
+ * <LI>A space</LI>
+ * <LI>A period</LI>
+ * <LI>A comma</LI>
+ * <LI>A slash</LI>
+ * <LI>A dollar sign</LI>
+ * <LI>A plus sign</LI>
+ * <LI>A dash</LI>
+ * <LI>An underscore</LI>
+ * <LI>An octothorpe</LI>
+ * <LI>An equal sign</LI>
+ * </UL>
+ */
+final class KeywordEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    final String normalStr = normalize(value);
+
+    return new Assertion()
+    {
+      public ConditionResult matches(final ByteSequence attributeValue)
+      {
+        // See if the assertion value is contained in the attribute
+        // value. If not, then it isn't a match.
+        final String valueStr1 = attributeValue.toString();
+
+        final int pos = valueStr1.indexOf(normalStr);
+        if (pos < 0)
+        {
+          return ConditionResult.FALSE;
+        }
+
+        if (pos > 0)
+        {
+          final char c = valueStr1.charAt(pos - 1);
+          switch (c)
+          {
+          case ' ':
+          case '.':
+          case ',':
+          case '/':
+          case '$':
+          case '+':
+          case '-':
+          case '_':
+          case '#':
+          case '=':
+            // These are all acceptable.
+            break;
+
+          default:
+            // Anything else is not.
+            return ConditionResult.FALSE;
+          }
+        }
+
+        if (valueStr1.length() > pos + normalStr.length())
+        {
+          final char c = valueStr1.charAt(pos + normalStr.length());
+          switch (c)
+          {
+          case ' ':
+          case '.':
+          case ',':
+          case '/':
+          case '$':
+          case '+':
+          case '-':
+          case '_':
+          case '#':
+          case '=':
+            // These are all acceptable.
+            break;
+
+          default:
+            // Anything else is not.
+            return ConditionResult.FALSE;
+          }
+        }
+
+        // If we've gotten here, then we can assume it is a match.
+        return ConditionResult.TRUE;
+      }
+    };
+  }
+
+
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return ByteString.valueOf(normalize(value));
+  }
+
+
+
+  private String normalize(final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return " ".intern();
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return "".intern();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return buffer.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/LDAPSyntaxDescriptionSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/LDAPSyntaxDescriptionSyntaxImpl.java
new file mode 100644
index 0000000..80964d4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/LDAPSyntaxDescriptionSyntaxImpl.java
@@ -0,0 +1,228 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_LDAP_SYNTAX_NAME;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class defines the LDAP syntax description syntax, which is used to hold
+ * attribute syntax definitions in the schema. The format of this syntax is
+ * defined in RFC 2252.
+ */
+final class LDAPSyntaxDescriptionSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_LDAP_SYNTAX_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll use the decodeNameForm method to determine if the value is
+    // acceptable.
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE
+            .get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("LDAPSyntaxDescriptionSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("LDAPSyntaxDescriptionSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the syntax. It is an
+          // arbitrary string of characters enclosed in single quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("LDAPSyntaxDescriptionSyntax",
+              "valueIsAcceptable", e);
+          throw e;
+        }
+      }
+
+      for (final Map.Entry<String, List<String>> property : extraProperties
+          .entrySet())
+      {
+        if (property.getKey().equalsIgnoreCase("x-pattern"))
+        {
+          final Iterator<String> values = property.getValue().iterator();
+          if (values.hasNext())
+          {
+            final String pattern = values.next();
+            try
+            {
+              Pattern.compile(values.next());
+            }
+            catch (final Exception e)
+            {
+              final LocalizableMessage message = WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_PATTERN
+                  .get(oid, pattern);
+              final DecodeException de = DecodeException.error(message, e);
+              StaticUtils.DEBUG_LOG.throwing("LDAPSyntaxDescriptionSyntax",
+                  "valueIsAcceptable", de);
+              throw de;
+            }
+            break;
+          }
+        }
+        else if (property.getKey().equalsIgnoreCase("x-enum"))
+        {
+          final List<String> values = property.getValue();
+          for (int i = 0; i < values.size() - 1; i++)
+          {
+            final String entry = values.get(i);
+            for (int j = i + 1; j < values.size(); j++)
+            {
+              if (entry.equals(values.get(j)))
+              {
+                final LocalizableMessage message = WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_DUPLICATE_VALUE
+                    .get(oid, entry, j);
+                final DecodeException e = DecodeException.error(message);
+                StaticUtils.DEBUG_LOG.throwing("LDAPSyntaxDescriptionSyntax",
+                    "valueIsAcceptable", e);
+                throw e;
+              }
+            }
+          }
+        }
+      }
+
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRule.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRule.java
new file mode 100644
index 0000000..3343f7d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRule.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX;
+import static com.sun.opends.sdk.messages.Messages.WARN_MATCHING_RULE_NOT_IMPLEMENTED;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a data structure for storing and interacting with matching
+ * rules, which are used by servers to compare attribute values against
+ * assertion values when performing Search and Compare operations. They are also
+ * used to identify the value to be added or deleted when modifying entries, and
+ * are used when comparing a purported distinguished name with the name of an
+ * entry.
+ * <p>
+ * Matching rule implementations must extend the
+ * <code>MatchingRuleImplementation</code> class so they can be used by OpenDS.
+ * <p>
+ * Where ordered sets of names, or extra properties are provided, the ordering
+ * will be preserved when the associated fields are accessed via their getters
+ * or via the {@link #toString()} methods.
+ */
+public final class MatchingRule extends SchemaElement
+{
+  private final String oid;
+  private final List<String> names;
+  private final boolean isObsolete;
+  private final String syntaxOID;
+  private final String definition;
+  private MatchingRuleImpl impl;
+  private Syntax syntax;
+  private Schema schema;
+
+
+
+  MatchingRule(final String oid, final List<String> names,
+      final String description, final boolean obsolete, final String syntax,
+      final Map<String, List<String>> extraProperties, final String definition,
+      final MatchingRuleImpl implementation)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(oid, names, description, syntax);
+    Validator.ensureNotNull(extraProperties);
+    this.oid = oid;
+    this.names = names;
+    this.isObsolete = obsolete;
+    this.syntaxOID = syntax;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+    this.impl = implementation;
+  }
+
+
+
+  /**
+   * Get a comparator that can be used to compare the attribute values
+   * normalized by this matching rule.
+   *
+   * @return A comparator that can be used to compare the attribute values
+   *         normalized by this matching rule.
+   */
+  public Comparator<ByteSequence> comparator()
+  {
+    return impl.comparator(schema);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean equals(final Object o)
+  {
+    if (o == null)
+    {
+      return false;
+    }
+
+    if (this == o)
+    {
+      return true;
+    }
+
+    if (!(o instanceof MatchingRule))
+    {
+      return false;
+    }
+
+    return getOID().equals(((MatchingRule) o).getOID());
+  }
+
+
+
+  /**
+   * Returns the normalized form of the provided assertion value, which is best
+   * suite for efficiently performing matching operations on that value. The
+   * assertion value is guarenteed to be valid against this matching rule's
+   * assertion syntax.
+   *
+   * @param value
+   *          The syntax checked assertion value to be normalized.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if the syntax of the value is not valid.
+   */
+  public Assertion getAssertion(final ByteSequence value)
+      throws DecodeException
+  {
+    return impl.getAssertion(schema, value);
+  }
+
+
+
+  /**
+   * Returns the normalized form of the provided assertion substring values,
+   * which is best suite for efficiently performing matching operations on that
+   * value.
+   *
+   * @param subInitial
+   *          The normalized substring value fragment that should appear at the
+   *          beginning of the target value.
+   * @param subAnyElements
+   *          The normalized substring value fragments that should appear in the
+   *          middle of the target value.
+   * @param subFinal
+   *          The normalized substring value fragment that should appear at the
+   *          end of the target value.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if the syntax of the value is not valid.
+   */
+  public Assertion getAssertion(final ByteSequence subInitial,
+      final List<? extends ByteSequence> subAnyElements,
+      final ByteSequence subFinal) throws DecodeException
+  {
+    return impl.getAssertion(schema, subInitial, subAnyElements, subFinal);
+  }
+
+
+
+  /**
+   * Returns the normalized form of the provided assertion value, which is best
+   * suite for efficiently performing greater than or equal ordering matching
+   * operations on that value. The assertion value is guarenteed to be valid
+   * against this matching rule's assertion syntax.
+   *
+   * @param value
+   *          The syntax checked assertion value to be normalized.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if the syntax of the value is not valid.
+   */
+  public Assertion getGreaterOrEqualAssertion(final ByteSequence value)
+      throws DecodeException
+  {
+    return impl.getGreaterOrEqualAssertion(schema, value);
+  }
+
+
+
+  /**
+   * Returns the normalized form of the provided assertion value, which is best
+   * suite for efficiently performing greater than or equal ordering matching
+   * operations on that value. The assertion value is guarenteed to be valid
+   * against this matching rule's assertion syntax.
+   *
+   * @param value
+   *          The syntax checked assertion value to be normalized.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if the syntax of the value is not valid.
+   */
+  public Assertion getLessOrEqualAssertion(final ByteSequence value)
+      throws DecodeException
+  {
+    return impl.getLessOrEqualAssertion(schema, value);
+  }
+
+
+
+  /**
+   * Returns the name or OID for this schema definition. If it has one or more
+   * names, then the primary name will be returned. If it does not have any
+   * names, then the OID will be returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public String getNameOrOID()
+  {
+    if (names.isEmpty())
+    {
+      return oid;
+    }
+    return names.get(0);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the user-defined names that may be
+   * used to reference this schema definition.
+   *
+   * @return Returns an unmodifiable list containing the user-defined names that
+   *         may be used to reference this schema definition.
+   */
+  public List<String> getNames()
+  {
+    return names;
+  }
+
+
+
+  /**
+   * Returns the OID for this schema definition.
+   *
+   * @return The OID for this schema definition.
+   */
+  public String getOID()
+  {
+
+    return oid;
+  }
+
+
+
+  /**
+   * Returns the OID of the assertion value syntax with which this matching rule
+   * is associated.
+   *
+   * @return The OID of the assertion value syntax with which this matching rule
+   *         is associated.
+   */
+  public Syntax getSyntax()
+  {
+    return syntax;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public int hashCode()
+  {
+    return oid.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name.
+   *
+   * @param name
+   *          The name for which to make the determination.
+   * @return <code>true</code> if the specified name is assigned to this schema
+   *         definition, or <code>false</code> if not.
+   */
+  public boolean hasName(final String name)
+  {
+    for (final String n : names)
+    {
+      if (n.equalsIgnoreCase(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name or OID.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return <code>true</code> if the provided value matches the OID or one of
+   *         the names assigned to this schema definition, or <code>false</code>
+   *         if not.
+   */
+  public boolean hasNameOrOID(final String value)
+  {
+    return hasName(value) || getOID().equals(value);
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition is declared "obsolete".
+   *
+   * @return <code>true</code> if this schema definition is declared "obsolete",
+   *         or <code>false</code> if not.
+   */
+  public boolean isObsolete()
+  {
+    return isObsolete;
+  }
+
+
+
+  /**
+   * Returns the normalized form of the provided attribute value, which is best
+   * suite for efficiently performing matching operations on that value.
+   *
+   * @param value
+   *          The attribute value to be normalized.
+   * @return The normalized version of the provided attribute value.
+   * @throws DecodeException
+   *           if the syntax of the value is not valid.
+   */
+  public ByteString normalizeAttributeValue(final ByteSequence value)
+      throws DecodeException
+  {
+    return impl.normalizeAttributeValue(schema, value);
+  }
+
+
+
+  /**
+   * Returns the string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  MatchingRule duplicate()
+  {
+    return new MatchingRule(oid, names, description, isObsolete, syntaxOID,
+        extraProperties, definition, impl);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(oid);
+
+    if (!names.isEmpty())
+    {
+      final Iterator<String> iterator = names.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NAME ( '");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append("' '");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append("' )");
+      }
+      else
+      {
+        buffer.append(" NAME '");
+        buffer.append(firstName);
+        buffer.append("'");
+      }
+    }
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+
+    if (isObsolete)
+    {
+      buffer.append(" OBSOLETE");
+    }
+
+    buffer.append(" SYNTAX ");
+    buffer.append(syntaxOID);
+  }
+
+
+
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    // Try finding an implementation in the core schema
+    if (impl == null && Schema.getDefaultSchema().hasMatchingRule(oid))
+    {
+      impl = Schema.getDefaultSchema().getMatchingRule(oid).impl;
+    }
+    if (impl == null && Schema.getCoreSchema().hasMatchingRule(oid))
+    {
+      impl = Schema.getCoreSchema().getMatchingRule(oid).impl;
+    }
+
+    if (impl == null)
+    {
+      impl = Schema.getDefaultMatchingRule().impl;
+      final LocalizableMessage message = WARN_MATCHING_RULE_NOT_IMPLEMENTED
+          .get(oid, Schema.getDefaultMatchingRule().getOID());
+      warnings.add(message);
+    }
+
+    try
+    {
+      // Make sure the specifiec syntax is defined in this schema.
+      syntax = schema.getSyntax(syntaxOID);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX.get(
+          getNameOrOID(), syntaxOID);
+      throw new SchemaException(message, e);
+    }
+
+    this.schema = schema;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleImpl.java
new file mode 100644
index 0000000..d29b53f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleImpl.java
@@ -0,0 +1,157 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import java.util.Comparator;
+import java.util.List;
+
+import org.opends.sdk.Assertion;
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+
+
+/**
+ * This interface defines the set of methods that must be implemented to define
+ * a new matching rule.
+ */
+public interface MatchingRuleImpl
+{
+  /**
+   * Get a comparator that can be used to compare the attribute values
+   * normalized by this matching rule.
+   *
+   * @param schema
+   *          The schema in which this matching rule is defined.
+   * @return A comparator that can be used to compare the attribute values
+   *         normalized by this matching rule.
+   */
+  public Comparator<ByteSequence> comparator(Schema schema);
+
+
+
+  /**
+   * Retrieves the normalized form of the provided assertion value, which is
+   * best suite for efficiently performing matching operations on that value.
+   * The assertion value is guarenteed to be valid against this matching rule's
+   * assertion syntax.
+   *
+   * @param schema
+   *          The schema in which this matching rule is defined.
+   * @param value
+   *          The syntax checked assertion value to be normalized.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if an syntax error occured while parsing the value.
+   */
+  public Assertion getAssertion(Schema schema, ByteSequence value)
+      throws DecodeException;
+
+
+
+  /**
+   * Retrieves the normalized form of the provided assertion substring values,
+   * which is best suite for efficiently performing matching operations on that
+   * value.
+   *
+   * @param schema
+   *          The schema in which this matching rule is defined.
+   * @param subInitial
+   *          The normalized substring value fragment that should appear at the
+   *          beginning of the target value.
+   * @param subAnyElements
+   *          The normalized substring value fragments that should appear in the
+   *          middle of the target value.
+   * @param subFinal
+   *          The normalized substring value fragment that should appear at the
+   *          end of the target value.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if an syntax error occured while parsing the value.
+   */
+  public Assertion getAssertion(Schema schema, ByteSequence subInitial,
+      List<? extends ByteSequence> subAnyElements, ByteSequence subFinal)
+      throws DecodeException;
+
+
+
+  /**
+   * Retrieves the normalized form of the provided assertion value, which is
+   * best suite for efficiently performing greater than or equal matching
+   * operations on that value. The assertion value is guarenteed to be valid
+   * against this matching rule's assertion syntax.
+   *
+   * @param schema
+   *          The schema in which this matching rule is defined.
+   * @param value
+   *          The syntax checked assertion value to be normalized.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if an syntax error occured while parsing the value.
+   */
+  public Assertion getGreaterOrEqualAssertion(Schema schema, ByteSequence value)
+      throws DecodeException;
+
+
+
+  /**
+   * Retrieves the normalized form of the provided assertion value, which is
+   * best suite for efficiently performing greater than or equal matching
+   * operations on that value. The assertion value is guarenteed to be valid
+   * against this matching rule's assertion syntax.
+   *
+   * @param schema
+   *          The schema in which this matching rule is defined.
+   * @param value
+   *          The syntax checked assertion value to be normalized.
+   * @return The normalized version of the provided assertion value.
+   * @throws DecodeException
+   *           if an syntax error occured while parsing the value.
+   */
+  public Assertion getLessOrEqualAssertion(Schema schema, ByteSequence value)
+      throws DecodeException;
+
+
+
+  /**
+   * Retrieves the normalized form of the provided attribute value, which is
+   * best suite for efficiently performing matching operations on that value.
+   *
+   * @param schema
+   *          The schema in which this matching rule is defined.
+   * @param value
+   *          The attribute value to be normalized.
+   * @return The normalized version of the provided attribute value.
+   * @throws DecodeException
+   *           if an syntax error occured while parsing the value.
+   */
+  public ByteString normalizeAttributeValue(Schema schema, ByteSequence value)
+      throws DecodeException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleSyntaxImpl.java
new file mode 100644
index 0000000..0de0869
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleSyntaxImpl.java
@@ -0,0 +1,215 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_ILLEGAL_TOKEN;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MR_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MR_NO_SYNTAX;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_MATCHING_RULE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the matching rule description syntax, which is used to
+ * hold matching rule definitions in the server schema. The format of this
+ * syntax is defined in RFC 2252.
+ */
+final class MatchingRuleSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_MATCHING_RULE_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll use the decodeMatchingRule method to determine if the value
+    // is acceptable.
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EMPTY_VALUE.get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("MatchingRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("MatchingRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      SchemaUtils.readOID(reader);
+      String syntax = null;
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the matching rule. It is
+          // an arbitrary string of characters enclosed in single
+          // quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the matching rule should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("syntax"))
+        {
+          syntax = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          SchemaUtils.readExtensions(reader);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("MatchingRuleSyntax",
+              "valueIsAcceptable", e);
+          throw e;
+        }
+      }
+
+      // Make sure that a syntax was specified.
+      if (syntax == null)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_NO_SYNTAX
+            .get(definition);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("MatchingRuleSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUse.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUse.java
new file mode 100644
index 0000000..6efee7f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUse.java
@@ -0,0 +1,372 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE;
+
+import java.util.*;
+
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a data structure for storing and interacting with a
+ * matching rule use definition, which may be used to restrict the set of
+ * attribute types that may be used for a given matching rule.
+ */
+public final class MatchingRuleUse extends SchemaElement
+{
+  // The OID of the matching rule associated with this matching rule
+  // use definition.
+  private final String oid;
+
+  // The set of user defined names for this definition.
+  private final List<String> names;
+
+  // Indicates whether this definition is declared "obsolete".
+  private final boolean isObsolete;
+
+  // The set of attribute types with which this matching rule use is
+  // associated.
+  private final Set<String> attributeOIDs;
+
+  // The definition string used to create this objectclass.
+  private final String definition;
+
+  private MatchingRule matchingRule;
+  private Set<AttributeType> attributes = Collections.emptySet();
+
+
+
+  MatchingRuleUse(final String oid, final List<String> names,
+      final String description, final boolean obsolete,
+      final Set<String> attributeOIDs,
+      final Map<String, List<String>> extraProperties, final String definition)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(oid, names, attributeOIDs);
+    this.oid = oid;
+    this.names = names;
+    this.isObsolete = obsolete;
+    this.attributeOIDs = attributeOIDs;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the attributes associated with this
+   * matching rule use.
+   *
+   * @return An unmodifiable set containing the attributes associated with this
+   *         matching rule use.
+   */
+  public Set<AttributeType> getAttributes()
+  {
+    return attributes;
+  }
+
+
+
+  /**
+   * Returns the matching rule for this matching rule use.
+   *
+   * @return The matching rule for this matching rule use.
+   */
+  public MatchingRule getMatchingRule()
+  {
+    return matchingRule;
+  }
+
+
+
+  /**
+   * Returns the matching rule OID for this schema definition.
+   *
+   * @return The OID for this schema definition.
+   */
+  public String getMatchingRuleOID()
+  {
+    return oid;
+  }
+
+
+
+  /**
+   * Returns the name or matching rule OID for this schema definition. If it has
+   * one or more names, then the primary name will be returned. If it does not
+   * have any names, then the OID will be returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public String getNameOrOID()
+  {
+    if (names.isEmpty())
+    {
+      return oid;
+    }
+    return names.get(0);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the user-defined names that may be
+   * used to reference this schema definition.
+   *
+   * @return Returns an unmodifiable list containing the user-defined names that
+   *         may be used to reference this schema definition.
+   */
+  public List<String> getNames()
+  {
+    return names;
+  }
+
+
+
+  /**
+   * Indicates whether the provided attribute type is referenced by this
+   * matching rule use.
+   *
+   * @param attributeType
+   *          The attribute type for which to make the determination.
+   * @return {@code true} if the provided attribute type is referenced by this
+   *         matching rule use, or {@code false} if it is not.
+   */
+  public boolean hasAttribute(final AttributeType attributeType)
+  {
+    return attributes.contains(attributeType);
+  }
+
+
+
+  @Override
+  public int hashCode()
+  {
+    return oid.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name.
+   *
+   * @param name
+   *          The name for which to make the determination.
+   * @return <code>true</code> if the specified name is assigned to this schema
+   *         definition, or <code>false</code> if not.
+   */
+  public boolean hasName(final String name)
+  {
+    for (final String n : names)
+    {
+      if (n.equalsIgnoreCase(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name or matching
+   * rule OID.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return <code>true</code> if the provided value matches the OID or one of
+   *         the names assigned to this schema definition, or <code>false</code>
+   *         if not.
+   */
+  public boolean hasNameOrOID(final String value)
+  {
+    return hasName(value) || oid.equals(value);
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition is declared "obsolete".
+   *
+   * @return <code>true</code> if this schema definition is declared "obsolete",
+   *         or <code>false</code> if not.
+   */
+  public boolean isObsolete()
+  {
+    return isObsolete;
+  }
+
+
+
+  /**
+   * Returns the string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  MatchingRuleUse duplicate()
+  {
+    return new MatchingRuleUse(oid, names, description, isObsolete,
+        attributeOIDs, extraProperties, definition);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(oid);
+
+    if (!names.isEmpty())
+    {
+      final Iterator<String> iterator = names.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NAME ( '");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append("' '");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append("' )");
+      }
+      else
+      {
+        buffer.append(" NAME '");
+        buffer.append(firstName);
+        buffer.append("'");
+      }
+    }
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+
+    if (isObsolete)
+    {
+      buffer.append(" OBSOLETE");
+    }
+
+    if (!attributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = attributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" APPLIES ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" APPLIES ");
+        buffer.append(firstName);
+      }
+    }
+  }
+
+
+
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    try
+    {
+      matchingRule = schema.getMatchingRule(oid);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      // This is bad because the matching rule use is associated with a
+      // matching rule that we don't know anything about.
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE
+          .get(definition, oid);
+      throw new SchemaException(message, e);
+    }
+
+    attributes = new HashSet<AttributeType>(attributeOIDs.size());
+    AttributeType attributeType;
+    for (final String attribute : attributeOIDs)
+    {
+      try
+      {
+        attributeType = schema.getAttributeType(attribute);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR
+            .get(oid, attribute);
+        throw new SchemaException(message, e);
+      }
+      attributes.add(attributeType);
+    }
+    attributes = Collections.unmodifiableSet(attributes);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUseSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUseSyntaxImpl.java
new file mode 100644
index 0000000..9728454
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/MatchingRuleUseSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_ILLEGAL_TOKEN;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_MRUSE_NO_ATTR;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_MATCHING_RULE_USE_NAME;
+
+import java.util.Set;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the matching rule use description syntax, which is used
+ * to hold matching rule use definitions in the server schema. The format of
+ * this syntax is defined in RFC 2252.
+ */
+final class MatchingRuleUseSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_MATCHING_RULE_USE_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll use the decodeAttributeType method to determine if the
+    // value is acceptable.
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE
+            .get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("MatchingRuleUseSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("MatchingRuleUseSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      SchemaUtils.readOID(reader);
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      Set<String> attributes = null;
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("applies"))
+        {
+          attributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          SchemaUtils.readExtensions(reader);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("MatchingRuleUseSyntax",
+              "valueIsAcceptable", e);
+          throw e;
+        }
+      }
+
+      // Make sure that the set of attributes was defined.
+      if (attributes == null || attributes.size() == 0)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_NO_ATTR
+            .get(definition);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("MatchingRuleUseSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameAndOptionalUIDSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameAndOptionalUIDSyntaxImpl.java
new file mode 100644
index 0000000..f0367e0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameAndOptionalUIDSyntaxImpl.java
@@ -0,0 +1,151 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN;
+import static org.opends.sdk.schema.SchemaConstants.EMR_UNIQUE_MEMBER_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_NAME_AND_OPTIONAL_UID_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DN;
+import org.opends.sdk.LocalizableMessageBuilder;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+
+
+/**
+ * This class implements the name and optional UID attribute syntax, which holds
+ * values consisting of a DN, optionally followed by an octothorpe (#) and a bit
+ * string value.
+ */
+final class NameAndOptionalUIDSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_UNIQUE_MEMBER_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_NAME_AND_OPTIONAL_UID_NAME;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String valueString = value.toString().trim();
+    final int valueLength = valueString.length();
+
+    // See if the value contains the "optional uid" portion. If we think
+    // it does, then mark its location.
+    int dnEndPos = valueLength;
+    int sharpPos = -1;
+    if (valueString.endsWith("'B") || valueString.endsWith("'b"))
+    {
+      sharpPos = valueString.lastIndexOf("#'");
+      if (sharpPos > 0)
+      {
+        dnEndPos = sharpPos;
+      }
+    }
+
+    // Take the DN portion of the string and try to normalize it.
+    try
+    {
+      DN.valueOf(valueString.substring(0, dnEndPos), schema);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      // We couldn't normalize the DN for some reason. The value cannot
+      // be acceptable.
+      invalidReason.append(ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN.get(
+          valueString, e.getMessageObject()));
+      return false;
+    }
+
+    // If there is an "optional uid", then normalize it and make sure it
+    // only contains valid binary digits.
+    if (sharpPos > 0)
+    {
+      final int endPos = valueLength - 2;
+      for (int i = sharpPos + 2; i < endPos; i++)
+      {
+        final char c = valueString.charAt(i);
+        if (!(c == '0' || c == '1'))
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT
+              .get(valueString, String.valueOf(c), i));
+          return false;
+        }
+      }
+    }
+
+    // If we've gotten here, then the value is acceptable.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameForm.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameForm.java
new file mode 100644
index 0000000..6860c5c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameForm.java
@@ -0,0 +1,452 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS;
+
+import java.util.*;
+
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a data structure for storing and interacting with a name
+ * form, which defines the attribute type(s) that must and/or may be used in the
+ * RDN of an entry with a given structural objectclass.
+ */
+public final class NameForm extends SchemaElement
+{
+  // The OID that may be used to reference this definition.
+  private final String oid;
+
+  // The set of user defined names for this definition.
+  private final List<String> names;
+
+  // Indicates whether this definition is declared "obsolete".
+  private final boolean isObsolete;
+
+  // The reference to the structural objectclass for this name form.
+  private final String structuralClassOID;
+
+  // The set of optional attribute types for this name form.
+  private final Set<String> optionalAttributeOIDs;
+
+  // The set of required attribute types for this name form.
+  private final Set<String> requiredAttributeOIDs;
+
+  // The definition string used to create this objectclass.
+  private final String definition;
+
+  private ObjectClass structuralClass;
+  private Set<AttributeType> optionalAttributes = Collections.emptySet();
+  private Set<AttributeType> requiredAttributes = Collections.emptySet();
+
+
+
+  NameForm(final String oid, final List<String> names,
+      final String description, final boolean obsolete,
+      final String structuralClassOID, final Set<String> requiredAttributeOIDs,
+      final Set<String> optionalAttributeOIDs,
+      final Map<String, List<String>> extraProperties, final String definition)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(oid, names);
+    Validator.ensureNotNull(structuralClassOID, requiredAttributeOIDs,
+        optionalAttributeOIDs);
+    Validator.ensureTrue(requiredAttributeOIDs.size() > 0,
+        "required attribute is empty");
+    this.oid = oid;
+    this.names = names;
+    this.isObsolete = obsolete;
+    this.structuralClassOID = structuralClassOID;
+    this.requiredAttributeOIDs = requiredAttributeOIDs;
+    this.optionalAttributeOIDs = optionalAttributeOIDs;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+  }
+
+
+
+  /**
+   * Returns the name or OID for this schema definition. If it has one or more
+   * names, then the primary name will be returned. If it does not have any
+   * names, then the OID will be returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public String getNameOrOID()
+  {
+    if (names.isEmpty())
+    {
+      return oid;
+    }
+    return names.get(0);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the user-defined names that may be
+   * used to reference this schema definition.
+   *
+   * @return Returns an unmodifiable list containing the user-defined names that
+   *         may be used to reference this schema definition.
+   */
+  public List<String> getNames()
+  {
+    return names;
+  }
+
+
+
+  /**
+   * Returns the OID for this schema definition.
+   *
+   * @return The OID for this schema definition.
+   */
+  public String getOID()
+  {
+
+    return oid;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the optional attributes for this
+   * name form.
+   *
+   * @return An unmodifiable set containing the optional attributes for this
+   *         name form.
+   */
+  public Set<AttributeType> getOptionalAttributes()
+  {
+    return optionalAttributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the required attributes for this
+   * name form.
+   *
+   * @return An unmodifiable set containing the required attributes for this
+   *         name form.
+   */
+  public Set<AttributeType> getRequiredAttributes()
+  {
+    return requiredAttributes;
+  }
+
+
+
+  /**
+   * Returns the reference to the structural objectclass for this name form.
+   *
+   * @return The reference to the structural objectclass for this name form.
+   */
+  public ObjectClass getStructuralClass()
+  {
+    return structuralClass;
+  }
+
+
+
+  @Override
+  public int hashCode()
+  {
+    return oid.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name.
+   *
+   * @param name
+   *          The name for which to make the determination.
+   * @return <code>true</code> if the specified name is assigned to this schema
+   *         definition, or <code>false</code> if not.
+   */
+  public boolean hasName(final String name)
+  {
+    for (final String n : names)
+    {
+      if (n.equalsIgnoreCase(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name or OID.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return <code>true</code> if the provided value matches the OID or one of
+   *         the names assigned to this schema definition, or <code>false</code>
+   *         if not.
+   */
+  public boolean hasNameOrOID(final String value)
+  {
+    return hasName(value) || getOID().equals(value);
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition is declared "obsolete".
+   *
+   * @return <code>true</code> if this schema definition is declared "obsolete",
+   *         or <code>false</code> if not.
+   */
+  public boolean isObsolete()
+  {
+    return isObsolete;
+  }
+
+
+
+  /**
+   * Returns the string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  NameForm duplicate()
+  {
+    return new NameForm(oid, names, description, isObsolete,
+        structuralClassOID, requiredAttributeOIDs, optionalAttributeOIDs,
+        extraProperties, definition);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(oid);
+
+    if (!names.isEmpty())
+    {
+      final Iterator<String> iterator = names.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NAME ( '");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append("' '");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append("' )");
+      }
+      else
+      {
+        buffer.append(" NAME '");
+        buffer.append(firstName);
+        buffer.append("'");
+      }
+    }
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+
+    if (isObsolete)
+    {
+      buffer.append(" OBSOLETE");
+    }
+
+    buffer.append(" OC ");
+    buffer.append(structuralClassOID);
+
+    if (!requiredAttributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = requiredAttributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" MUST ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" MUST ");
+        buffer.append(firstName);
+      }
+    }
+
+    if (!optionalAttributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = optionalAttributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" MAY ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" MAY ");
+        buffer.append(firstName);
+      }
+    }
+  }
+
+
+
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    try
+    {
+      structuralClass = schema.getObjectClass(structuralClassOID);
+    }
+    catch (final UnknownSchemaElementException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS
+          .get(oid, structuralClassOID);
+      throw new SchemaException(message, e);
+    }
+    if (structuralClass.getObjectClassType() != ObjectClassType.STRUCTURAL)
+    {
+      // This is bad because the associated structural class type is not
+      // structural.
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL
+          .get(oid, structuralClass.getOID(), structuralClass.getNameOrOID(),
+              String.valueOf(structuralClass.getObjectClassType()));
+      throw new SchemaException(message);
+    }
+
+    requiredAttributes = new HashSet<AttributeType>(requiredAttributeOIDs
+        .size());
+    AttributeType attributeType;
+    for (final String oid : requiredAttributeOIDs)
+    {
+      try
+      {
+        attributeType = schema.getAttributeType(oid);
+      }
+      catch (final UnknownSchemaElementException e)
+      {
+        // This isn't good because it means that the name form requires
+        // an attribute type that we don't know anything about.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR
+            .get(this.oid, oid);
+        throw new SchemaException(message, e);
+      }
+      requiredAttributes.add(attributeType);
+    }
+
+    if (!optionalAttributeOIDs.isEmpty())
+    {
+      optionalAttributes = new HashSet<AttributeType>(optionalAttributeOIDs
+          .size());
+      for (final String oid : optionalAttributeOIDs)
+      {
+        try
+        {
+          attributeType = schema.getAttributeType(oid);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          // This isn't good because it means that the name form
+          // requires an attribute type that we don't know anything
+          // about.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR
+              .get(this.oid, oid);
+          throw new SchemaException(message, e);
+        }
+        optionalAttributes.add(attributeType);
+      }
+    }
+
+    optionalAttributes = Collections.unmodifiableSet(optionalAttributes);
+    requiredAttributes = Collections.unmodifiableSet(requiredAttributes);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameFormSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameFormSyntaxImpl.java
new file mode 100644
index 0000000..74d50f5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NameFormSyntaxImpl.java
@@ -0,0 +1,222 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_NAME_FORM_NAME;
+
+import java.util.Set;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the name form description syntax, which is used to hold
+ * name form definitions in the server schema. The format of this syntax is
+ * defined in RFC 2252.
+ */
+final class NameFormSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_NAME_FORM_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll use the decodeNameForm method to determine if the value is
+    // acceptable.
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE
+            .get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG
+            .throwing("NameFormSyntax", "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), c);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG
+            .throwing("NameFormSyntax", "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      SchemaUtils.readOID(reader);
+
+      String structuralClass = null;
+      Set<String> requiredAttributes = null;
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("oc"))
+        {
+          structuralClass = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("must"))
+        {
+          requiredAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("may"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          SchemaUtils.readExtensions(reader);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("NameFormSyntax", "valueIsAcceptable",
+              e);
+          throw e;
+        }
+      }
+
+      // Make sure that a structural class was specified. If not, then
+      // it cannot be valid.
+      if (structuralClass == null)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS
+            .get(definition);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG
+            .throwing("NameFormSyntax", "valueIsAcceptable", e);
+        throw e;
+      }
+
+      if (requiredAttributes == null || requiredAttributes.size() == 0)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_NO_REQUIRED_ATTR
+            .get(definition);
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG
+            .throwing("NameFormSyntax", "valueIsAcceptable", e);
+        throw e;
+      }
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..90cd3d8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringEqualityMatchingRuleImpl.java
@@ -0,0 +1,60 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class implements the numericStringMatch matching rule defined in X.520
+ * and referenced in RFC 2252. It allows for values with numeric digits and
+ * spaces, but ignores spaces when performing matching.
+ */
+final class NumericStringEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
+
+    if (buffer.length() == 0)
+    {
+      return ByteString.empty();
+    }
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..67eea56
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringOrderingMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This implements defines the numericStringOrderingMatch matching rule defined
+ * in X.520 and referenced in RFC 2252.
+ */
+final class NumericStringOrderingMatchingRuleImpl extends
+    AbstractOrderingMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
+
+    if (buffer.length() == 0)
+    {
+      return ByteString.empty();
+    }
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..224c592
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSubstringMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.NO_CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class implements the numericStringSubstringsMatch matching rule defined
+ * in X.520 and referenced in RFC 2252.
+ */
+final class NumericStringSubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
+
+    if (buffer.length() == 0)
+    {
+      return ByteString.empty();
+    }
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSyntaxImpl.java
new file mode 100644
index 0000000..30dcbf0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/NumericStringSyntaxImpl.java
@@ -0,0 +1,135 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR;
+import static com.sun.opends.sdk.util.StaticUtils.isDigit;
+import static org.opends.sdk.schema.SchemaConstants.EMR_NUMERIC_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_NUMERIC_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_EXACT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_NUMERIC_STRING_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the numeric string attribute syntax, which may be hold
+ * one or more numeric digits and/or spaces. Equality, ordering, and substring
+ * matching will be allowed by default.
+ */
+final class NumericStringSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_NUMERIC_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_NUMERIC_STRING_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_NUMERIC_STRING_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_EXACT_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String valueString = value.toString();
+    final int length = valueString.length();
+
+    // It must have at least one digit or space.
+    if (length == 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE.get());
+      return false;
+    }
+
+    // Iterate through the characters and make sure they are all digits
+    // or spaces.
+    for (int i = 0; i < length; i++)
+    {
+      final char c = valueString.charAt(i);
+      if (!(isDigit(c) || c == ' '))
+      {
+
+        invalidReason.append(WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR.get(
+            valueString, String.valueOf(c), i));
+        return false;
+      }
+    }
+
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OIDSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OIDSyntaxImpl.java
new file mode 100644
index 0000000..1699ac7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OIDSyntaxImpl.java
@@ -0,0 +1,108 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_OID_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class defines the OID syntax, which holds either an identifier name or a
+ * numeric OID. Equality and substring matching will be allowed by default.
+ */
+final class OIDSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_OID_NAME;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    try
+    {
+      SchemaUtils.readOID(new SubstringReader(value.toString()));
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClass.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClass.java
new file mode 100644
index 0000000..a19b6fd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClass.java
@@ -0,0 +1,797 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_NAME;
+import static org.opends.sdk.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_OID;
+import static org.opends.sdk.schema.SchemaConstants.TOP_OBJECTCLASS_NAME;
+
+import java.util.*;
+
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a data structure for storing and interacting with an
+ * objectclass, which contains a collection of attributes that must and/or may
+ * be present in an entry with that objectclass.
+ * <p>
+ * Where ordered sets of names, attribute types, or extra properties are
+ * provided, the ordering will be preserved when the associated fields are
+ * accessed via their getters or via the {@link #toString()} methods.
+ */
+public final class ObjectClass extends SchemaElement
+{
+  // The OID that may be used to reference this definition.
+  private final String oid;
+
+  // The set of user defined names for this definition.
+  private final List<String> names;
+
+  // Indicates whether this definition is declared "obsolete".
+  private final boolean isObsolete;
+
+  // The reference to the superior objectclasses.
+  private final Set<String> superiorClassOIDs;
+
+  // The objectclass type for this objectclass.
+  private final ObjectClassType objectClassType;
+
+  // The set of required attribute types for this objectclass.
+  private final Set<String> requiredAttributeOIDs;
+
+  // The set of optional attribute types for this objectclass.
+  private final Set<String> optionalAttributeOIDs;
+
+  // The definition string used to create this objectclass.
+  private final String definition;
+
+  private Set<ObjectClass> superiorClasses = Collections.emptySet();
+  private Set<AttributeType> declaredRequiredAttributes = Collections
+      .emptySet();
+  private Set<AttributeType> requiredAttributes = Collections.emptySet();
+  private Set<AttributeType> declaredOptionalAttributes = Collections
+      .emptySet();
+  private Set<AttributeType> optionalAttributes = Collections.emptySet();
+  private boolean validated = false;
+
+
+
+  ObjectClass(final String oid, final List<String> names,
+      final String description, final boolean obsolete,
+      final Set<String> superiorClassOIDs,
+      final Set<String> requiredAttributeOIDs,
+      final Set<String> optionalAttributeOIDs,
+      final ObjectClassType objectClassType,
+      final Map<String, List<String>> extraProperties, final String definition)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(oid, names);
+    Validator.ensureNotNull(superiorClassOIDs, requiredAttributeOIDs,
+        optionalAttributeOIDs, objectClassType);
+    this.oid = oid;
+    this.names = names;
+    this.isObsolete = obsolete;
+    this.superiorClassOIDs = superiorClassOIDs;
+    this.objectClassType = objectClassType;
+    this.requiredAttributeOIDs = requiredAttributeOIDs;
+    this.optionalAttributeOIDs = optionalAttributeOIDs;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+  }
+
+
+
+  /**
+   * Construct a extensibleObject object class where the set of allowed
+   * attribute types of this object class is implicitly the set of all attribute
+   * types of userApplications usage.
+   *
+   * @param description
+   *          The description for this schema definition
+   * @param extraProperties
+   *          The map of "extra" properties for this schema definition
+   */
+  ObjectClass(final String description,
+      final Map<String, List<String>> extraProperties)
+  {
+    super(description, extraProperties);
+    this.oid = EXTENSIBLE_OBJECT_OBJECTCLASS_OID;
+    this.names = Collections.singletonList(EXTENSIBLE_OBJECT_OBJECTCLASS_NAME);
+    this.isObsolete = false;
+    this.superiorClassOIDs = Collections.singleton(TOP_OBJECTCLASS_NAME);
+    this.objectClassType = ObjectClassType.AUXILIARY;
+    this.requiredAttributeOIDs = Collections.emptySet();
+    this.optionalAttributeOIDs = Collections.emptySet();
+
+    this.definition = buildDefinition();
+  }
+
+
+
+  @Override
+  public boolean equals(final Object o)
+  {
+    if (this == o)
+    {
+      return true;
+    }
+
+    if (o instanceof ObjectClass)
+    {
+      final ObjectClass other = (ObjectClass) o;
+      return oid.equals(other.oid);
+    }
+
+    return false;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the optional attributes for this
+   * object class. Note that this set will not automatically include any
+   * optional attributes for superior object classes.
+   *
+   * @return An unmodifiable set containing the optional attributes for this
+   *         object class.
+   */
+  public Set<AttributeType> getDeclaredOptionalAttributes()
+  {
+    return declaredOptionalAttributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the required attributes for this
+   * object class. Note that this set will not automatically include any
+   * required attributes for superior object classes.
+   *
+   * @return An unmodifiable set containing the required attributes for this
+   *         object class.
+   */
+  public Set<AttributeType> getDeclaredRequiredAttributes()
+  {
+    return declaredRequiredAttributes;
+  }
+
+
+
+  /**
+   * Returns the name or OID for this schema definition. If it has one or more
+   * names, then the primary name will be returned. If it does not have any
+   * names, then the OID will be returned.
+   *
+   * @return The name or OID for this schema definition.
+   */
+  public String getNameOrOID()
+  {
+    if (names.isEmpty())
+    {
+      return oid;
+    }
+    return names.get(0);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the user-defined names that may be
+   * used to reference this schema definition.
+   *
+   * @return Returns an unmodifiable list containing the user-defined names that
+   *         may be used to reference this schema definition.
+   */
+  public List<String> getNames()
+  {
+    return names;
+  }
+
+
+
+  /**
+   * Returns the objectclass type for this objectclass.
+   *
+   * @return The objectclass type for this objectclass.
+   */
+  public ObjectClassType getObjectClassType()
+  {
+
+    return objectClassType;
+  }
+
+
+
+  /**
+   * Returns the OID for this schema definition.
+   *
+   * @return The OID for this schema definition.
+   */
+  public String getOID()
+  {
+
+    return oid;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the optional attributes for this
+   * object class and any superior object classes that it might have.
+   *
+   * @return An unmodifiable set containing the optional attributes for this
+   *         object class and any superior object classes that it might have.
+   */
+  public Set<AttributeType> getOptionalAttributes()
+  {
+    return optionalAttributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the required attributes for this
+   * object class and any superior object classes that it might have.
+   *
+   * @return An unmodifiable set containing the required attributes for this
+   *         object class and any superior object classes that it might have.
+   */
+  public Set<AttributeType> getRequiredAttributes()
+  {
+    return requiredAttributes;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the superior classes for this object
+   * class.
+   *
+   * @return An unmodifiable set containing the superior classes for this object
+   *         class.
+   */
+  public Set<ObjectClass> getSuperiorClasses()
+  {
+    return superiorClasses;
+  }
+
+
+
+  @Override
+  public int hashCode()
+  {
+    return oid.hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name.
+   *
+   * @param name
+   *          The name for which to make the determination.
+   * @return <code>true</code> if the specified name is assigned to this schema
+   *         definition, or <code>false</code> if not.
+   */
+  public boolean hasName(final String name)
+  {
+    for (final String n : names)
+    {
+      if (n.equalsIgnoreCase(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition has the specified name or OID.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return <code>true</code> if the provided value matches the OID or one of
+   *         the names assigned to this schema definition, or <code>false</code>
+   *         if not.
+   */
+  public boolean hasNameOrOID(final String value)
+  {
+    return hasName(value) || getOID().equals(value);
+  }
+
+
+
+  /**
+   * Indicates whether this objectclass is a descendant of the provided class.
+   *
+   * @param objectClass
+   *          The objectClass for which to make the determination.
+   * @return <code>true</code> if this objectclass is a descendant of the
+   *         provided class, or <code>false</code> if not.
+   */
+  public boolean isDescendantOf(final ObjectClass objectClass)
+  {
+    for (final ObjectClass sup : superiorClasses)
+    {
+      if (sup.equals(objectClass) || sup.isDescendantOf(objectClass))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether this schema definition is declared "obsolete".
+   *
+   * @return <code>true</code> if this schema definition is declared "obsolete",
+   *         or <code>false</code> if not.
+   */
+  public boolean isObsolete()
+  {
+    return isObsolete;
+  }
+
+
+
+  /**
+   * Indicates whether the provided attribute type is included in the optional
+   * attribute list for this or any of its superior objectclasses.
+   *
+   * @param attributeType
+   *          The attribute type for which to make the determination.
+   * @return <code>true</code> if the provided attribute type is optional for
+   *         this objectclass or any of its superior classes, or
+   *         <code>false</code> if not.
+   */
+  public boolean isOptional(final AttributeType attributeType)
+  {
+    return optionalAttributes.contains(attributeType);
+  }
+
+
+
+  /**
+   * Indicates whether the provided attribute type is included in the required
+   * attribute list for this or any of its superior objectclasses.
+   *
+   * @param attributeType
+   *          The attribute type for which to make the determination.
+   * @return <code>true</code> if the provided attribute type is required by
+   *         this objectclass or any of its superior classes, or
+   *         <code>false</code> if not.
+   */
+  public boolean isRequired(final AttributeType attributeType)
+  {
+    return requiredAttributes.contains(attributeType);
+  }
+
+
+
+  /**
+   * Indicates whether the provided attribute type is in the list of required or
+   * optional attributes for this objectclass or any of its superior classes.
+   *
+   * @param attributeType
+   *          The attribute type for which to make the determination.
+   * @return <code>true</code> if the provided attribute type is required or
+   *         allowed for this objectclass or any of its superior classes, or
+   *         <code>false</code> if it is not.
+   */
+  public boolean isRequiredOrOptional(final AttributeType attributeType)
+  {
+    return isRequired(attributeType) || isOptional(attributeType);
+  }
+
+
+
+  /**
+   * Returns the string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  ObjectClass duplicate()
+  {
+    return new ObjectClass(oid, names, description, isObsolete,
+        superiorClassOIDs, requiredAttributeOIDs, optionalAttributeOIDs,
+        objectClassType, extraProperties, definition);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(oid);
+
+    if (!names.isEmpty())
+    {
+      final Iterator<String> iterator = names.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" NAME ( '");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append("' '");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append("' )");
+      }
+      else
+      {
+        buffer.append(" NAME '");
+        buffer.append(firstName);
+        buffer.append("'");
+      }
+    }
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+
+    if (isObsolete)
+    {
+      buffer.append(" OBSOLETE");
+    }
+
+    if (!superiorClassOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = superiorClassOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" SUP ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" SUP ");
+        buffer.append(firstName);
+      }
+    }
+
+    if (objectClassType != null)
+    {
+      buffer.append(" ");
+      buffer.append(objectClassType.toString());
+    }
+
+    if (!requiredAttributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = requiredAttributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" MUST ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" MUST ");
+        buffer.append(firstName);
+      }
+    }
+
+    if (!optionalAttributeOIDs.isEmpty())
+    {
+      final Iterator<String> iterator = optionalAttributeOIDs.iterator();
+
+      final String firstName = iterator.next();
+      if (iterator.hasNext())
+      {
+        buffer.append(" MAY ( ");
+        buffer.append(firstName);
+
+        while (iterator.hasNext())
+        {
+          buffer.append(" $ ");
+          buffer.append(iterator.next());
+        }
+
+        buffer.append(" )");
+      }
+      else
+      {
+        buffer.append(" MAY ");
+        buffer.append(firstName);
+      }
+    }
+  }
+
+
+
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    if (validated)
+    {
+      return;
+    }
+    validated = true;
+
+    // Init a flag to check to inheritance from top (only needed for
+    // structural object classes) per RFC 4512
+    boolean derivesTop = objectClassType != ObjectClassType.STRUCTURAL;
+
+    if (!superiorClassOIDs.isEmpty())
+    {
+      superiorClasses = new HashSet<ObjectClass>(superiorClassOIDs.size());
+      ObjectClass superiorClass;
+      for (final String superClassOid : superiorClassOIDs)
+      {
+        try
+        {
+          superiorClass = schema.getObjectClass(superClassOid);
+        }
+        catch (final UnknownSchemaElementException e)
+        {
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS
+              .get(oid, superClassOid);
+          throw new SchemaException(message, e);
+        }
+
+        // Make sure that the inheritance configuration is acceptable.
+        final ObjectClassType superiorType = superiorClass.getObjectClassType();
+        switch (objectClassType)
+        {
+        case ABSTRACT:
+          // Abstract classes may only inherit from other abstract
+          // classes.
+          if (superiorType != ObjectClassType.ABSTRACT)
+          {
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE
+                .get(oid, objectClassType.toString(), superiorType.toString(),
+                    superiorClass.getNameOrOID());
+            throw new SchemaException(message);
+          }
+          break;
+
+        case AUXILIARY:
+          // Auxiliary classes may only inherit from abstract classes or
+          // other auxiliary classes.
+          if (superiorType != ObjectClassType.ABSTRACT
+              && superiorType != ObjectClassType.AUXILIARY)
+          {
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE
+                .get(oid, objectClassType.toString(), superiorType.toString(),
+                    superiorClass.getNameOrOID());
+            throw new SchemaException(message);
+          }
+          break;
+
+        case STRUCTURAL:
+          // Structural classes may only inherit from abstract classes
+          // or other structural classes.
+          if (superiorType != ObjectClassType.ABSTRACT
+              && superiorType != ObjectClassType.STRUCTURAL)
+          {
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE
+                .get(oid, objectClassType.toString(), superiorType.toString(),
+                    superiorClass.getNameOrOID());
+            throw new SchemaException(message);
+          }
+          break;
+        }
+
+        // All existing structural object classes defined in this schema
+        // are implicitly guaranteed to inherit from top
+        if (!derivesTop && superiorType == ObjectClassType.STRUCTURAL)
+        {
+          derivesTop = true;
+        }
+
+        // Validate superior object class so we can inherit its
+        // attributes.
+        superiorClass.validate(warnings, schema);
+
+        // Inherit all required attributes from superior class.
+        Iterator<AttributeType> i = superiorClass.getRequiredAttributes()
+            .iterator();
+        if (i.hasNext() && requiredAttributes == Collections.EMPTY_SET)
+        {
+          requiredAttributes = new HashSet<AttributeType>();
+        }
+        while (i.hasNext())
+        {
+          requiredAttributes.add(i.next());
+        }
+
+        // Inherit all optional attributes from superior class.
+        i = superiorClass.getRequiredAttributes().iterator();
+        if (i.hasNext() && requiredAttributes == Collections.EMPTY_SET)
+        {
+          requiredAttributes = new HashSet<AttributeType>();
+        }
+        while (i.hasNext())
+        {
+          requiredAttributes.add(i.next());
+        }
+
+        superiorClasses.add(superiorClass);
+      }
+    }
+
+    if (!derivesTop)
+    {
+      derivesTop = isDescendantOf(schema.getObjectClass("2.5.6.0"));
+    }
+
+    // Structural classes must have the "top" objectclass somewhere
+    // in the superior chain.
+    if (!derivesTop)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP
+          .get(oid);
+      throw new SchemaException(message);
+    }
+
+    if (oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID))
+    {
+      declaredOptionalAttributes = new HashSet<AttributeType>(
+          requiredAttributeOIDs.size());
+      for (final AttributeType attributeType : schema.getAttributeTypes())
+      {
+        if (attributeType.getUsage() == AttributeUsage.USER_APPLICATIONS)
+        {
+          declaredOptionalAttributes.add(attributeType);
+        }
+      }
+      optionalAttributes = declaredRequiredAttributes;
+    }
+    else
+    {
+      if (!requiredAttributeOIDs.isEmpty())
+      {
+        declaredRequiredAttributes = new HashSet<AttributeType>(
+            requiredAttributeOIDs.size());
+        AttributeType attributeType;
+        for (final String requiredAttribute : requiredAttributeOIDs)
+        {
+          try
+          {
+            attributeType = schema.getAttributeType(requiredAttribute);
+          }
+          catch (final UnknownSchemaElementException e)
+          {
+            // This isn't good because it means that the objectclass
+            // requires an attribute type that we don't know anything
+            // about.
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR
+                .get(oid, requiredAttribute);
+            throw new SchemaException(message, e);
+          }
+          declaredRequiredAttributes.add(attributeType);
+        }
+        if (requiredAttributes == Collections.EMPTY_SET)
+        {
+          requiredAttributes = declaredRequiredAttributes;
+        }
+        else
+        {
+          requiredAttributes.addAll(declaredRequiredAttributes);
+        }
+      }
+
+      if (!optionalAttributeOIDs.isEmpty())
+      {
+        declaredOptionalAttributes = new HashSet<AttributeType>(
+            optionalAttributeOIDs.size());
+        AttributeType attributeType;
+        for (final String optionalAttribute : optionalAttributeOIDs)
+        {
+          try
+          {
+            attributeType = schema.getAttributeType(optionalAttribute);
+          }
+          catch (final UnknownSchemaElementException e)
+          {
+            // This isn't good because it means that the objectclass
+            // requires an attribute type that we don't know anything
+            // about.
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR
+                .get(oid, optionalAttribute);
+            throw new SchemaException(message, e);
+          }
+          declaredOptionalAttributes.add(attributeType);
+        }
+        if (optionalAttributes == Collections.EMPTY_SET)
+        {
+          optionalAttributes = declaredOptionalAttributes;
+        }
+        else
+        {
+          optionalAttributes.addAll(declaredOptionalAttributes);
+        }
+      }
+    }
+
+    declaredOptionalAttributes = Collections
+        .unmodifiableSet(declaredOptionalAttributes);
+    declaredRequiredAttributes = Collections
+        .unmodifiableSet(declaredRequiredAttributes);
+    optionalAttributes = Collections.unmodifiableSet(optionalAttributes);
+    requiredAttributes = Collections.unmodifiableSet(requiredAttributes);
+    superiorClasses = Collections.unmodifiableSet(superiorClasses);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassSyntaxImpl.java
new file mode 100644
index 0000000..167b3ba
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassSyntaxImpl.java
@@ -0,0 +1,217 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_ILLEGAL_TOKEN;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.
+  ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS;
+import static org.opends.sdk.schema.SchemaConstants.EMR_OID_FIRST_COMPONENT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_OBJECTCLASS_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the object class description syntax, which is used to
+ * hold objectclass definitions in the server schema. The format of this syntax
+ * is defined in RFC 2252.
+ */
+final class ObjectClassSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OID_FIRST_COMPONENT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_OBJECTCLASS_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll use the decodeObjectClass method to determine if the value
+    // is acceptable.
+    try
+    {
+      final String definition = value.toString();
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE
+            .get();
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("ObjectClassSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        final DecodeException e = DecodeException.error(message);
+        StaticUtils.DEBUG_LOG.throwing("ObjectClassSyntax",
+            "valueIsAcceptable", e);
+        throw e;
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      SchemaUtils.readOID(reader);
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("sup"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("abstract"))
+        {
+          // This indicates that entries must not include this
+          // objectclass unless they also include a non-abstract
+          // objectclass that inherits from this class. We do not need
+          // any more parsing for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("structural"))
+        {
+          // This indicates that this is a structural objectclass.
+          // We do not need any more parsing for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("auxiliary"))
+        {
+          // This indicates that this is an auxiliary objectclass.
+          // We do not need any more parsing for this token.
+        }
+        else if (tokenName.equalsIgnoreCase("must"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("may"))
+        {
+          SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          SchemaUtils.readExtensions(reader);
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          final DecodeException e = DecodeException.error(message);
+          StaticUtils.DEBUG_LOG.throwing("ObjectClassSyntax",
+              "valueIsAcceptable", e);
+          throw e;
+        }
+      }
+      return true;
+    }
+    catch (final DecodeException de)
+    {
+      invalidReason.append(de.getMessageObject());
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassType.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassType.java
new file mode 100644
index 0000000..4157ab7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectClassType.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+/**
+ * This enumeration defines the set of possible objectclass types that may be
+ * used, as defined in RFC 2252.
+ */
+public enum ObjectClassType
+{
+  /**
+   * The objectclass type that to use for classes declared "abstract".
+   */
+  ABSTRACT("ABSTRACT"),
+
+  /**
+   * The objectclass type that to use for classes declared "structural".
+   */
+  STRUCTURAL("STRUCTURAL"),
+
+  /**
+   * The objectclass type that to use for classes declared "auxiliary".
+   */
+  AUXILIARY("AUXILIARY");
+
+  // The string representation of this objectclass type.
+  private final String typeString;
+
+
+
+  /**
+   * Creates a new objectclass type with the provided string representation.
+   *
+   * @param typeString
+   *          The string representation for this objectclass type.
+   */
+  private ObjectClassType(final String typeString)
+  {
+    this.typeString = typeString;
+  }
+
+
+
+  /**
+   * Retrieves a string representation of this objectclass type.
+   *
+   * @return A string representation of this objectclass type.
+   */
+  @Override
+  public String toString()
+  {
+    return typeString;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..c3bb105
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
@@ -0,0 +1,179 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class defines the objectIdentifierMatch matching rule defined in X.520
+ * and referenced in RFC 2252. This expects to work on OIDs and will match
+ * either an attribute/objectclass name or a numeric OID. NOTE: This matching
+ * rule requires a schema to lookup object identifiers in the descriptor form.
+ */
+final class ObjectIdentifierEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  static class OIDAssertion implements Assertion
+  {
+    private final String oid;
+
+
+
+    OIDAssertion(final String oid)
+    {
+      this.oid = oid;
+    }
+
+
+
+    public ConditionResult matches(final ByteSequence attributeValue)
+    {
+      final String attrStr = attributeValue.toString();
+
+      // We should have normalized all values to OIDs. If not, we know
+      // the descriptor form is not valid in the schema.
+      if (attrStr.length() == 0 || !StaticUtils.isDigit(attrStr.charAt(0)))
+      {
+        return ConditionResult.UNDEFINED;
+      }
+      if (oid.length() == 0 || !StaticUtils.isDigit(oid.charAt(0)))
+      {
+        return ConditionResult.UNDEFINED;
+      }
+
+      return attrStr.equals(oid) ? ConditionResult.TRUE : ConditionResult.FALSE;
+    }
+  }
+
+
+
+  static String resolveNames(final Schema schema, final String oid)
+  {
+    if (!StaticUtils.isDigit(oid.charAt(0)))
+    {
+      // Do an best effort attempt to normalize names to OIDs.
+
+      String schemaName = null;
+
+      if (schema.hasAttributeType(oid))
+      {
+        schemaName = schema.getAttributeType(oid).getOID();
+      }
+
+      if (schemaName == null)
+      {
+        if (schema.hasDITContentRule(oid))
+        {
+          schemaName = schema.getDITContentRule(oid).getStructuralClass()
+              .getOID();
+        }
+      }
+
+      if (schemaName == null)
+      {
+        if (schema.hasSyntax(oid))
+        {
+          schemaName = schema.getSyntax(oid).getOID();
+        }
+      }
+
+      if (schemaName == null)
+      {
+        if (schema.hasObjectClass(oid))
+        {
+          schemaName = schema.getObjectClass(oid).getOID();
+        }
+      }
+
+      if (schemaName == null)
+      {
+        if (schema.hasMatchingRule(oid))
+        {
+          schemaName = schema.getMatchingRule(oid).getOID();
+        }
+      }
+
+      if (schemaName == null)
+      {
+        if (schema.hasMatchingRuleUse(oid))
+        {
+          schemaName = schema.getMatchingRuleUse(oid).getMatchingRule()
+              .getOID();
+        }
+      }
+
+      if (schemaName == null)
+      {
+        if (schema.hasNameForm(oid))
+        {
+          schemaName = schema.getNameForm(oid).getOID();
+        }
+      }
+
+      if (schemaName != null)
+      {
+        return schemaName;
+      }
+      else
+      {
+        return StaticUtils.toLowerCase(oid);
+      }
+    }
+    return oid;
+  }
+
+
+
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    final String definition = value.toString();
+    final SubstringReader reader = new SubstringReader(definition);
+    final String normalized = resolveNames(schema, SchemaUtils.readOID(reader));
+
+    return new OIDAssertion(normalized);
+  }
+
+
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final String definition = value.toString();
+    final SubstringReader reader = new SubstringReader(definition);
+    final String normalized = resolveNames(schema, SchemaUtils.readOID(reader));
+    return ByteString.valueOf(normalized);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..17bdad5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * This class implements the objectIdentifierFirstComponentMatch matching rule
+ * defined in X.520 and referenced in RFC 2252. This rule is intended for use
+ * with attributes whose values contain a set of parentheses enclosing a
+ * space-delimited set of names and/or name-value pairs (like attribute type or
+ * objectclass descriptions) in which the "first component" is the first item
+ * after the opening parenthesis.
+ */
+final class ObjectIdentifierFirstComponentEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    final String definition = value.toString();
+    final SubstringReader reader = new SubstringReader(definition);
+    final String normalized = ObjectIdentifierEqualityMatchingRuleImpl
+        .resolveNames(schema, SchemaUtils.readOID(reader));
+
+    return new ObjectIdentifierEqualityMatchingRuleImpl.OIDAssertion(normalized);
+  }
+
+
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    final String definition = value.toString();
+    final SubstringReader reader = new SubstringReader(definition);
+
+    // We'll do this a character at a time. First, skip over any leading
+    // whitespace.
+    reader.skipWhitespaces();
+
+    if (reader.remaining() <= 0)
+    {
+      // This means that the value was empty or contained only
+      // whitespace. That is illegal.
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_EMPTY_VALUE.get();
+      throw DecodeException.error(message);
+    }
+
+    // The next character must be an open parenthesis. If it is not,
+    // then that is an error.
+    final char c = reader.read();
+    if (c != '(')
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS
+          .get(definition, (reader.pos() - 1), String.valueOf(c));
+      throw DecodeException.error(message);
+    }
+
+    // Skip over any spaces immediately following the opening
+    // parenthesis.
+    reader.skipWhitespaces();
+
+    // The next set of characters must be the OID.
+    final String normalized = ObjectIdentifierEqualityMatchingRuleImpl
+        .resolveNames(schema, SchemaUtils.readOID(reader));
+    return ByteString.valueOf(normalized);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..bd30880
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringEqualityMatchingRuleImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines the octetStringMatch matching rule defined in X.520. It
+ * will be used as the default equality matching rule for the binary and octet
+ * string syntaxes.
+ */
+final class OctetStringEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return value.toByteString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..0777d61
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringOrderingMatchingRuleImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines the octetStringOrderingMatch matching rule defined in
+ * X.520. This will be the default ordering matching rule for the binary and
+ * octet string syntaxes.
+ */
+final class OctetStringOrderingMatchingRuleImpl extends
+    AbstractOrderingMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return value.toByteString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..ecee397
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSubstringMatchingRuleImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines the octetStringSubstringsMatch matching rule defined in
+ * X.520. It will be used as the default substring matching rule for the binary
+ * and octet string syntaxes.
+ */
+final class OctetStringSubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return value.toByteString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSyntaxImpl.java
new file mode 100644
index 0000000..10fc033
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OctetStringSyntaxImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_OCTET_STRING_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the octet string attribute syntax, which is equivalent
+ * to the binary syntax and should be considered a replacement for it. Equality,
+ * ordering, and substring matching will be allowed by default.
+ */
+final class OctetStringSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_OCTET_STRING_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the octet string syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OtherMailboxSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OtherMailboxSyntaxImpl.java
new file mode 100644
index 0000000..610733b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/OtherMailboxSyntaxImpl.java
@@ -0,0 +1,173 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_LIST_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_LIST_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_OTHER_MAILBOX_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the other mailbox attribute syntax, which consists of a
+ * printable string component (the mailbox type) followed by a dollar sign and
+ * an IA5 string component (the mailbox). Equality and substring matching will
+ * be allowed by default.
+ */
+final class OtherMailboxSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_LIST_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_OTHER_MAILBOX_NAME;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_LIST_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Check to see if the provided value was null. If so, then that's
+    // not acceptable.
+    if (value == null)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE.get());
+      return false;
+    }
+
+    // Get the value as a string and determine its length. If it is
+    // empty, then that's not acceptable.
+    final String valueString = value.toString();
+    final int valueLength = valueString.length();
+    if (valueLength == 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE.get());
+      return false;
+    }
+
+    // Iterate through the characters in the vale until we find a dollar
+    // sign. Every character up to that point must be a printable string
+    // character.
+    int pos = 0;
+    for (; pos < valueLength; pos++)
+    {
+      final char c = valueString.charAt(pos);
+      if (c == '$')
+      {
+        if (pos == 0)
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE
+              .get(valueString));
+          return false;
+        }
+
+        pos++;
+        break;
+      }
+      else if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+      {
+
+        invalidReason.append(ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR
+            .get(valueString, String.valueOf(c), pos));
+        return false;
+      }
+    }
+
+    // Make sure there is at least one character left for the mailbox.
+    if (pos >= valueLength)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX
+          .get(valueString));
+      return false;
+    }
+
+    // The remaining characters in the value must be IA5 (ASCII)
+    // characters.
+    for (; pos < valueLength; pos++)
+    {
+      final char c = valueString.charAt(pos);
+      if (c != (c & 0x7F))
+      {
+
+        invalidReason.append(ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR.get(
+            valueString, String.valueOf(c), pos));
+        return false;
+      }
+    }
+
+    // If we've gotten here, then the value is OK.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PostalAddressSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PostalAddressSyntaxImpl.java
new file mode 100644
index 0000000..b1d0102
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PostalAddressSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_POSTAL_ADDRESS_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the postal address attribute syntax, which is a list of
+ * UCS (Universal Character Set, as defined in the ISO 10646 specification and
+ * includes UTF-8 and UTF-16) strings separated by dollar signs. By default,
+ * they will be treated in a case-insensitive manner, and equality and substring
+ * matching will be allowed.
+ */
+final class PostalAddressSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_POSTAL_ADDRESS_NAME;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We'll allow any value.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..0d6f9a9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class implements the presentationAddressMatch matching rule defined in
+ * X.520 and referenced in RFC 2252. However, since this matching rule and the
+ * associated syntax have been deprecated, this matching rule behaves exactly
+ * like the caseIgnoreMatch rule.
+ */
+final class PresentationAddressEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressSyntaxImpl.java
new file mode 100644
index 0000000..c3d2e62
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PresentationAddressSyntaxImpl.java
@@ -0,0 +1,112 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the presentation address attribute syntax, which is
+ * defined in RFC 1278. However, because this LDAP syntax is being deprecated,
+ * this implementation behaves exactly like the directory string syntax.
+ */
+final class PresentationAddressSyntaxImpl extends AbstractSyntaxImpl
+{
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_PRESENTATION_ADDRESS_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We will accept any value for this syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PrintableStringSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PrintableStringSyntaxImpl.java
new file mode 100644
index 0000000..eb4cba3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/PrintableStringSyntaxImpl.java
@@ -0,0 +1,248 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.
+  WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE;
+import static com.sun.opends.sdk.messages.Messages.
+  WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER;
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the printable string attribute syntax, which is simply
+ * a string of characters from a limited ASCII character set (uppercase and
+ * lowercase letters, numeric digits, the space, and a set of various symbols).
+ * By default, they will be treated in a case-insensitive manner, and equality,
+ * ordering, substring, and approximate matching will be allowed.
+ */
+final class PrintableStringSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  /**
+   * Indicates whether the provided character is a valid printable character.
+   *
+   * @param c
+   *          The character for which to make the determination.
+   * @return <CODE>true</CODE> if the provided character is a printable
+   *         character, or <CODE>false</CODE> if not.
+   */
+  static boolean isPrintableCharacter(final char c)
+  {
+    switch (c)
+    {
+    case 'a':
+    case 'b':
+    case 'c':
+    case 'd':
+    case 'e':
+    case 'f':
+    case 'g':
+    case 'h':
+    case 'i':
+    case 'j':
+    case 'k':
+    case 'l':
+    case 'm':
+    case 'n':
+    case 'o':
+    case 'p':
+    case 'q':
+    case 'r':
+    case 's':
+    case 't':
+    case 'u':
+    case 'v':
+    case 'w':
+    case 'x':
+    case 'y':
+    case 'z':
+    case 'A':
+    case 'B':
+    case 'C':
+    case 'D':
+    case 'E':
+    case 'F':
+    case 'G':
+    case 'H':
+    case 'I':
+    case 'J':
+    case 'K':
+    case 'L':
+    case 'M':
+    case 'N':
+    case 'O':
+    case 'P':
+    case 'Q':
+    case 'R':
+    case 'S':
+    case 'T':
+    case 'U':
+    case 'V':
+    case 'W':
+    case 'X':
+    case 'Y':
+    case 'Z':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '\'':
+    case '(':
+    case ')':
+    case '+':
+    case ',':
+    case '-':
+    case '.':
+    case '=':
+    case '/':
+    case ':':
+    case '?':
+    case ' ':
+      return true;
+    default:
+      return false;
+    }
+  }
+
+
+
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_PRINTABLE_STRING_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Check to see if the provided value was null. If so, then that's
+    // not acceptable.
+    if (value == null)
+    {
+
+      invalidReason.append(WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE.get());
+      return false;
+    }
+
+    // Get the value as a string and determine its length. If it is
+    // empty, then that's not acceptable.
+    final String valueString = value.toString();
+    final int valueLength = valueString.length();
+    if (valueLength == 0)
+    {
+
+      invalidReason.append(WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE.get());
+      return false;
+    }
+
+    // Iterate through all the characters and see if they are
+    // acceptable.
+    for (int i = 0; i < valueLength; i++)
+    {
+      final char c = valueString.charAt(i);
+      if (!isPrintableCharacter(c))
+      {
+
+        invalidReason
+            .append(WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER.get(
+                valueString, String.valueOf(c), i));
+        return false;
+      }
+    }
+
+    // If we've gotten here, then the value is OK.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..7d988fa
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class implements the protocolInformationMatch matching rule defined in
+ * X.520 and referenced in RFC 2252. However, since this matching rule and the
+ * associated syntax have been deprecated, this matching rule behaves exactly
+ * like the caseIgnoreMatch rule.
+ */
+final class ProtocolInformationEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return SchemaConstants.SINGLE_SPACE_VALUE;
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationSyntaxImpl.java
new file mode 100644
index 0000000..de40958
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/ProtocolInformationSyntaxImpl.java
@@ -0,0 +1,113 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the protocol information attribute syntax, which is
+ * being deprecated. As such, this implementation behaves exactly like the
+ * directory string syntax.
+ */
+final class ProtocolInformationSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_PROTOCOL_INFORMATION_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We will accept any value for this syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/RegexSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/RegexSyntaxImpl.java
new file mode 100644
index 0000000..5481937
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/RegexSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_VALUE;
+import static org.opends.sdk.schema.SchemaConstants.AMR_DOUBLE_METAPHONE_OID;
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+
+import java.util.regex.Pattern;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class provides a regex mechanism where a new syntax and its
+ * corresponding matching rules can be created on-the-fly. A regex syntax is an
+ * LDAPSyntaxDescriptionSyntax with X-PATTERN extension.
+ */
+final class RegexSyntaxImpl extends AbstractSyntaxImpl
+{
+  // The Pattern associated with the regex.
+  private final Pattern pattern;
+
+
+
+  RegexSyntaxImpl(final Pattern pattern)
+  {
+    Validator.ensureNotNull(pattern);
+    this.pattern = pattern;
+  }
+
+
+
+  @Override
+  public String getApproximateMatchingRule()
+  {
+    return AMR_DOUBLE_METAPHONE_OID;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return "Regex(" + pattern.toString() + ")";
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    final String strValue = value.toString();
+    final boolean matches = pattern.matcher(strValue).matches();
+    if (!matches)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_VALUE
+          .get(strValue, pattern.pattern());
+      invalidReason.append(message);
+    }
+    return matches;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Schema.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Schema.java
new file mode 100644
index 0000000..d984613
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Schema.java
@@ -0,0 +1,2617 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.opends.sdk.*;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.Responses;
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+
+import com.sun.opends.sdk.util.FutureResultTransformer;
+import com.sun.opends.sdk.util.RecursiveFutureResult;
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class defines a data structure that holds information about the
+ * components of the LDAP schema. It includes the following kinds of elements:
+ * <UL>
+ * <LI>Attribute type definitions</LI>
+ * <LI>Object class definitions</LI>
+ * <LI>Attribute syntax definitions</LI>
+ * <LI>Matching rule definitions</LI>
+ * <LI>Matching rule use definitions</LI>
+ * <LI>DIT content rule definitions</LI>
+ * <LI>DIT structure rule definitions</LI>
+ * <LI>Name form definitions</LI>
+ * </UL>
+ */
+public final class Schema
+{
+  private static final class EmptyImpl implements Impl
+  {
+    private final SchemaCompatOptions options;
+
+
+
+    private EmptyImpl()
+    {
+      this.options = SchemaCompatOptions.defaultOptions();
+    }
+
+
+
+    public AttributeType getAttributeType(final String name)
+    {
+      // Construct an placeholder attribute type with the given name,
+      // the default matching rule, and the default syntax. The OID of
+      // the attribute will be the normalized OID alias with "-oid"
+      // appended to the given name.
+      final StringBuilder builder = new StringBuilder(name.length() + 4);
+      StaticUtils.toLowerCase(name, builder);
+      builder.append("-oid");
+      final String noid = builder.toString();
+
+      return new AttributeType(noid, Collections.singletonList(name), "",
+          Schema.getDefaultMatchingRule(), Schema.getDefaultSyntax());
+    }
+
+
+
+    public Collection<AttributeType> getAttributeTypes()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public List<AttributeType> getAttributeTypesByName(final String name)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public DITContentRule getDITContentRule(final String name)
+        throws UnknownSchemaElementException
+    {
+      throw new UnknownSchemaElementException(WARN_DCR_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<DITContentRule> getDITContentRules()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<DITContentRule> getDITContentRulesByName(final String name)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public DITStructureRule getDITStructureRule(final int ruleID)
+        throws UnknownSchemaElementException
+    {
+      throw new UnknownSchemaElementException(WARN_DSR_UNKNOWN.get(String
+          .valueOf(ruleID)));
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStructureRulesByName(
+        final String name)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStructureRulesByNameForm(
+        final NameForm nameForm)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStuctureRules()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public MatchingRule getMatchingRule(final String name)
+        throws UnknownSchemaElementException
+    {
+      throw new UnknownSchemaElementException(WARN_MR_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<MatchingRule> getMatchingRules()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<MatchingRule> getMatchingRulesByName(final String name)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
+        throws UnknownSchemaElementException
+    {
+      return getMatchingRuleUse(matchingRule.getOID());
+    }
+
+
+
+    public MatchingRuleUse getMatchingRuleUse(final String name)
+        throws UnknownSchemaElementException
+    {
+      throw new UnknownSchemaElementException(WARN_MRU_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<MatchingRuleUse> getMatchingRuleUses()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<MatchingRuleUse> getMatchingRuleUsesByName(
+        final String name)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public NameForm getNameForm(final String name)
+        throws UnknownSchemaElementException
+    {
+      throw new UnknownSchemaElementException(WARN_NAMEFORM_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<NameForm> getNameFormByObjectClass(
+        final ObjectClass structuralClass)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<NameForm> getNameForms()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<NameForm> getNameFormsByName(final String name)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public ObjectClass getObjectClass(final String name)
+        throws UnknownSchemaElementException
+    {
+      throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN
+          .get(name));
+    }
+
+
+
+    public Collection<ObjectClass> getObjectClasses()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<ObjectClass> getObjectClassesByName(final String name)
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public SchemaCompatOptions getSchemaCompatOptions()
+    {
+      return options;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName()
+    {
+      return "Empty Schema";
+    }
+
+
+
+    public Syntax getSyntax(final String numericOID)
+    {
+      // Fake up a syntax substituted by the default syntax.
+      return new Syntax(numericOID);
+    }
+
+
+
+    public Collection<Syntax> getSyntaxes()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public Collection<LocalizableMessage> getWarnings()
+    {
+      return Collections.emptyList();
+    }
+
+
+
+    public boolean hasAttributeType(final String name)
+    {
+      // In theory a non-strict schema always contains the requested
+      // attribute type, so we could always return true. However, we
+      // should provide a way for callers to differentiate between a
+      // real attribute type and a faked up attribute type.
+      return false;
+    }
+
+
+
+    public boolean hasDITContentRule(final String name)
+    {
+      return false;
+    }
+
+
+
+    public boolean hasDITStructureRule(final int ruleID)
+    {
+      return false;
+    }
+
+
+
+    public boolean hasMatchingRule(final String name)
+    {
+      return false;
+    }
+
+
+
+    public boolean hasMatchingRuleUse(final String name)
+    {
+      return false;
+    }
+
+
+
+    public boolean hasNameForm(final String name)
+    {
+      return false;
+    }
+
+
+
+    public boolean hasObjectClass(final String name)
+    {
+      return false;
+    }
+
+
+
+    public boolean hasSyntax(final String numericOID)
+    {
+      return false;
+    }
+
+
+
+    public boolean isStrict()
+    {
+      return false;
+    }
+  }
+
+
+
+  private static interface Impl
+  {
+    AttributeType getAttributeType(String name)
+        throws UnknownSchemaElementException;
+
+
+
+    Collection<AttributeType> getAttributeTypes();
+
+
+
+    List<AttributeType> getAttributeTypesByName(String name);
+
+
+
+    DITContentRule getDITContentRule(String name)
+        throws UnknownSchemaElementException;
+
+
+
+    Collection<DITContentRule> getDITContentRules();
+
+
+
+    Collection<DITContentRule> getDITContentRulesByName(String name);
+
+
+
+    DITStructureRule getDITStructureRule(int ruleID)
+        throws UnknownSchemaElementException;
+
+
+
+    Collection<DITStructureRule> getDITStructureRulesByName(String name);
+
+
+
+    Collection<DITStructureRule> getDITStructureRulesByNameForm(
+        NameForm nameForm);
+
+
+
+    Collection<DITStructureRule> getDITStuctureRules();
+
+
+
+    MatchingRule getMatchingRule(String name)
+        throws UnknownSchemaElementException;
+
+
+
+    Collection<MatchingRule> getMatchingRules();
+
+
+
+    Collection<MatchingRule> getMatchingRulesByName(String name);
+
+
+
+    MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule)
+        throws UnknownSchemaElementException;
+
+
+
+    MatchingRuleUse getMatchingRuleUse(String name)
+        throws UnknownSchemaElementException;
+
+
+
+    Collection<MatchingRuleUse> getMatchingRuleUses();
+
+
+
+    Collection<MatchingRuleUse> getMatchingRuleUsesByName(String name);
+
+
+
+    NameForm getNameForm(String name) throws UnknownSchemaElementException;
+
+
+
+    Collection<NameForm> getNameFormByObjectClass(ObjectClass structuralClass);
+
+
+
+    Collection<NameForm> getNameForms();
+
+
+
+    Collection<NameForm> getNameFormsByName(String name);
+
+
+
+    ObjectClass getObjectClass(String name)
+        throws UnknownSchemaElementException;
+
+
+
+    Collection<ObjectClass> getObjectClasses();
+
+
+
+    Collection<ObjectClass> getObjectClassesByName(String name);
+
+
+
+    SchemaCompatOptions getSchemaCompatOptions();
+
+
+
+    String getSchemaName();
+
+
+
+    Syntax getSyntax(String numericOID) throws UnknownSchemaElementException;
+
+
+
+    Collection<Syntax> getSyntaxes();
+
+
+
+    Collection<LocalizableMessage> getWarnings();
+
+
+
+    boolean hasAttributeType(String name);
+
+
+
+    boolean hasDITContentRule(String name);
+
+
+
+    boolean hasDITStructureRule(int ruleID);
+
+
+
+    boolean hasMatchingRule(String name);
+
+
+
+    boolean hasMatchingRuleUse(String name);
+
+
+
+    boolean hasNameForm(String name);
+
+
+
+    boolean hasObjectClass(String name);
+
+
+
+    boolean hasSyntax(String numericOID);
+
+
+
+    boolean isStrict();
+  }
+
+
+
+  private static final class NonStrictImpl implements Impl
+  {
+    private final Impl strictImpl;
+
+
+
+    private NonStrictImpl(final Impl strictImpl)
+    {
+      this.strictImpl = strictImpl;
+    }
+
+
+
+    public AttributeType getAttributeType(final String name)
+        throws UnknownSchemaElementException
+    {
+      if (!strictImpl.hasAttributeType(name))
+      {
+        // Construct an placeholder attribute type with the given name,
+        // the default matching rule, and the default syntax. The OID of
+        // the attribute will be the normalized OID alias with "-oid"
+        // appended to the given name.
+        final StringBuilder builder = new StringBuilder(name.length() + 4);
+        StaticUtils.toLowerCase(name, builder);
+        builder.append("-oid");
+        final String noid = builder.toString();
+
+        return new AttributeType(noid, Collections.singletonList(name), "",
+            Schema.getDefaultMatchingRule(), Schema.getDefaultSyntax());
+      }
+      return strictImpl.getAttributeType(name);
+    }
+
+
+
+    public Collection<AttributeType> getAttributeTypes()
+    {
+      return strictImpl.getAttributeTypes();
+    }
+
+
+
+    public List<AttributeType> getAttributeTypesByName(final String name)
+    {
+      return strictImpl.getAttributeTypesByName(name);
+    }
+
+
+
+    public DITContentRule getDITContentRule(final String name)
+        throws UnknownSchemaElementException
+    {
+      return strictImpl.getDITContentRule(name);
+    }
+
+
+
+    public Collection<DITContentRule> getDITContentRules()
+    {
+      return strictImpl.getDITContentRules();
+    }
+
+
+
+    public Collection<DITContentRule> getDITContentRulesByName(final String name)
+    {
+      return strictImpl.getDITContentRulesByName(name);
+    }
+
+
+
+    public DITStructureRule getDITStructureRule(final int ruleID)
+        throws UnknownSchemaElementException
+    {
+      return strictImpl.getDITStructureRule(ruleID);
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStructureRulesByName(
+        final String name)
+    {
+      return strictImpl.getDITStructureRulesByName(name);
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStructureRulesByNameForm(
+        final NameForm nameForm)
+    {
+      return strictImpl.getDITStructureRulesByNameForm(nameForm);
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStuctureRules()
+    {
+      return strictImpl.getDITStuctureRules();
+    }
+
+
+
+    public MatchingRule getMatchingRule(final String name)
+        throws UnknownSchemaElementException
+    {
+      return strictImpl.getMatchingRule(name);
+    }
+
+
+
+    public Collection<MatchingRule> getMatchingRules()
+    {
+      return strictImpl.getMatchingRules();
+    }
+
+
+
+    public Collection<MatchingRule> getMatchingRulesByName(final String name)
+    {
+      return strictImpl.getMatchingRulesByName(name);
+    }
+
+
+
+    public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
+        throws UnknownSchemaElementException
+    {
+      return strictImpl.getMatchingRuleUse(matchingRule);
+    }
+
+
+
+    public MatchingRuleUse getMatchingRuleUse(final String name)
+        throws UnknownSchemaElementException
+    {
+      return strictImpl.getMatchingRuleUse(name);
+    }
+
+
+
+    public Collection<MatchingRuleUse> getMatchingRuleUses()
+    {
+      return strictImpl.getMatchingRuleUses();
+    }
+
+
+
+    public Collection<MatchingRuleUse> getMatchingRuleUsesByName(
+        final String name)
+    {
+      return strictImpl.getMatchingRuleUsesByName(name);
+    }
+
+
+
+    public NameForm getNameForm(final String name)
+        throws UnknownSchemaElementException
+    {
+      return strictImpl.getNameForm(name);
+    }
+
+
+
+    public Collection<NameForm> getNameFormByObjectClass(
+        final ObjectClass structuralClass)
+    {
+      return strictImpl.getNameFormByObjectClass(structuralClass);
+    }
+
+
+
+    public Collection<NameForm> getNameForms()
+    {
+      return strictImpl.getNameForms();
+    }
+
+
+
+    public Collection<NameForm> getNameFormsByName(final String name)
+    {
+      return strictImpl.getNameFormsByName(name);
+    }
+
+
+
+    public ObjectClass getObjectClass(final String name)
+        throws UnknownSchemaElementException
+    {
+      return strictImpl.getObjectClass(name);
+    }
+
+
+
+    public Collection<ObjectClass> getObjectClasses()
+    {
+      return strictImpl.getObjectClasses();
+    }
+
+
+
+    public Collection<ObjectClass> getObjectClassesByName(final String name)
+    {
+      return strictImpl.getObjectClassesByName(name);
+    }
+
+
+
+    public SchemaCompatOptions getSchemaCompatOptions()
+    {
+      return strictImpl.getSchemaCompatOptions();
+    }
+
+
+
+    public String getSchemaName()
+    {
+      return strictImpl.getSchemaName();
+    }
+
+
+
+    public Syntax getSyntax(final String numericOID)
+    {
+      if (!strictImpl.hasSyntax(numericOID))
+      {
+        return new Syntax(numericOID);
+      }
+      return strictImpl.getSyntax(numericOID);
+    }
+
+
+
+    public Collection<Syntax> getSyntaxes()
+    {
+      return strictImpl.getSyntaxes();
+    }
+
+
+
+    public Collection<LocalizableMessage> getWarnings()
+    {
+      return strictImpl.getWarnings();
+    }
+
+
+
+    public boolean hasAttributeType(final String name)
+    {
+      // In theory a non-strict schema always contains the requested
+      // attribute type, so we could always return true. However, we
+      // should provide a way for callers to differentiate between a
+      // real attribute type and a faked up attribute type.
+      return strictImpl.hasAttributeType(name);
+    }
+
+
+
+    public boolean hasDITContentRule(final String name)
+    {
+      return strictImpl.hasDITContentRule(name);
+    }
+
+
+
+    public boolean hasDITStructureRule(final int ruleID)
+    {
+      return strictImpl.hasDITStructureRule(ruleID);
+    }
+
+
+
+    public boolean hasMatchingRule(final String name)
+    {
+      return strictImpl.hasMatchingRule(name);
+    }
+
+
+
+    public boolean hasMatchingRuleUse(final String name)
+    {
+      return strictImpl.hasMatchingRuleUse(name);
+    }
+
+
+
+    public boolean hasNameForm(final String name)
+    {
+      return strictImpl.hasNameForm(name);
+    }
+
+
+
+    public boolean hasObjectClass(final String name)
+    {
+      return strictImpl.hasObjectClass(name);
+    }
+
+
+
+    public boolean hasSyntax(final String numericOID)
+    {
+      return strictImpl.hasSyntax(numericOID);
+    }
+
+
+
+    public boolean isStrict()
+    {
+      return false;
+    }
+  }
+
+
+
+  private static final class StrictImpl implements Impl
+  {
+    private final Map<Integer, DITStructureRule> id2StructureRules;
+
+    private final Map<String, List<AttributeType>> name2AttributeTypes;
+
+    private final Map<String, List<DITContentRule>> name2ContentRules;
+
+    private final Map<String, List<MatchingRule>> name2MatchingRules;
+
+    private final Map<String, List<MatchingRuleUse>> name2MatchingRuleUses;
+
+    private final Map<String, List<NameForm>> name2NameForms;
+
+    private final Map<String, List<ObjectClass>> name2ObjectClasses;
+
+    private final Map<String, List<DITStructureRule>> name2StructureRules;
+
+    private final Map<String, List<DITStructureRule>> nameForm2StructureRules;
+
+    private final Map<String, AttributeType> numericOID2AttributeTypes;
+
+    private final Map<String, DITContentRule> numericOID2ContentRules;
+
+    private final Map<String, MatchingRule> numericOID2MatchingRules;
+
+    private final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses;
+
+    private final Map<String, NameForm> numericOID2NameForms;
+
+    private final Map<String, ObjectClass> numericOID2ObjectClasses;
+
+    private final Map<String, Syntax> numericOID2Syntaxes;
+
+    private final Map<String, List<NameForm>> objectClass2NameForms;
+
+    private final SchemaCompatOptions options;
+
+    private final List<LocalizableMessage> warnings;
+
+    private final String schemaName;
+
+
+
+    private StrictImpl(final String schemaName,
+        final Map<String, Syntax> numericOID2Syntaxes,
+        final Map<String, MatchingRule> numericOID2MatchingRules,
+        final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses,
+        final Map<String, AttributeType> numericOID2AttributeTypes,
+        final Map<String, ObjectClass> numericOID2ObjectClasses,
+        final Map<String, NameForm> numericOID2NameForms,
+        final Map<String, DITContentRule> numericOID2ContentRules,
+        final Map<Integer, DITStructureRule> id2StructureRules,
+        final Map<String, List<MatchingRule>> name2MatchingRules,
+        final Map<String, List<MatchingRuleUse>> name2MatchingRuleUses,
+        final Map<String, List<AttributeType>> name2AttributeTypes,
+        final Map<String, List<ObjectClass>> name2ObjectClasses,
+        final Map<String, List<NameForm>> name2NameForms,
+        final Map<String, List<DITContentRule>> name2ContentRules,
+        final Map<String, List<DITStructureRule>> name2StructureRules,
+        final Map<String, List<NameForm>> objectClass2NameForms,
+        final Map<String, List<DITStructureRule>> nameForm2StructureRules,
+        final SchemaCompatOptions options,
+        final List<LocalizableMessage> warnings)
+    {
+      this.schemaName = schemaName;
+      this.numericOID2Syntaxes = Collections
+          .unmodifiableMap(numericOID2Syntaxes);
+      this.numericOID2MatchingRules = Collections
+          .unmodifiableMap(numericOID2MatchingRules);
+      this.numericOID2MatchingRuleUses = Collections
+          .unmodifiableMap(numericOID2MatchingRuleUses);
+      this.numericOID2AttributeTypes = Collections
+          .unmodifiableMap(numericOID2AttributeTypes);
+      this.numericOID2ObjectClasses = Collections
+          .unmodifiableMap(numericOID2ObjectClasses);
+      this.numericOID2NameForms = Collections
+          .unmodifiableMap(numericOID2NameForms);
+      this.numericOID2ContentRules = Collections
+          .unmodifiableMap(numericOID2ContentRules);
+      this.id2StructureRules = Collections.unmodifiableMap(id2StructureRules);
+      this.name2MatchingRules = Collections.unmodifiableMap(name2MatchingRules);
+      this.name2MatchingRuleUses = Collections
+          .unmodifiableMap(name2MatchingRuleUses);
+      this.name2AttributeTypes = Collections
+          .unmodifiableMap(name2AttributeTypes);
+      this.name2ObjectClasses = Collections.unmodifiableMap(name2ObjectClasses);
+      this.name2NameForms = Collections.unmodifiableMap(name2NameForms);
+      this.name2ContentRules = Collections.unmodifiableMap(name2ContentRules);
+      this.name2StructureRules = Collections
+          .unmodifiableMap(name2StructureRules);
+      this.objectClass2NameForms = Collections
+          .unmodifiableMap(objectClass2NameForms);
+      this.nameForm2StructureRules = Collections
+          .unmodifiableMap(nameForm2StructureRules);
+      this.options = options;
+      this.warnings = Collections.unmodifiableList(warnings);
+    }
+
+
+
+    public AttributeType getAttributeType(final String name)
+        throws UnknownSchemaElementException
+    {
+      final AttributeType type = numericOID2AttributeTypes.get(name);
+      if (type != null)
+      {
+        return type;
+      }
+      final List<AttributeType> attributes = name2AttributeTypes
+          .get(StaticUtils.toLowerCase(name));
+      if (attributes != null)
+      {
+        if (attributes.size() == 1)
+        {
+          return attributes.get(0);
+        }
+        throw new UnknownSchemaElementException(WARN_ATTR_TYPE_AMBIGIOUS
+            .get(name));
+      }
+      throw new UnknownSchemaElementException(WARN_ATTR_TYPE_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<AttributeType> getAttributeTypes()
+    {
+      return numericOID2AttributeTypes.values();
+    }
+
+
+
+    public List<AttributeType> getAttributeTypesByName(final String name)
+    {
+      final List<AttributeType> attributes = name2AttributeTypes
+          .get(StaticUtils.toLowerCase(name));
+      if (attributes == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return attributes;
+      }
+    }
+
+
+
+    public DITContentRule getDITContentRule(final String name)
+        throws UnknownSchemaElementException
+    {
+      final DITContentRule rule = numericOID2ContentRules.get(name);
+      if (rule != null)
+      {
+        return rule;
+      }
+      final List<DITContentRule> rules = name2ContentRules.get(StaticUtils
+          .toLowerCase(name));
+      if (rules != null)
+      {
+        if (rules.size() == 1)
+        {
+          return rules.get(0);
+        }
+        throw new UnknownSchemaElementException(WARN_DCR_AMBIGIOUS.get(name));
+      }
+      throw new UnknownSchemaElementException(WARN_DCR_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<DITContentRule> getDITContentRules()
+    {
+      return numericOID2ContentRules.values();
+    }
+
+
+
+    public Collection<DITContentRule> getDITContentRulesByName(final String name)
+    {
+      final List<DITContentRule> rules = name2ContentRules.get(StaticUtils
+          .toLowerCase(name));
+      if (rules == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return rules;
+      }
+    }
+
+
+
+    public DITStructureRule getDITStructureRule(final int ruleID)
+        throws UnknownSchemaElementException
+    {
+      final DITStructureRule rule = id2StructureRules.get(ruleID);
+      if (rule == null)
+      {
+        throw new UnknownSchemaElementException(WARN_DSR_UNKNOWN.get(String
+            .valueOf(ruleID)));
+      }
+      return rule;
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStructureRulesByName(
+        final String name)
+    {
+      final List<DITStructureRule> rules = name2StructureRules.get(StaticUtils
+          .toLowerCase(name));
+      if (rules == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return rules;
+      }
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStructureRulesByNameForm(
+        final NameForm nameForm)
+    {
+      final List<DITStructureRule> rules = nameForm2StructureRules.get(nameForm
+          .getOID());
+      if (rules == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return rules;
+      }
+    }
+
+
+
+    public Collection<DITStructureRule> getDITStuctureRules()
+    {
+      return id2StructureRules.values();
+    }
+
+
+
+    public MatchingRule getMatchingRule(final String name)
+        throws UnknownSchemaElementException
+    {
+      final MatchingRule rule = numericOID2MatchingRules.get(name);
+      if (rule != null)
+      {
+        return rule;
+      }
+      final List<MatchingRule> rules = name2MatchingRules.get(StaticUtils
+          .toLowerCase(name));
+      if (rules != null)
+      {
+        if (rules.size() == 1)
+        {
+          return rules.get(0);
+        }
+        throw new UnknownSchemaElementException(WARN_MR_AMBIGIOUS.get(name));
+      }
+      throw new UnknownSchemaElementException(WARN_MR_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<MatchingRule> getMatchingRules()
+    {
+      return numericOID2MatchingRules.values();
+    }
+
+
+
+    public Collection<MatchingRule> getMatchingRulesByName(final String name)
+    {
+      final List<MatchingRule> rules = name2MatchingRules.get(StaticUtils
+          .toLowerCase(name));
+      if (rules == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return rules;
+      }
+    }
+
+
+
+    public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
+        throws UnknownSchemaElementException
+    {
+      return getMatchingRuleUse(matchingRule.getOID());
+    }
+
+
+
+    public MatchingRuleUse getMatchingRuleUse(final String name)
+        throws UnknownSchemaElementException
+    {
+      final MatchingRuleUse rule = numericOID2MatchingRuleUses.get(name);
+      if (rule != null)
+      {
+        return rule;
+      }
+      final List<MatchingRuleUse> uses = name2MatchingRuleUses.get(StaticUtils
+          .toLowerCase(name));
+      if (uses != null)
+      {
+        if (uses.size() == 1)
+        {
+          return uses.get(0);
+        }
+        throw new UnknownSchemaElementException(WARN_MRU_AMBIGIOUS.get(name));
+      }
+      throw new UnknownSchemaElementException(WARN_MRU_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<MatchingRuleUse> getMatchingRuleUses()
+    {
+      return numericOID2MatchingRuleUses.values();
+    }
+
+
+
+    public Collection<MatchingRuleUse> getMatchingRuleUsesByName(
+        final String name)
+    {
+      final List<MatchingRuleUse> rules = name2MatchingRuleUses.get(StaticUtils
+          .toLowerCase(name));
+      if (rules == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return rules;
+      }
+    }
+
+
+
+    public NameForm getNameForm(final String name)
+        throws UnknownSchemaElementException
+    {
+      final NameForm form = numericOID2NameForms.get(name);
+      if (form != null)
+      {
+        return form;
+      }
+      final List<NameForm> forms = name2NameForms.get(StaticUtils
+          .toLowerCase(name));
+      if (forms != null)
+      {
+        if (forms.size() == 1)
+        {
+          return forms.get(0);
+        }
+        throw new UnknownSchemaElementException(WARN_NAMEFORM_AMBIGIOUS
+            .get(name));
+      }
+      throw new UnknownSchemaElementException(WARN_NAMEFORM_UNKNOWN.get(name));
+    }
+
+
+
+    public Collection<NameForm> getNameFormByObjectClass(
+        final ObjectClass structuralClass)
+    {
+      final List<NameForm> forms = objectClass2NameForms.get(structuralClass
+          .getOID());
+      if (forms == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return forms;
+      }
+    }
+
+
+
+    public Collection<NameForm> getNameForms()
+    {
+      return numericOID2NameForms.values();
+    }
+
+
+
+    public Collection<NameForm> getNameFormsByName(final String name)
+    {
+      final List<NameForm> forms = name2NameForms.get(StaticUtils
+          .toLowerCase(name));
+      if (forms == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return forms;
+      }
+    }
+
+
+
+    public ObjectClass getObjectClass(final String name)
+        throws UnknownSchemaElementException
+    {
+      final ObjectClass oc = numericOID2ObjectClasses.get(name);
+      if (oc != null)
+      {
+        return oc;
+      }
+      final List<ObjectClass> classes = name2ObjectClasses.get(StaticUtils
+          .toLowerCase(name));
+      if (classes != null)
+      {
+        if (classes.size() == 1)
+        {
+          return classes.get(0);
+        }
+        throw new UnknownSchemaElementException(WARN_OBJECTCLASS_AMBIGIOUS
+            .get(name));
+      }
+      throw new UnknownSchemaElementException(WARN_OBJECTCLASS_UNKNOWN
+          .get(name));
+    }
+
+
+
+    public Collection<ObjectClass> getObjectClasses()
+    {
+      return numericOID2ObjectClasses.values();
+    }
+
+
+
+    public Collection<ObjectClass> getObjectClassesByName(final String name)
+    {
+      final List<ObjectClass> classes = name2ObjectClasses.get(StaticUtils
+          .toLowerCase(name));
+      if (classes == null)
+      {
+        return Collections.emptyList();
+      }
+      else
+      {
+        return classes;
+      }
+    }
+
+
+
+    public SchemaCompatOptions getSchemaCompatOptions()
+    {
+      return options;
+    }
+
+
+
+    public String getSchemaName()
+    {
+      return schemaName;
+    }
+
+
+
+    public Syntax getSyntax(final String numericOID)
+        throws UnknownSchemaElementException
+    {
+      final Syntax syntax = numericOID2Syntaxes.get(numericOID);
+      if (syntax == null)
+      {
+        throw new UnknownSchemaElementException(WARN_SYNTAX_UNKNOWN
+            .get(numericOID));
+      }
+      return syntax;
+    }
+
+
+
+    public Collection<Syntax> getSyntaxes()
+    {
+      return numericOID2Syntaxes.values();
+    }
+
+
+
+    public Collection<LocalizableMessage> getWarnings()
+    {
+      return warnings;
+    }
+
+
+
+    public boolean hasAttributeType(final String name)
+    {
+      if (numericOID2AttributeTypes.containsKey(name))
+      {
+        return true;
+      }
+      final List<AttributeType> attributes = name2AttributeTypes
+          .get(StaticUtils.toLowerCase(name));
+      return attributes != null && attributes.size() == 1;
+    }
+
+
+
+    public boolean hasDITContentRule(final String name)
+    {
+      if (numericOID2ContentRules.containsKey(name))
+      {
+        return true;
+      }
+      final List<DITContentRule> rules = name2ContentRules.get(StaticUtils
+          .toLowerCase(name));
+      return rules != null && rules.size() == 1;
+    }
+
+
+
+    public boolean hasDITStructureRule(final int ruleID)
+    {
+      return id2StructureRules.containsKey(ruleID);
+    }
+
+
+
+    public boolean hasMatchingRule(final String name)
+    {
+      if (numericOID2MatchingRules.containsKey(name))
+      {
+        return true;
+      }
+      final List<MatchingRule> rules = name2MatchingRules.get(StaticUtils
+          .toLowerCase(name));
+      return rules != null && rules.size() == 1;
+    }
+
+
+
+    public boolean hasMatchingRuleUse(final String name)
+    {
+      if (numericOID2MatchingRuleUses.containsKey(name))
+      {
+        return true;
+      }
+      final List<MatchingRuleUse> uses = name2MatchingRuleUses.get(StaticUtils
+          .toLowerCase(name));
+      return uses != null && uses.size() == 1;
+    }
+
+
+
+    public boolean hasNameForm(final String name)
+    {
+      if (numericOID2NameForms.containsKey(name))
+      {
+        return true;
+      }
+      final List<NameForm> forms = name2NameForms.get(StaticUtils
+          .toLowerCase(name));
+      return forms != null && forms.size() == 1;
+    }
+
+
+
+    public boolean hasObjectClass(final String name)
+    {
+      if (numericOID2ObjectClasses.containsKey(name))
+      {
+        return true;
+      }
+      final List<ObjectClass> classes = name2ObjectClasses.get(StaticUtils
+          .toLowerCase(name));
+      return classes != null && classes.size() == 1;
+    }
+
+
+
+    public boolean hasSyntax(final String numericOID)
+    {
+      return numericOID2Syntaxes.containsKey(numericOID);
+    }
+
+
+
+    public boolean isStrict()
+    {
+      return true;
+    }
+  }
+
+
+
+  private static final Schema CORE_SCHEMA = CoreSchemaImpl.getInstance();
+
+  private static final Schema EMPTY_SCHEMA = new Schema(new EmptyImpl());
+
+  private static volatile Schema defaultSchema = CoreSchemaImpl.getInstance();
+
+  static final String ATTR_ATTRIBUTE_TYPES = "attributeTypes";
+
+  static final String ATTR_DIT_CONTENT_RULES = "dITContentRules";
+
+  static final String ATTR_DIT_STRUCTURE_RULES = "dITStructureRules";
+
+  static final String ATTR_LDAP_SYNTAXES = "ldapSyntaxes";
+
+  static final String ATTR_MATCHING_RULE_USE = "matchingRuleUse";
+
+  static final String ATTR_MATCHING_RULES = "matchingRules";
+
+  static final String ATTR_NAME_FORMS = "nameForms";
+
+  static final String ATTR_OBJECT_CLASSES = "objectClasses";
+
+  private static final String ATTR_SUBSCHEMA_SUBENTRY = "subschemaSubentry";
+
+  private static final String[] SUBSCHEMA_ATTRS = new String[] {
+      ATTR_LDAP_SYNTAXES.toString(), ATTR_ATTRIBUTE_TYPES.toString(),
+      ATTR_DIT_CONTENT_RULES.toString(), ATTR_DIT_STRUCTURE_RULES.toString(),
+      ATTR_MATCHING_RULE_USE.toString(), ATTR_MATCHING_RULES.toString(),
+      ATTR_NAME_FORMS.toString(), ATTR_OBJECT_CLASSES.toString() };
+
+  private static final Filter SUBSCHEMA_FILTER = Filter.newEqualityMatchFilter(
+      CoreSchema.getObjectClassAttributeType().getNameOrOID(), CoreSchema
+          .getSubschemaObjectClass().getNameOrOID());
+
+  private static final String[] SUBSCHEMA_SUBENTRY_ATTRS = new String[] { ATTR_SUBSCHEMA_SUBENTRY
+      .toString() };
+
+
+
+  /**
+   * Returns the core schema. The core schema is non-strict and contains the
+   * following standard LDAP schema elements:
+   * <ul>
+   * <li><a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
+   * Directory Access Protocol (LDAP): Directory Information Models </a>
+   * <li><a href="http://tools.ietf.org/html/rfc4517">RFC 4517 - Lightweight
+   * Directory Access Protocol (LDAP): Syntaxes and Matching Rules </a>
+   * <li><a href="http://tools.ietf.org/html/rfc4519">RFC 4519 - Lightweight
+   * Directory Access Protocol (LDAP): Schema for User Applications </a>
+   * <li><a href="http://tools.ietf.org/html/rfc4530">RFC 4530 - Lightweight
+   * Directory Access Protocol (LDAP): entryUUID Operational Attribute </a>
+   * <li><a href="http://tools.ietf.org/html/rfc3045">RFC 3045 - Storing Vendor
+   * Information in the LDAP root DSE </a>
+   * <li><a href="http://tools.ietf.org/html/rfc3112">RFC 3112 - LDAP
+   * Authentication Password Schema </a>
+   * </ul>
+   *
+   * @return The core schema.
+   */
+  public static Schema getCoreSchema()
+  {
+    return CORE_SCHEMA;
+  }
+
+
+
+  /**
+   * Returns the default schema which should be used by this application. The
+   * default schema is initially set to the core schema.
+   *
+   * @return The default schema which should be used by this application.
+   */
+  public static Schema getDefaultSchema()
+  {
+    return defaultSchema;
+  }
+
+
+
+  /**
+   * Returns the empty schema. The empty schema is non-strict and does not
+   * contain any schema elements.
+   *
+   * @return The empty schema.
+   */
+  public static Schema getEmptySchema()
+  {
+    return EMPTY_SCHEMA;
+  }
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named subschema
+   * sub-entry.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, the returned future will never return {@code null}.
+   * <p>
+   * This method uses a Search operation to read the schema and does not perform
+   * caching. More specifically, it does not use the
+   * {@link AsynchronousConnection#readSchema} method.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be read.
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code null}.
+   */
+  public static FutureResult<Schema> readSchema(
+      final AsynchronousConnection connection, final DN name,
+      final ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = getReadSchemaSearchRequest(name);
+
+    final FutureResultTransformer<SearchResultEntry, Schema> future =
+      new FutureResultTransformer<SearchResultEntry, Schema>(handler)
+    {
+
+      @Override
+      protected Schema transformResult(final SearchResultEntry result)
+          throws ErrorResultException
+      {
+        return valueOf(result);
+      }
+
+    };
+
+    final FutureResult<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(request, future);
+    future.setFutureResult(innerFuture);
+    return future;
+  }
+
+
+
+  /**
+   * Reads the schema from the Directory Server contained in the named subschema
+   * sub-entry using the provided connection.
+   * <p>
+   * If the requested schema is not returned by the Directory Server then the
+   * request will fail with an {@link EntryNotFoundException}. More
+   * specifically, this method will never return {@code null}.
+   * <p>
+   * This method uses a Search operation to read the schema and does not perform
+   * caching. More specifically, it does not use the
+   * {@link Connection#readSchema} method.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be read.
+   * @param name
+   *          The distinguished name of the subschema sub-entry.
+   * @return The schema from the Directory Server.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code null}.
+   */
+  public static Schema readSchema(final Connection connection, final DN name)
+      throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = getReadSchemaSearchRequest(name);
+    final Entry entry = connection.searchSingleEntry(request);
+    return valueOf(entry);
+  }
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the named
+   * entry.
+   * <p>
+   * If the requested entry or its associated schema are not returned by the
+   * Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, the returned future will
+   * never return {@code null}.
+   * <p>
+   * This implementation first reads the {@code subschemaSubentry} attribute of
+   * the entry in order to identify the schema and then invokes
+   * {@link #readSchema} to read the schema. More specifically, it does not use
+   * the {@link AsynchronousConnection#readSchemaForEntry} method.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be read.
+   * @param name
+   *          The distinguished name of the entry whose schema is to be located.
+   * @param handler
+   *          A result handler which can be used to asynchronously process the
+   *          operation result when it is received, may be {@code null}.
+   * @return A future representing the result of the operation.
+   * @throws UnsupportedOperationException
+   *           If this connection does not support search operations.
+   * @throws IllegalStateException
+   *           If this connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code null}.
+   */
+  public static FutureResult<Schema> readSchemaForEntry(
+      final AsynchronousConnection connection, final DN name,
+      final ResultHandler<? super Schema> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final RecursiveFutureResult<SearchResultEntry, Schema> future =
+      new RecursiveFutureResult<SearchResultEntry, Schema>(handler)
+    {
+
+      @Override
+      protected FutureResult<Schema> chainResult(
+          final SearchResultEntry innerResult,
+          final ResultHandler<? super Schema> handler)
+          throws ErrorResultException
+      {
+        final DN subschemaDN = getSubschemaSubentryDN(name, innerResult);
+        return readSchema(connection, subschemaDN, handler);
+      }
+
+    };
+
+    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
+    final FutureResult<SearchResultEntry> innerFuture = connection
+        .searchSingleEntry(request, future);
+    future.setFutureResult(innerFuture);
+    return future;
+  }
+
+
+
+  /**
+   * Reads the schema from the Directory Server which applies to the named entry
+   * using the provided connection.
+   * <p>
+   * If the requested entry or its associated schema are not returned by the
+   * Directory Server then the request will fail with an
+   * {@link EntryNotFoundException}. More specifically, this method will never
+   * return {@code null}.
+   * <p>
+   * This implementation first reads the {@code subschemaSubentry} attribute of
+   * the entry in order to identify the schema and then invokes
+   * {@link #readSchema} to read the schema. More specifically, it does not use
+   * the {@link Connection#readSchemaForEntry} method.
+   *
+   * @param connection
+   *          A connection to the Directory Server whose schema is to be read.
+   * @param name
+   *          The distinguished name of the entry whose schema is to be located.
+   * @return The schema from the Directory Server which applies to the named
+   *         entry.
+   * @throws ErrorResultException
+   *           If the result code indicates that the request failed for some
+   *           reason.
+   * @throws InterruptedException
+   *           If the current thread was interrupted while waiting.
+   * @throws UnsupportedOperationException
+   *           If the connection does not support search operations.
+   * @throws IllegalStateException
+   *           If the connection has already been closed, i.e. if {@code
+   *           isClosed() == true}.
+   * @throws NullPointerException
+   *           If the {@code connection} or {@code name} was {@code null}.
+   */
+  public static Schema readSchemaForEntry(final Connection connection,
+      final DN name) throws ErrorResultException, InterruptedException,
+      UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
+    final Entry entry = connection.searchSingleEntry(request);
+    final DN subschemaDN = getSubschemaSubentryDN(name, entry);
+
+    return readSchema(connection, subschemaDN);
+  }
+
+
+
+  /**
+   * Sets the default schema which should be used by this application. The
+   * default schema is initially set to the core schema.
+   *
+   * @param schema
+   *          The default schema which should be used by this application.
+   */
+  public static void setDefaultSchema(final Schema schema)
+  {
+    defaultSchema = schema;
+  }
+
+
+
+  /**
+   * Parses the provided entry as a subschema subentry. Any problems encountered
+   * while parsing the entry can be retrieved using the returned schema's
+   * {@link #getWarnings()} method.
+   *
+   * @param entry
+   *          The subschema subentry to be parsed.
+   * @return The parsed schema.
+   */
+  public static Schema valueOf(final Entry entry)
+  {
+    return new SchemaBuilder(entry).toSchema();
+  }
+
+
+
+  static MatchingRule getDefaultMatchingRule()
+  {
+    return CoreSchema.getOctetStringMatchingRule();
+  }
+
+
+
+  static Syntax getDefaultSyntax()
+  {
+    return CoreSchema.getOctetStringSyntax();
+  }
+
+
+
+  // Constructs a search request for retrieving the subschemaSubentry
+  // attribute from the named entry.
+  private static SearchRequest getReadSchemaForEntrySearchRequest(final DN dn)
+  {
+    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, Filter
+        .getObjectClassPresentFilter(), SUBSCHEMA_SUBENTRY_ATTRS);
+  }
+
+
+
+  // Constructs a search request for retrieving the named subschema
+  // sub-entry.
+  private static SearchRequest getReadSchemaSearchRequest(final DN dn)
+  {
+    return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT,
+        SUBSCHEMA_FILTER, SUBSCHEMA_ATTRS);
+  }
+
+
+
+  private static DN getSubschemaSubentryDN(final DN name, final Entry entry)
+      throws ErrorResultException
+  {
+    final Attribute subentryAttr = entry.getAttribute(ATTR_SUBSCHEMA_SUBENTRY);
+
+    if (subentryAttr == null || subentryAttr.isEmpty())
+    {
+      // Did not get the subschema sub-entry attribute.
+      final Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage(
+          ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString()).toString());
+      throw ErrorResultException.wrap(result);
+    }
+
+    final String dnString = subentryAttr.iterator().next().toString();
+    DN subschemaDN;
+    try
+    {
+      subschemaDN = DN.valueOf(dnString);
+    }
+    catch (final LocalizedIllegalArgumentException e)
+    {
+      final Result result = Responses.newResult(
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage(
+          ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString(), dnString,
+              e.getMessageObject()).toString());
+      throw ErrorResultException.wrap(result);
+    }
+    return subschemaDN;
+  }
+
+
+
+  private final Impl impl;
+
+
+
+  Schema(final String schemaName,
+      final Map<String, Syntax> numericOID2Syntaxes,
+      final Map<String, MatchingRule> numericOID2MatchingRules,
+      final Map<String, MatchingRuleUse> numericOID2MatchingRuleUses,
+      final Map<String, AttributeType> numericOID2AttributeTypes,
+      final Map<String, ObjectClass> numericOID2ObjectClasses,
+      final Map<String, NameForm> numericOID2NameForms,
+      final Map<String, DITContentRule> numericOID2ContentRules,
+      final Map<Integer, DITStructureRule> id2StructureRules,
+      final Map<String, List<MatchingRule>> name2MatchingRules,
+      final Map<String, List<MatchingRuleUse>> name2MatchingRuleUses,
+      final Map<String, List<AttributeType>> name2AttributeTypes,
+      final Map<String, List<ObjectClass>> name2ObjectClasses,
+      final Map<String, List<NameForm>> name2NameForms,
+      final Map<String, List<DITContentRule>> name2ContentRules,
+      final Map<String, List<DITStructureRule>> name2StructureRules,
+      final Map<String, List<NameForm>> objectClass2NameForms,
+      final Map<String, List<DITStructureRule>> nameForm2StructureRules,
+      final SchemaCompatOptions options, final List<LocalizableMessage> warnings)
+  {
+    impl = new StrictImpl(schemaName, numericOID2Syntaxes,
+        numericOID2MatchingRules, numericOID2MatchingRuleUses,
+        numericOID2AttributeTypes, numericOID2ObjectClasses,
+        numericOID2NameForms, numericOID2ContentRules, id2StructureRules,
+        name2MatchingRules, name2MatchingRuleUses, name2AttributeTypes,
+        name2ObjectClasses, name2NameForms, name2ContentRules,
+        name2StructureRules, objectClass2NameForms, nameForm2StructureRules,
+        options, warnings);
+  }
+
+
+
+  private Schema(final Impl impl)
+  {
+    this.impl = impl;
+  }
+
+
+
+  /**
+   * Returns the attribute type with the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the attribute type to retrieve.
+   * @return The requested attribute type.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested attribute type was
+   *           not found or if the provided name is ambiguous.
+   */
+  public AttributeType getAttributeType(final String name)
+      throws UnknownSchemaElementException
+  {
+    return impl.getAttributeType(name);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the attribute types
+   * contained in this schema.
+   *
+   * @return An unmodifiable collection containing all of the attribute types
+   *         contained in this schema.
+   */
+  public Collection<AttributeType> getAttributeTypes()
+  {
+    return impl.getAttributeTypes();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the attribute types
+   * having the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the attribute types to retrieve.
+   * @return An unmodifiable collection containing all of the attribute types
+   *         having the specified name or numeric OID.
+   */
+  public List<AttributeType> getAttributeTypesByName(final String name)
+  {
+    return impl.getAttributeTypesByName(name);
+  }
+
+
+
+  /**
+   * Returns the DIT content rule with the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the DIT content rule to retrieve.
+   * @return The requested DIT content rule.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested DIT content rule was
+   *           not found or if the provided name is ambiguous.
+   */
+  public DITContentRule getDITContentRule(final String name)
+      throws UnknownSchemaElementException
+  {
+    return impl.getDITContentRule(name);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the DIT content rules
+   * contained in this schema.
+   *
+   * @return An unmodifiable collection containing all of the DIT content rules
+   *         contained in this schema.
+   */
+  public Collection<DITContentRule> getDITContentRules()
+  {
+    return impl.getDITContentRules();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the DIT content rules
+   * having the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the DIT content rules to retrieve.
+   * @return An unmodifiable collection containing all of the DIT content rules
+   *         having the specified name or numeric OID.
+   */
+  public Collection<DITContentRule> getDITContentRulesByName(final String name)
+  {
+    return impl.getDITContentRulesByName(name);
+  }
+
+
+
+  /**
+   * Returns the DIT structure rule with the specified name or numeric OID.
+   *
+   * @param ruleID
+   *          The ID of the DIT structure rule to retrieve.
+   * @return The requested DIT structure rule.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested DIT structure rule
+   *           was not found.
+   */
+  public DITStructureRule getDITStructureRule(final int ruleID)
+      throws UnknownSchemaElementException
+  {
+    return impl.getDITStructureRule(ruleID);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the DIT structure
+   * rules having the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the DIT structure rules to retrieve.
+   * @return An unmodifiable collection containing all of the DIT structure
+   *         rules having the specified name or numeric OID.
+   */
+  public Collection<DITStructureRule> getDITStructureRulesByName(
+      final String name)
+  {
+    return impl.getDITStructureRulesByName(name);
+  }
+
+
+
+  /**
+   * Retrieves the DIT structure rules for the provided name form.
+   *
+   * @param nameForm
+   *          The name form.
+   * @return The requested DIT structure rules.
+   */
+  public Collection<DITStructureRule> getDITStructureRulesByNameForm(
+      final NameForm nameForm)
+  {
+    return impl.getDITStructureRulesByNameForm(nameForm);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the DIT structure
+   * rules contained in this schema.
+   *
+   * @return An unmodifiable collection containing all of the DIT structure
+   *         rules contained in this schema.
+   */
+  public Collection<DITStructureRule> getDITStuctureRules()
+  {
+    return impl.getDITStuctureRules();
+  }
+
+
+
+  /**
+   * Returns the matching rule with the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the matching rule to retrieve.
+   * @return The requested matching rule.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested matching rule was
+   *           not found or if the provided name is ambiguous.
+   */
+  public MatchingRule getMatchingRule(final String name)
+      throws UnknownSchemaElementException
+  {
+    return impl.getMatchingRule(name);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the matching rules
+   * contained in this schema.
+   *
+   * @return An unmodifiable collection containing all of the matching rules
+   *         contained in this schema.
+   */
+  public Collection<MatchingRule> getMatchingRules()
+  {
+    return impl.getMatchingRules();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the matching rules
+   * having the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the matching rules to retrieve.
+   * @return An unmodifiable collection containing all of the matching rules
+   *         having the specified name or numeric OID.
+   */
+  public Collection<MatchingRule> getMatchingRulesByName(final String name)
+  {
+    return impl.getMatchingRulesByName(name);
+  }
+
+
+
+  /**
+   * Returns the matching rule use associated with the provided matching rule.
+   *
+   * @param matchingRule
+   *          The matching rule whose matching rule use is to be retrieved.
+   * @return The requested matching rule use.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested matching rule use
+   *           was not found or if the provided name is ambiguous.
+   */
+  public MatchingRuleUse getMatchingRuleUse(final MatchingRule matchingRule)
+      throws UnknownSchemaElementException
+  {
+    return getMatchingRuleUse(matchingRule.getOID());
+  }
+
+
+
+  /**
+   * Returns the matching rule use with the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the matching rule use to retrieve.
+   * @return The requested matching rule use.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested matching rule use
+   *           was not found or if the provided name is ambiguous.
+   */
+  public MatchingRuleUse getMatchingRuleUse(final String name)
+      throws UnknownSchemaElementException
+  {
+    return impl.getMatchingRuleUse(name);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the matching rule uses
+   * contained in this schema.
+   *
+   * @return An unmodifiable collection containing all of the matching rule uses
+   *         contained in this schema.
+   */
+  public Collection<MatchingRuleUse> getMatchingRuleUses()
+  {
+    return impl.getMatchingRuleUses();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the matching rule uses
+   * having the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the matching rule uses to retrieve.
+   * @return An unmodifiable collection containing all of the matching rule uses
+   *         having the specified name or numeric OID.
+   */
+  public Collection<MatchingRuleUse> getMatchingRuleUsesByName(final String name)
+  {
+    return impl.getMatchingRuleUsesByName(name);
+  }
+
+
+
+  /**
+   * Returns the name form with the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the name form to retrieve.
+   * @return The requested name form.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested name form was not
+   *           found or if the provided name is ambiguous.
+   */
+  public NameForm getNameForm(final String name)
+      throws UnknownSchemaElementException
+  {
+    return impl.getNameForm(name);
+  }
+
+
+
+  /**
+   * Retrieves the name forms for the specified structural objectclass.
+   *
+   * @param structuralClass
+   *          The structural objectclass for the name form to retrieve.
+   * @return The requested name forms
+   */
+  public Collection<NameForm> getNameFormByObjectClass(
+      final ObjectClass structuralClass)
+  {
+    return impl.getNameFormByObjectClass(structuralClass);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the name forms
+   * contained in this schema.
+   *
+   * @return An unmodifiable collection containing all of the name forms
+   *         contained in this schema.
+   */
+  public Collection<NameForm> getNameForms()
+  {
+    return impl.getNameForms();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the name forms having
+   * the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the name forms to retrieve.
+   * @return An unmodifiable collection containing all of the name forms having
+   *         the specified name or numeric OID.
+   */
+  public Collection<NameForm> getNameFormsByName(final String name)
+  {
+    return impl.getNameFormsByName(name);
+  }
+
+
+
+  /**
+   * Returns the object class with the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the object class to retrieve.
+   * @return The requested object class.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested object class was not
+   *           found or if the provided name is ambiguous.
+   */
+  public ObjectClass getObjectClass(final String name)
+      throws UnknownSchemaElementException
+  {
+    return impl.getObjectClass(name);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the object classes
+   * contained in this schema.
+   *
+   * @return An unmodifiable collection containing all of the object classes
+   *         contained in this schema.
+   */
+  public Collection<ObjectClass> getObjectClasses()
+  {
+    return impl.getObjectClasses();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the object classes
+   * having the specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the object classes to retrieve.
+   * @return An unmodifiable collection containing all of the object classes
+   *         having the specified name or numeric OID.
+   */
+  public Collection<ObjectClass> getObjectClassesByName(final String name)
+  {
+    return impl.getObjectClassesByName(name);
+  }
+
+
+
+  /**
+   * Returns the user-friendly name of this schema which may be used for
+   * debugging purposes. The format of the schema name is not defined but should
+   * contain the distinguished name of the subschema sub-entry for those schemas
+   * retrieved from a Directory Server.
+   *
+   * @return The user-friendly name of this schema which may be used for
+   *         debugging purposes.
+   */
+  public String getSchemaName()
+  {
+    return impl.getSchemaName();
+  }
+
+
+
+  /**
+   * Returns the syntax with the specified numeric OID.
+   *
+   * @param numericOID
+   *          The OID of the syntax to retrieve.
+   * @return The requested syntax.
+   * @throws UnknownSchemaElementException
+   *           If this is a strict schema and the requested syntax was not found
+   *           or if the provided name is ambiguous.
+   */
+  public Syntax getSyntax(final String numericOID)
+      throws UnknownSchemaElementException
+  {
+    return impl.getSyntax(numericOID);
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the syntaxes contained
+   * in this schema.
+   *
+   * @return An unmodifiable collection containing all of the syntaxes contained
+   *         in this schema.
+   */
+  public Collection<Syntax> getSyntaxes()
+  {
+    return impl.getSyntaxes();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable collection containing all of the warnings that were
+   * detected when this schema was constructed.
+   *
+   * @return An unmodifiable collection containing all of the warnings that were
+   *         detected when this schema was constructed.
+   */
+  public Collection<LocalizableMessage> getWarnings()
+  {
+    return impl.getWarnings();
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains an attribute type with the
+   * specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the attribute type.
+   * @return {@code true} if this schema contains an attribute type with the
+   *         specified name or numeric OID, otherwise {@code false}.
+   */
+  public boolean hasAttributeType(final String name)
+  {
+    return impl.hasAttributeType(name);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains a DIT content rule with the
+   * specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the DIT content rule.
+   * @return {@code true} if this schema contains a DIT content rule with the
+   *         specified name or numeric OID, otherwise {@code false}.
+   */
+  public boolean hasDITContentRule(final String name)
+  {
+    return impl.hasDITContentRule(name);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains a DIT structure rule with the
+   * specified rule ID.
+   *
+   * @param ruleID
+   *          The ID of the DIT structure rule.
+   * @return {@code true} if this schema contains a DIT structure rule with the
+   *         specified rule ID, otherwise {@code false}.
+   */
+  public boolean hasDITStructureRule(final int ruleID)
+  {
+    return impl.hasDITStructureRule(ruleID);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains a matching rule with the
+   * specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the matching rule.
+   * @return {@code true} if this schema contains a matching rule with the
+   *         specified name or numeric OID, otherwise {@code false}.
+   */
+  public boolean hasMatchingRule(final String name)
+  {
+    return impl.hasMatchingRule(name);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains a matching rule use with the
+   * specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the matching rule use.
+   * @return {@code true} if this schema contains a matching rule use with the
+   *         specified name or numeric OID, otherwise {@code false}.
+   */
+  public boolean hasMatchingRuleUse(final String name)
+  {
+    return impl.hasMatchingRuleUse(name);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains a name form with the
+   * specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the name form.
+   * @return {@code true} if this schema contains a name form with the specified
+   *         name or numeric OID, otherwise {@code false}.
+   */
+  public boolean hasNameForm(final String name)
+  {
+    return impl.hasNameForm(name);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains an object class with the
+   * specified name or numeric OID.
+   *
+   * @param name
+   *          The name or OID of the object class.
+   * @return {@code true} if this schema contains an object class with the
+   *         specified name or numeric OID, otherwise {@code false}.
+   */
+  public boolean hasObjectClass(final String name)
+  {
+    return impl.hasObjectClass(name);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema contains a syntax with the specified
+   * numeric OID.
+   *
+   * @param numericOID
+   *          The OID of the syntax.
+   * @return {@code true} if this schema contains a syntax with the specified
+   *         numeric OID, otherwise {@code false}.
+   */
+  public boolean hasSyntax(final String numericOID)
+  {
+    return impl.hasSyntax(numericOID);
+  }
+
+
+
+  /**
+   * Indicates whether or not this schema is strict. Attribute type queries in
+   * non-strict schema always succeed: if the requested attribute type is not
+   * found then a temporary attribute type is created automatically having the
+   * Octet String syntax and associated matching rules. Strict schema, on the
+   * other hand, throw an {@link UnknownSchemaElementException} whenever an
+   * attempt is made to retrieve a non-existent attribute type.
+   *
+   * @return {@code true} if this schema is strict.
+   */
+  public boolean isStrict()
+  {
+    return impl.isStrict();
+  }
+
+
+
+  /**
+   * Returns a non-strict view of this schema. Attribute type queries in
+   * non-strict schema always succeed: if the requested attribute type is not
+   * found then a temporary attribute type is created automatically having the
+   * Octet String syntax and associated matching rules. Strict schema, on the
+   * other hand, throw an {@link UnknownSchemaElementException} whenever an
+   * attempt is made to retrieve a non-existent attribute type.
+   *
+   * @return A non-strict view of this schema.
+   */
+  public Schema nonStrict()
+  {
+    if (impl.isStrict())
+    {
+      return new Schema(new NonStrictImpl(impl));
+    }
+    else
+    {
+      return this;
+    }
+  }
+
+
+
+  /**
+   * Adds the definitions of all the schema elements contained in this schema to
+   * the provided subschema subentry. Any existing attributes (including schema
+   * definitions) contained in the provided entry will be preserved.
+   *
+   * @param entry
+   *          The subschema subentry to which all schema definitions should be
+   *          added.
+   * @return The updated subschema subentry.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public Entry toEntry(Entry entry) throws NullPointerException
+  {
+    Attribute attr = new LinkedAttribute(Schema.ATTR_LDAP_SYNTAXES);
+    for (Syntax syntax : getSyntaxes())
+    {
+      attr.add(syntax.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    attr = new LinkedAttribute(Schema.ATTR_ATTRIBUTE_TYPES);
+    for (AttributeType attributeType : getAttributeTypes())
+    {
+      attr.add(attributeType.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    attr = new LinkedAttribute(Schema.ATTR_OBJECT_CLASSES);
+    for (ObjectClass objectClass : getObjectClasses())
+    {
+      attr.add(objectClass.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULE_USE);
+    for (MatchingRuleUse matchingRuleUse : getMatchingRuleUses())
+    {
+      attr.add(matchingRuleUse.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    attr = new LinkedAttribute(Schema.ATTR_MATCHING_RULES);
+    for (MatchingRule matchingRule : getMatchingRules())
+    {
+      attr.add(matchingRule.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    attr = new LinkedAttribute(Schema.ATTR_DIT_CONTENT_RULES);
+    for (DITContentRule ditContentRule : getDITContentRules())
+    {
+      attr.add(ditContentRule.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    attr = new LinkedAttribute(Schema.ATTR_DIT_STRUCTURE_RULES);
+    for (DITStructureRule ditStructureRule : getDITStuctureRules())
+    {
+      attr.add(ditStructureRule.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    attr = new LinkedAttribute(Schema.ATTR_NAME_FORMS);
+    for (NameForm nameForm : getNameForms())
+    {
+      attr.add(nameForm.toString());
+    }
+    if (!attr.isEmpty())
+    {
+      entry.addAttribute(attr);
+    }
+
+    return entry;
+  }
+
+
+
+  SchemaCompatOptions getSchemaCompatOptions()
+  {
+    return impl.getSchemaCompatOptions();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaBuilder.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaBuilder.java
new file mode 100644
index 0000000..3509ec4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaBuilder.java
@@ -0,0 +1,3134 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_GENERIC_ENUM_NAME;
+import static org.opends.sdk.schema.SchemaConstants.SCHEMA_PROPERTY_APPROX_RULE;
+import static org.opends.sdk.schema.SchemaConstants.TOP_OBJECTCLASS_NAME;
+import static org.opends.sdk.schema.SchemaUtils.unmodifiableCopyOfExtraProperties;
+import static org.opends.sdk.schema.SchemaUtils.unmodifiableCopyOfList;
+import static org.opends.sdk.schema.SchemaUtils.unmodifiableCopyOfSet;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
+
+import org.opends.sdk.*;
+
+import com.sun.opends.sdk.util.StaticUtils;
+import com.sun.opends.sdk.util.SubstringReader;
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * Schema builders should be used for incremental construction of new schemas.
+ */
+public final class SchemaBuilder
+{
+
+  private Map<Integer, DITStructureRule> id2StructureRules;
+
+  private Map<String, List<AttributeType>> name2AttributeTypes;
+
+  private Map<String, List<DITContentRule>> name2ContentRules;
+
+  private Map<String, List<MatchingRule>> name2MatchingRules;
+
+  private Map<String, List<MatchingRuleUse>> name2MatchingRuleUses;
+
+  private Map<String, List<NameForm>> name2NameForms;
+
+  private Map<String, List<ObjectClass>> name2ObjectClasses;
+
+  private Map<String, List<DITStructureRule>> name2StructureRules;
+
+  private Map<String, List<DITStructureRule>> nameForm2StructureRules;
+
+  private Map<String, AttributeType> numericOID2AttributeTypes;
+
+  private Map<String, DITContentRule> numericOID2ContentRules;
+
+  private Map<String, MatchingRule> numericOID2MatchingRules;
+
+  private Map<String, MatchingRuleUse> numericOID2MatchingRuleUses;
+
+  private Map<String, NameForm> numericOID2NameForms;
+
+  private Map<String, ObjectClass> numericOID2ObjectClasses;
+
+  private Map<String, Syntax> numericOID2Syntaxes;
+
+  private Map<String, List<NameForm>> objectClass2NameForms;
+
+  private SchemaCompatOptions options;
+
+  private List<LocalizableMessage> warnings;
+
+  private Schema schema;
+
+  // A unique ID which can be used to uniquely identify schemas
+  // constructed without a name.
+  private final AtomicInteger nextSchemaID = new AtomicInteger();
+
+
+
+  /**
+   * Creates a new schema builder with no schema elements and default
+   * compatibility options.
+   */
+  public SchemaBuilder()
+  {
+    initBuilder(null);
+  }
+
+
+
+  /**
+   * Creates a new schema builder containing all of the schema elements
+   * contained in the provided a subschema subentry. Any problems encountered
+   * while parsing the entry can be retrieved using the returned schema's
+   * {@link Schema#getWarnings()} method.
+   *
+   * @param entry
+   *          The subschema subentry to be parsed.
+   * @throws NullPointerException
+   *           If {@code entry} was {@code null}.
+   */
+  public SchemaBuilder(final Entry entry) throws NullPointerException
+  {
+    initBuilder(entry.getName().toString());
+
+    Attribute attr = entry.getAttribute(Schema.ATTR_LDAP_SYNTAXES);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addSyntax(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+
+    attr = entry.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addAttributeType(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+
+    attr = entry.getAttribute(Schema.ATTR_OBJECT_CLASSES);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addObjectClass(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+
+    attr = entry.getAttribute(Schema.ATTR_MATCHING_RULE_USE);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addMatchingRuleUse(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+
+    attr = entry.getAttribute(Schema.ATTR_MATCHING_RULES);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addMatchingRule(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+
+    attr = entry.getAttribute(Schema.ATTR_DIT_CONTENT_RULES);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addDITContentRule(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+
+    attr = entry.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addDITStructureRule(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+
+    attr = entry.getAttribute(Schema.ATTR_NAME_FORMS);
+    if (attr != null)
+    {
+      for (final ByteString def : attr)
+      {
+        try
+        {
+          addNameForm(def.toString(), true);
+        }
+        catch (final LocalizedIllegalArgumentException e)
+        {
+          addWarning(e.getMessageObject());
+        }
+      }
+    }
+  }
+
+
+
+  /**
+   * Creates a new schema builder containing all of the schema elements from the
+   * provided schema and its compatibility options.
+   *
+   * @param schema
+   *          The initial contents of the schema builder.
+   * @throws NullPointerException
+   *           If {@code schema} was {@code null}.
+   */
+  public SchemaBuilder(final Schema schema) throws NullPointerException
+  {
+    initBuilder(schema.getSchemaName());
+    setSchemaCompatOptions(schema.getSchemaCompatOptions());
+    addSchema(schema, true);
+  }
+
+
+
+  /**
+   * Creates a new schema builder with no schema elements and default
+   * compatibility options.
+   *
+   * @param schemaName
+   *          The user-friendly name of this schema which may be used for
+   *          debugging purposes.
+   */
+  public SchemaBuilder(final String schemaName)
+  {
+    initBuilder(schemaName);
+  }
+
+
+
+  /**
+   * Adds the provided attribute type definition to this schema builder.
+   *
+   * @param definition
+   *          The attribute type definition.
+   * @param overwrite
+   *          {@code true} if any existing attribute type with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided attribute type definition could not be parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addAttributeType(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the definition was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      List<String> names = Collections.emptyList();
+      String description = "".intern();
+      boolean isObsolete = false;
+      String superiorType = null;
+      String equalityMatchingRule = null;
+      String orderingMatchingRule = null;
+      String substringMatchingRule = null;
+      String approximateMatchingRule = null;
+      String syntax = null;
+      boolean isSingleValue = false;
+      boolean isCollective = false;
+      boolean isNoUserModification = false;
+      AttributeUsage attributeUsage = AttributeUsage.USER_APPLICATIONS;
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the definition. But before we start, set default
+      // values for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          names = SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+          isObsolete = true;
+        }
+        else if (tokenName.equalsIgnoreCase("sup"))
+        {
+          // This specifies the name or OID of the superior attribute
+          // type from which this attribute type should inherit its
+          // properties.
+          superiorType = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("equality"))
+        {
+          // This specifies the name or OID of the equality matching
+          // rule to use for this attribute type.
+          equalityMatchingRule = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("ordering"))
+        {
+          // This specifies the name or OID of the ordering matching
+          // rule to use for this attribute type.
+          orderingMatchingRule = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("substr"))
+        {
+          // This specifies the name or OID of the substring matching
+          // rule to use for this attribute type.
+          substringMatchingRule = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("syntax"))
+        {
+          // This specifies the numeric OID of the syntax for this
+          // matching rule. It may optionally be immediately followed by
+          // an open curly brace, an integer definition, and a close
+          // curly brace to suggest the minimum number of characters
+          // that should be allowed in values of that type. This
+          // implementation will ignore any such length because it does
+          // not impose any practical limit on the length of attribute
+          // values.
+          syntax = SchemaUtils.readOIDLen(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("single-definition"))
+        {
+          // This indicates that attributes of this type are allowed to
+          // have at most one definition. We do not need any more
+          // parsing for this token.
+          isSingleValue = true;
+        }
+        else if (tokenName.equalsIgnoreCase("single-value"))
+        {
+          // This indicates that attributes of this type are allowed to
+          // have at most one value. We do not need any more parsing for
+          // this token.
+          isSingleValue = true;
+        }
+        else if (tokenName.equalsIgnoreCase("collective"))
+        {
+          // This indicates that attributes of this type are collective
+          // (i.e., have their values generated dynamically in some
+          // way). We do not need any more parsing for this token.
+          isCollective = true;
+        }
+        else if (tokenName.equalsIgnoreCase("no-user-modification"))
+        {
+          // This indicates that the values of attributes of this type
+          // are not to be modified by end users. We do not need any
+          // more parsing for this token.
+          isNoUserModification = true;
+        }
+        else if (tokenName.equalsIgnoreCase("usage"))
+        {
+          // This specifies the usage string for this attribute type. It
+          // should be followed by one of the strings
+          // "userApplications", "directoryOperation",
+          // "distributedOperation", or "dSAOperation".
+          int length = 0;
+
+          reader.skipWhitespaces();
+          reader.mark();
+
+          while (reader.read() != ' ')
+          {
+            length++;
+          }
+
+          reader.reset();
+          final String usageStr = reader.read(length);
+          if (usageStr.equalsIgnoreCase("userapplications"))
+          {
+            attributeUsage = AttributeUsage.USER_APPLICATIONS;
+          }
+          else if (usageStr.equalsIgnoreCase("directoryoperation"))
+          {
+            attributeUsage = AttributeUsage.DIRECTORY_OPERATION;
+          }
+          else if (usageStr.equalsIgnoreCase("distributedoperation"))
+          {
+            attributeUsage = AttributeUsage.DISTRIBUTED_OPERATION;
+          }
+          else if (usageStr.equalsIgnoreCase("dsaoperation"))
+          {
+            attributeUsage = AttributeUsage.DSA_OPERATION;
+          }
+          else
+          {
+            final LocalizableMessage message = WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE
+                .get(String.valueOf(oid), usageStr);
+            throw new LocalizedIllegalArgumentException(message);
+          }
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      final List<String> approxRules = extraProperties
+          .get(SCHEMA_PROPERTY_APPROX_RULE);
+      if (approxRules != null && !approxRules.isEmpty())
+      {
+        approximateMatchingRule = approxRules.get(0);
+      }
+
+      if (!extraProperties.isEmpty())
+      {
+        extraProperties = Collections.unmodifiableMap(extraProperties);
+      }
+
+      final AttributeType attrType = new AttributeType(oid, names, description,
+          isObsolete, superiorType, equalityMatchingRule, orderingMatchingRule,
+          substringMatchingRule, approximateMatchingRule, syntax,
+          isSingleValue, isCollective, isNoUserModification, attributeUsage,
+          extraProperties, definition);
+
+      addAttributeType(attrType, overwrite);
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided attribute type definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the attribute type definition.
+   * @param names
+   *          The user-friendly names of the attribute type definition.
+   * @param description
+   *          The description of the attribute type definition.
+   * @param obsolete
+   *          {@code true} if the attribute type definition is obsolete,
+   *          otherwise {@code false}.
+   * @param superiorType
+   *          The OID of the superior attribute type definition.
+   * @param equalityMatchingRule
+   *          The OID of the equality matching rule, which may be {@code null}
+   *          indicating that the superior attribute type's matching rule should
+   *          be used or, if none is defined, the default matching rule
+   *          associated with the syntax.
+   * @param orderingMatchingRule
+   *          The OID of the ordering matching rule, which may be {@code null}
+   *          indicating that the superior attribute type's matching rule should
+   *          be used or, if none is defined, the default matching rule
+   *          associated with the syntax.
+   * @param substringMatchingRule
+   *          The OID of the substring matching rule, which may be {@code null}
+   *          indicating that the superior attribute type's matching rule should
+   *          be used or, if none is defined, the default matching rule
+   *          associated with the syntax.
+   * @param approximateMatchingRule
+   *          The OID of the approximate matching rule, which may be {@code
+   *          null} indicating that the superior attribute type's matching rule
+   *          should be used or, if none is defined, the default matching rule
+   *          associated with the syntax.
+   * @param syntax
+   *          The OID of the syntax definition.
+   * @param singleValue
+   *          {@code true} if the attribute type definition is single-valued,
+   *          otherwise {@code false}.
+   * @param collective
+   *          {@code true} if the attribute type definition is a collective
+   *          attribute, otherwise {@code false}.
+   * @param noUserModification
+   *          {@code true} if the attribute type definition is read-only,
+   *          otherwise {@code false}.
+   * @param attributeUsage
+   *          The intended use of the attribute type definition.
+   * @param extraProperties
+   *          A map containing additional properties associated with the
+   *          attribute type definition.
+   * @param overwrite
+   *          {@code true} if any existing attribute type with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addAttributeType(final String oid,
+      final List<String> names, final String description,
+      final boolean obsolete, final String superiorType,
+      final String equalityMatchingRule, final String orderingMatchingRule,
+      final String substringMatchingRule, final String approximateMatchingRule,
+      final String syntax, final boolean singleValue, final boolean collective,
+      final boolean noUserModification, final AttributeUsage attributeUsage,
+      final Map<String, List<String>> extraProperties, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    final AttributeType attrType = new AttributeType(oid,
+        unmodifiableCopyOfList(names), description, obsolete, superiorType,
+        equalityMatchingRule, orderingMatchingRule, substringMatchingRule,
+        approximateMatchingRule, syntax, singleValue, collective,
+        noUserModification, attributeUsage,
+        unmodifiableCopyOfExtraProperties(extraProperties), null);
+    addAttributeType(attrType, overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided DIT content rule definition to this schema builder.
+   *
+   * @param definition
+   *          The DIT content rule definition.
+   * @param overwrite
+   *          {@code true} if any existing DIT content rule with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided DIT content rule definition could not be parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addDITContentRule(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String structuralClass = SchemaUtils.readOID(reader);
+
+      List<String> names = Collections.emptyList();
+      String description = "".intern();
+      boolean isObsolete = false;
+      Set<String> auxiliaryClasses = Collections.emptySet();
+      Set<String> optionalAttributes = Collections.emptySet();
+      Set<String> prohibitedAttributes = Collections.emptySet();
+      Set<String> requiredAttributes = Collections.emptySet();
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          names = SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+          isObsolete = true;
+        }
+        else if (tokenName.equalsIgnoreCase("aux"))
+        {
+          auxiliaryClasses = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("must"))
+        {
+          requiredAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("may"))
+        {
+          optionalAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("not"))
+        {
+          prohibitedAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      if (!extraProperties.isEmpty())
+      {
+        extraProperties = Collections.unmodifiableMap(extraProperties);
+      }
+
+      final DITContentRule rule = new DITContentRule(structuralClass, names,
+          description, isObsolete, auxiliaryClasses, optionalAttributes,
+          prohibitedAttributes, requiredAttributes, extraProperties, definition);
+      addDITContentRule(rule, overwrite);
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided DIT content rule definition to this schema builder.
+   *
+   * @param structuralClass
+   *          The name of the structural object class to which the DIT content
+   *          rule applies.
+   * @param names
+   *          The user-friendly names of the DIT content rule definition.
+   * @param description
+   *          The description of the DIT content rule definition.
+   * @param obsolete
+   *          {@code true} if the DIT content rule definition is obsolete,
+   *          otherwise {@code false}.
+   * @param auxiliaryClasses
+   *          A list of auxiliary object classes that entries subject to the DIT
+   *          content rule may belong to.
+   * @param optionalAttributes
+   *          A list of attribute types that entries subject to the DIT content
+   *          rule may contain.
+   * @param prohibitedAttributes
+   *          A list of attribute types that entries subject to the DIT content
+   *          rule must not contain.
+   * @param requiredAttributes
+   *          A list of attribute types that entries subject to the DIT content
+   *          rule must contain.
+   * @param extraProperties
+   *          A map containing additional properties associated with the DIT
+   *          content rule definition.
+   * @param overwrite
+   *          {@code true} if any existing DIT content rule with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addDITContentRule(final String structuralClass,
+      final List<String> names, final String description,
+      final boolean obsolete, final Set<String> auxiliaryClasses,
+      final Set<String> optionalAttributes,
+      final Set<String> prohibitedAttributes,
+      final Set<String> requiredAttributes,
+      final Map<String, List<String>> extraProperties, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    final DITContentRule rule = new DITContentRule(structuralClass,
+        unmodifiableCopyOfList(names), description, obsolete,
+        unmodifiableCopyOfSet(auxiliaryClasses),
+        unmodifiableCopyOfSet(optionalAttributes),
+        unmodifiableCopyOfSet(prohibitedAttributes),
+        unmodifiableCopyOfSet(requiredAttributes),
+        unmodifiableCopyOfExtraProperties(extraProperties), null);
+    addDITContentRule(rule, overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided DIT structure rule definition to this schema builder.
+   *
+   * @param ruleID
+   *          The rule identifier of the DIT structure rule.
+   * @param names
+   *          The user-friendly names of the DIT structure rule definition.
+   * @param description
+   *          The description of the DIT structure rule definition.
+   * @param obsolete
+   *          {@code true} if the DIT structure rule definition is obsolete,
+   *          otherwise {@code false}.
+   * @param nameForm
+   *          The name form associated with the DIT structure rule.
+   * @param superiorRules
+   *          A list of superior rules (by rule id).
+   * @param extraProperties
+   *          A map containing additional properties associated with the DIT
+   *          structure rule definition.
+   * @param overwrite
+   *          {@code true} if any existing DIT structure rule with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addDITStructureRule(final Integer ruleID,
+      final List<String> names, final String description,
+      final boolean obsolete, final String nameForm,
+      final Set<Integer> superiorRules,
+      final Map<String, List<String>> extraProperties, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    final DITStructureRule rule = new DITStructureRule(ruleID,
+        unmodifiableCopyOfList(names), description, obsolete, nameForm,
+        unmodifiableCopyOfSet(superiorRules),
+        unmodifiableCopyOfExtraProperties(extraProperties), null);
+    addDITStructureRule(rule, overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided DIT structure rule definition to this schema builder.
+   *
+   * @param definition
+   *          The DIT structure rule definition.
+   * @param overwrite
+   *          {@code true} if any existing DIT structure rule with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided DIT structure rule definition could not be
+   *           parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addDITStructureRule(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final Integer ruleID = SchemaUtils.readRuleID(reader);
+
+      List<String> names = Collections.emptyList();
+      String description = "".intern();
+      boolean isObsolete = false;
+      String nameForm = null;
+      Set<Integer> superiorRules = Collections.emptySet();
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          names = SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+          isObsolete = true;
+        }
+        else if (tokenName.equalsIgnoreCase("form"))
+        {
+          nameForm = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("sup"))
+        {
+          superiorRules = SchemaUtils.readRuleIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      if (nameForm == null)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM
+            .get(definition);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      if (!extraProperties.isEmpty())
+      {
+        extraProperties = Collections.unmodifiableMap(extraProperties);
+      }
+
+      final DITStructureRule rule = new DITStructureRule(ruleID, names,
+          description, isObsolete, nameForm, superiorRules, extraProperties,
+          definition);
+      addDITStructureRule(rule, overwrite);
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided enumeration syntax definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the enumeration syntax definition.
+   * @param description
+   *          The description of the enumeration syntax definition.
+   * @param overwrite
+   *          {@code true} if any existing syntax with the same OID should be
+   *          overwritten.
+   * @param enumerations
+   *          The range of values which attribute values must match in order to
+   *          be valid.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addEnumerationSyntax(final String oid,
+      final String description, final boolean overwrite,
+      final String... enumerations) throws ConflictingSchemaElementException
+  {
+    Validator.ensureNotNull((Object) enumerations);
+
+    final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid, Arrays
+        .asList(enumerations));
+    final Syntax enumSyntax = new Syntax(oid, description, Collections
+        .singletonMap("X-ENUM", Arrays.asList(enumerations)), null, enumImpl);
+    final MatchingRule enumOMR = new MatchingRule(enumImpl
+        .getOrderingMatchingRule(), Collections
+        .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
+        CoreSchemaImpl.OPENDS_ORIGIN, null, new EnumOrderingMatchingRule(
+            enumImpl));
+
+    addSyntax(enumSyntax, overwrite);
+    try
+    {
+      addMatchingRule(enumOMR, overwrite);
+    }
+    catch (final ConflictingSchemaElementException e)
+    {
+      removeSyntax(oid);
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided matching rule definition to this schema builder.
+   *
+   * @param definition
+   *          The matching rule definition.
+   * @param overwrite
+   *          {@code true} if any existing matching rule with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided matching rule definition could not be parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addMatchingRule(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EMPTY_VALUE.get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      List<String> names = Collections.emptyList();
+      String description = "".intern();
+      boolean isObsolete = false;
+      String syntax = null;
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          names = SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the matching rule. It is
+          // an arbitrary string of characters enclosed in single
+          // quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the matching rule should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+          isObsolete = true;
+        }
+        else if (tokenName.equalsIgnoreCase("syntax"))
+        {
+          syntax = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      // Make sure that a syntax was specified.
+      if (syntax == null)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_NO_SYNTAX
+            .get(definition);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      if (!extraProperties.isEmpty())
+      {
+        extraProperties = Collections.unmodifiableMap(extraProperties);
+      }
+
+      addMatchingRule(new MatchingRule(oid, names, description, isObsolete,
+          syntax, extraProperties, definition, null), overwrite);
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided matching rule definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the matching rule definition.
+   * @param names
+   *          The user-friendly names of the matching rule definition.
+   * @param description
+   *          The description of the matching rule definition.
+   * @param obsolete
+   *          {@code true} if the matching rule definition is obsolete,
+   *          otherwise {@code false}.
+   * @param assertionSyntax
+   *          The OID of the assertion syntax definition.
+   * @param extraProperties
+   *          A map containing additional properties associated with the
+   *          matching rule definition.
+   * @param implementation
+   *          The implementation of the matching rule.
+   * @param overwrite
+   *          {@code true} if any existing matching rule with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addMatchingRule(final String oid,
+      final List<String> names, final String description,
+      final boolean obsolete, final String assertionSyntax,
+      final Map<String, List<String>> extraProperties,
+      final MatchingRuleImpl implementation, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    Validator.ensureNotNull(implementation);
+    final MatchingRule matchingRule = new MatchingRule(oid,
+        unmodifiableCopyOfList(names), description, obsolete, assertionSyntax,
+        unmodifiableCopyOfExtraProperties(extraProperties), null,
+        implementation);
+    addMatchingRule(matchingRule, overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided matching rule use definition to this schema builder.
+   *
+   * @param definition
+   *          The matching rule use definition.
+   * @param overwrite
+   *          {@code true} if any existing matching rule use with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided matching rule use definition could not be parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addMatchingRuleUse(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      List<String> names = Collections.emptyList();
+      String description = "".intern();
+      boolean isObsolete = false;
+      Set<String> attributes = null;
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          names = SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+          isObsolete = true;
+        }
+        else if (tokenName.equalsIgnoreCase("applies"))
+        {
+          attributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      // Make sure that the set of attributes was defined.
+      if (attributes == null || attributes.size() == 0)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_NO_ATTR
+            .get(definition);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      if (!extraProperties.isEmpty())
+      {
+        extraProperties = Collections.unmodifiableMap(extraProperties);
+      }
+
+      final MatchingRuleUse use = new MatchingRuleUse(oid, names, description,
+          isObsolete, attributes, extraProperties, definition);
+      addMatchingRuleUse(use, overwrite);
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided matching rule use definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the matching rule use definition.
+   * @param names
+   *          The user-friendly names of the matching rule use definition.
+   * @param description
+   *          The description of the matching rule use definition.
+   * @param obsolete
+   *          {@code true} if the matching rule use definition is obsolete,
+   *          otherwise {@code false}.
+   * @param attributeOIDs
+   *          The list of attribute types the matching rule applies to.
+   * @param extraProperties
+   *          A map containing additional properties associated with the
+   *          matching rule use definition.
+   * @param overwrite
+   *          {@code true} if any existing matching rule use with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addMatchingRuleUse(final String oid,
+      final List<String> names, final String description,
+      final boolean obsolete, final Set<String> attributeOIDs,
+      final Map<String, List<String>> extraProperties, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    final MatchingRuleUse use = new MatchingRuleUse(oid,
+        unmodifiableCopyOfList(names), description, obsolete,
+        unmodifiableCopyOfSet(attributeOIDs),
+        unmodifiableCopyOfExtraProperties(extraProperties), null);
+    addMatchingRuleUse(use, overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided name form definition to this schema builder.
+   *
+   * @param definition
+   *          The name form definition.
+   * @param overwrite
+   *          {@code true} if any existing name form with the same OID should be
+   *          overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided name form definition could not be parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addNameForm(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), c);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      List<String> names = Collections.emptyList();
+      String description = "".intern();
+      boolean isObsolete = false;
+      String structuralClass = null;
+      Set<String> optionalAttributes = Collections.emptySet();
+      Set<String> requiredAttributes = null;
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          names = SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+          isObsolete = true;
+        }
+        else if (tokenName.equalsIgnoreCase("oc"))
+        {
+          structuralClass = SchemaUtils.readOID(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("must"))
+        {
+          requiredAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("may"))
+        {
+          optionalAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      // Make sure that a structural class was specified. If not, then
+      // it cannot be valid.
+      if (structuralClass == null)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS
+            .get(definition);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      if (requiredAttributes == null || requiredAttributes.size() == 0)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_NO_REQUIRED_ATTR
+            .get(definition);
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      if (!extraProperties.isEmpty())
+      {
+        extraProperties = Collections.unmodifiableMap(extraProperties);
+      }
+
+      final NameForm nameForm = new NameForm(oid, names, description,
+          isObsolete, structuralClass, requiredAttributes, optionalAttributes,
+          extraProperties, definition);
+      addNameForm(nameForm, overwrite);
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided name form definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the name form definition.
+   * @param names
+   *          The user-friendly names of the name form definition.
+   * @param description
+   *          The description of the name form definition.
+   * @param obsolete
+   *          {@code true} if the name form definition is obsolete, otherwise
+   *          {@code false}.
+   * @param structuralClass
+   *          The structural object class this rule applies to.
+   * @param requiredAttributes
+   *          A list of naming attribute types that entries subject to the name
+   *          form must contain.
+   * @param optionalAttributes
+   *          A list of naming attribute types that entries subject to the name
+   *          form may contain.
+   * @param extraProperties
+   *          A map containing additional properties associated with the name
+   *          form definition.
+   * @param overwrite
+   *          {@code true} if any existing name form use with the same OID
+   *          should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addNameForm(final String oid, final List<String> names,
+      final String description, final boolean obsolete,
+      final String structuralClass, final Set<String> requiredAttributes,
+      final Set<String> optionalAttributes,
+      final Map<String, List<String>> extraProperties, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    final NameForm nameForm = new NameForm(oid, unmodifiableCopyOfList(names),
+        description, obsolete, structuralClass,
+        unmodifiableCopyOfSet(requiredAttributes),
+        unmodifiableCopyOfSet(optionalAttributes),
+        unmodifiableCopyOfExtraProperties(extraProperties), null);
+    addNameForm(nameForm, overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided object class definition to this schema builder.
+   *
+   * @param definition
+   *          The object class definition.
+   * @param overwrite
+   *          {@code true} if any existing object class with the same OID should
+   *          be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided object class definition could not be parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addObjectClass(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      List<String> names = Collections.emptyList();
+      String description = "".intern();
+      boolean isObsolete = false;
+      Set<String> superiorClasses = Collections.emptySet();
+      Set<String> requiredAttributes = Collections.emptySet();
+      Set<String> optionalAttributes = Collections.emptySet();
+      ObjectClassType objectClassType = ObjectClassType.STRUCTURAL;
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("name"))
+        {
+          names = SchemaUtils.readNameDescriptors(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the attribute type. It
+          // is an arbitrary string of characters enclosed in single
+          // quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("obsolete"))
+        {
+          // This indicates whether the attribute type should be
+          // considered obsolete. We do not need to do any more parsing
+          // for this token.
+          isObsolete = true;
+        }
+        else if (tokenName.equalsIgnoreCase("sup"))
+        {
+          superiorClasses = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("abstract"))
+        {
+          // This indicates that entries must not include this
+          // objectclass unless they also include a non-abstract
+          // objectclass that inherits from this class. We do not need
+          // any more parsing for this token.
+          objectClassType = ObjectClassType.ABSTRACT;
+        }
+        else if (tokenName.equalsIgnoreCase("structural"))
+        {
+          // This indicates that this is a structural objectclass. We do
+          // not need any more parsing for this token.
+          objectClassType = ObjectClassType.STRUCTURAL;
+        }
+        else if (tokenName.equalsIgnoreCase("auxiliary"))
+        {
+          // This indicates that this is an auxiliary objectclass. We do
+          // not need any more parsing for this token.
+          objectClassType = ObjectClassType.AUXILIARY;
+        }
+        else if (tokenName.equalsIgnoreCase("must"))
+        {
+          requiredAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.equalsIgnoreCase("may"))
+        {
+          optionalAttributes = SchemaUtils.readOIDs(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      if (oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID))
+      {
+        addObjectClass(new ObjectClass(description, extraProperties), overwrite);
+      }
+      else
+      {
+        if (objectClassType == ObjectClassType.STRUCTURAL
+            && superiorClasses.isEmpty())
+        {
+          superiorClasses = Collections.singleton(TOP_OBJECTCLASS_NAME);
+        }
+
+        if (!extraProperties.isEmpty())
+        {
+          extraProperties = Collections.unmodifiableMap(extraProperties);
+        }
+
+        addObjectClass(new ObjectClass(oid, names, description, isObsolete,
+            superiorClasses, requiredAttributes, optionalAttributes,
+            objectClassType, extraProperties, definition), overwrite);
+      }
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided object class definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the object class definition.
+   * @param names
+   *          The user-friendly names of the object class definition.
+   * @param description
+   *          The description of the object class definition.
+   * @param obsolete
+   *          {@code true} if the object class definition is obsolete, otherwise
+   *          {@code false}.
+   * @param superiorClassOIDs
+   *          A list of direct superclasses of the object class.
+   * @param requiredAttributeOIDs
+   *          A list of attribute types that entries must contain.
+   * @param optionalAttributeOIDs
+   *          A list of attribute types that entries may contain.
+   * @param objectClassType
+   *          The type of the object class.
+   * @param extraProperties
+   *          A map containing additional properties associated with the object
+   *          class definition.
+   * @param overwrite
+   *          {@code true} if any existing object class with the same OID should
+   *          be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addObjectClass(final String oid,
+      final List<String> names, final String description,
+      final boolean obsolete, Set<String> superiorClassOIDs,
+      final Set<String> requiredAttributeOIDs,
+      final Set<String> optionalAttributeOIDs,
+      final ObjectClassType objectClassType,
+      final Map<String, List<String>> extraProperties, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    if (oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID))
+    {
+      addObjectClass(new ObjectClass(description,
+          unmodifiableCopyOfExtraProperties(extraProperties)), overwrite);
+    }
+    else
+    {
+      if (objectClassType == ObjectClassType.STRUCTURAL
+          && superiorClassOIDs.isEmpty())
+      {
+        superiorClassOIDs = Collections.singleton(TOP_OBJECTCLASS_NAME);
+      }
+
+      addObjectClass(new ObjectClass(oid, unmodifiableCopyOfList(names),
+          description, obsolete, unmodifiableCopyOfSet(superiorClassOIDs),
+          unmodifiableCopyOfSet(requiredAttributeOIDs),
+          unmodifiableCopyOfSet(optionalAttributeOIDs), objectClassType,
+          unmodifiableCopyOfExtraProperties(extraProperties), null), overwrite);
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided pattern syntax definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the pattern syntax definition.
+   * @param description
+   *          The description of the pattern syntax definition.
+   * @param pattern
+   *          The regular expression pattern which attribute values must match
+   *          in order to be valid.
+   * @param overwrite
+   *          {@code true} if any existing syntax with the same OID should be
+   *          overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addPatternSyntax(final String oid,
+      final String description, final Pattern pattern, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    Validator.ensureNotNull(pattern);
+
+    addSyntax(
+        new Syntax(oid, description, Collections.singletonMap("X-PATTERN",
+            Collections.singletonList(pattern.toString())), null, null),
+        overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds all of the schema elements in the provided schema to this schema
+   * builder.
+   *
+   * @param schema
+   *          The schema to be copied into this schema builder.
+   * @param overwrite
+   *          {@code true} if existing schema elements with the same conflicting
+   *          OIDs should be overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and conflicting schema
+   *           elements were found.
+   * @throws NullPointerException
+   *           If {@code schema} was {@code null}.
+   */
+  public SchemaBuilder addSchema(final Schema schema, final boolean overwrite)
+      throws ConflictingSchemaElementException, NullPointerException
+  {
+    Validator.ensureNotNull(schema);
+    for (final Syntax syntax : schema.getSyntaxes())
+    {
+      addSyntax(syntax.duplicate(), overwrite);
+    }
+
+    for (final MatchingRule matchingRule : schema.getMatchingRules())
+    {
+      addMatchingRule(matchingRule.duplicate(), overwrite);
+    }
+
+    for (final MatchingRuleUse matchingRuleUse : schema.getMatchingRuleUses())
+    {
+      addMatchingRuleUse(matchingRuleUse.duplicate(), overwrite);
+    }
+
+    for (final AttributeType attributeType : schema.getAttributeTypes())
+    {
+      addAttributeType(attributeType.duplicate(), overwrite);
+    }
+
+    for (final ObjectClass objectClass : schema.getObjectClasses())
+    {
+      addObjectClass(objectClass.duplicate(), overwrite);
+    }
+
+    for (final NameForm nameForm : schema.getNameForms())
+    {
+      addNameForm(nameForm.duplicate(), overwrite);
+    }
+
+    for (final DITContentRule contentRule : schema.getDITContentRules())
+    {
+      addDITContentRule(contentRule.duplicate(), overwrite);
+    }
+
+    for (final DITStructureRule structureRule : schema.getDITStuctureRules())
+    {
+      addDITStructureRule(structureRule.duplicate(), overwrite);
+    }
+
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided substitution syntax definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the substitution syntax definition.
+   * @param description
+   *          The description of the substitution syntax definition.
+   * @param substituteSyntax
+   *          The OID of the syntax whose implementation should be substituted.
+   * @param overwrite
+   *          {@code true} if any existing syntax with the same OID should be
+   *          overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   */
+  public SchemaBuilder addSubstitutionSyntax(final String oid,
+      final String description, final String substituteSyntax,
+      final boolean overwrite) throws ConflictingSchemaElementException
+  {
+    Validator.ensureNotNull(substituteSyntax);
+
+    addSyntax(new Syntax(oid, description, Collections.singletonMap("X-SUBST",
+        Collections.singletonList(substituteSyntax)), null, null), overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided syntax definition to this schema builder.
+   *
+   * @param definition
+   *          The syntax definition.
+   * @param overwrite
+   *          {@code true} if any existing syntax with the same OID should be
+   *          overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws LocalizedIllegalArgumentException
+   *           If the provided syntax definition could not be parsed.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addSyntax(final String definition,
+      final boolean overwrite) throws ConflictingSchemaElementException,
+      LocalizedIllegalArgumentException, NullPointerException
+  {
+    Validator.ensureNotNull(definition);
+    try
+    {
+      final SubstringReader reader = new SubstringReader(definition);
+
+      // We'll do this a character at a time. First, skip over any
+      // leading whitespace.
+      reader.skipWhitespaces();
+
+      if (reader.remaining() <= 0)
+      {
+        // This means that the value was empty or contained only
+        // whitespace. That is illegal.
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE
+            .get();
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // The next character must be an open parenthesis. If it is not,
+      // then that is an error.
+      final char c = reader.read();
+      if (c != '(')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS
+            .get(definition, (reader.pos() - 1), String.valueOf(c));
+        throw new LocalizedIllegalArgumentException(message);
+      }
+
+      // Skip over any spaces immediately following the opening
+      // parenthesis.
+      reader.skipWhitespaces();
+
+      // The next set of characters must be the OID.
+      final String oid = SchemaUtils.readOID(reader);
+
+      String description = "".intern();
+      Map<String, List<String>> extraProperties = Collections.emptyMap();
+
+      // At this point, we should have a pretty specific syntax that
+      // describes what may come next, but some of the components are
+      // optional and it would be pretty easy to put something in the
+      // wrong order, so we will be very flexible about what we can
+      // accept. Just look at the next token, figure out what it is and
+      // how to treat what comes after it, then repeat until we get to
+      // the end of the value. But before we start, set default values
+      // for everything else we might need to know.
+      while (true)
+      {
+        final String tokenName = SchemaUtils.readTokenName(reader);
+
+        if (tokenName == null)
+        {
+          // No more tokens.
+          break;
+        }
+        else if (tokenName.equalsIgnoreCase("desc"))
+        {
+          // This specifies the description for the syntax. It is an
+          // arbitrary string of characters enclosed in single quotes.
+          description = SchemaUtils.readQuotedString(reader);
+        }
+        else if (tokenName.matches("^X-[A-Za-z_-]+$"))
+        {
+          // This must be a non-standard property and it must be
+          // followed by either a single definition in single quotes or
+          // an open parenthesis followed by one or more values in
+          // single quotes separated by spaces followed by a close
+          // parenthesis.
+          if (extraProperties.isEmpty())
+          {
+            extraProperties = new HashMap<String, List<String>>();
+          }
+          extraProperties.put(tokenName, SchemaUtils.readExtensions(reader));
+        }
+        else
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_TOKEN
+              .get(tokenName);
+          throw new LocalizedIllegalArgumentException(message);
+        }
+      }
+
+      if (!extraProperties.isEmpty())
+      {
+        extraProperties = Collections.unmodifiableMap(extraProperties);
+      }
+
+      // See if it is a enum syntax
+      for (final Map.Entry<String, List<String>> property : extraProperties
+          .entrySet())
+      {
+        if (property.getKey().equalsIgnoreCase("x-enum"))
+        {
+          final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid, property
+              .getValue());
+          final Syntax enumSyntax = new Syntax(oid, description,
+              extraProperties, definition, enumImpl);
+          final MatchingRule enumOMR = new MatchingRule(enumImpl
+              .getOrderingMatchingRule(), Collections
+              .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
+              CoreSchemaImpl.OPENDS_ORIGIN, null, new EnumOrderingMatchingRule(
+                  enumImpl));
+
+          addSyntax(enumSyntax, overwrite);
+          addMatchingRule(enumOMR, overwrite);
+          return this;
+        }
+      }
+
+      addSyntax(
+          new Syntax(oid, description, extraProperties, definition, null),
+          overwrite);
+    }
+    catch (final DecodeException e)
+    {
+      throw new LocalizedIllegalArgumentException(e.getMessageObject(), e
+          .getCause());
+    }
+    return this;
+  }
+
+
+
+  /**
+   * Adds the provided syntax definition to this schema builder.
+   *
+   * @param oid
+   *          The OID of the syntax definition.
+   * @param description
+   *          The description of the syntax definition.
+   * @param extraProperties
+   *          A map containing additional properties associated with the syntax
+   *          definition.
+   * @param implementation
+   *          The implementation of the syntax.
+   * @param overwrite
+   *          {@code true} if any existing syntax with the same OID should be
+   *          overwritten.
+   * @return A reference to this schema builder.
+   * @throws ConflictingSchemaElementException
+   *           If {@code overwrite} was {@code false} and a conflicting schema
+   *           element was found.
+   * @throws NullPointerException
+   *           If {@code definition} was {@code null}.
+   */
+  public SchemaBuilder addSyntax(final String oid, final String description,
+      final Map<String, List<String>> extraProperties,
+      final SyntaxImpl implementation, final boolean overwrite)
+      throws ConflictingSchemaElementException, NullPointerException
+  {
+    addSyntax(new Syntax(oid, description,
+        unmodifiableCopyOfExtraProperties(extraProperties), null,
+        implementation), overwrite);
+    return this;
+  }
+
+
+
+  /**
+   * Removes the named attribute type from this schema builder.
+   *
+   * @param name
+   *          The name or OID of the attribute type to be removed.
+   * @return {@code true} if the attribute type was found.
+   */
+  public boolean removeAttributeType(final String name)
+  {
+    if (schema.hasAttributeType(name))
+    {
+      removeAttributeType(schema.getAttributeType(name));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Removes the named DIT content rule from this schema builder.
+   *
+   * @param name
+   *          The name or OID of the DIT content rule to be removed.
+   * @return {@code true} if the DIT content rule was found.
+   */
+  public boolean removeDITContentRule(final String name)
+  {
+    if (schema.hasDITContentRule(name))
+    {
+      removeDITContentRule(schema.getDITContentRule(name));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Removes the specified DIT structure rule from this schema builder.
+   *
+   * @param ruleID
+   *          The ID of the DIT structure rule to be removed.
+   * @return {@code true} if the DIT structure rule was found.
+   */
+  public boolean removeDITStructureRule(final Integer ruleID)
+  {
+    if (schema.hasDITStructureRule(ruleID))
+    {
+      removeDITStructureRule(schema.getDITStructureRule(ruleID));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Removes the named matching rule from this schema builder.
+   *
+   * @param name
+   *          The name or OID of the matching rule to be removed.
+   * @return {@code true} if the matching rule was found.
+   */
+  public boolean removeMatchingRule(final String name)
+  {
+    if (schema.hasMatchingRule(name))
+    {
+      removeMatchingRule(schema.getMatchingRule(name));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Removes the named matching rule use from this schema builder.
+   *
+   * @param name
+   *          The name or OID of the matching rule use to be removed.
+   * @return {@code true} if the matching rule use was found.
+   */
+  public boolean removeMatchingRuleUse(final String name)
+  {
+    if (schema.hasMatchingRuleUse(name))
+    {
+      removeMatchingRuleUse(schema.getMatchingRuleUse(name));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Removes the named name form from this schema builder.
+   *
+   * @param name
+   *          The name or OID of the name form to be removed.
+   * @return {@code true} if the name form was found.
+   */
+  public boolean removeNameForm(final String name)
+  {
+    if (schema.hasNameForm(name))
+    {
+      removeNameForm(schema.getNameForm(name));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Removes the named object class from this schema builder.
+   *
+   * @param name
+   *          The name or OID of the object class to be removed.
+   * @return {@code true} if the object class was found.
+   */
+  public boolean removeObjectClass(final String name)
+  {
+    if (schema.hasObjectClass(name))
+    {
+      removeObjectClass(schema.getObjectClass(name));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Removes the named syntax from this schema builder.
+   *
+   * @param numericOID
+   *          The name of the syntax to be removed.
+   * @return {@code true} if the syntax was found.
+   */
+  public boolean removeSyntax(final String numericOID)
+  {
+    if (schema.hasSyntax(numericOID))
+    {
+      removeSyntax(schema.getSyntax(numericOID));
+      return true;
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Sets the schema compatibility options for this schema builder. The schema
+   * builder maintains its own set of compatibility options, so subsequent
+   * changes to the provided set of options will not impact this schema builder.
+   *
+   * @param options
+   *          The set of schema compatibility options that this schema builder
+   *          should use.
+   * @return A reference to this schema builder.
+   * @throws NullPointerException
+   *           If {@code options} was {@code null}.
+   */
+  public SchemaBuilder setSchemaCompatOptions(final SchemaCompatOptions options)
+      throws NullPointerException
+  {
+    Validator.ensureNotNull(options);
+    this.options.assign(options);
+    return this;
+  }
+
+
+
+  /**
+   * Returns a {@code Schema} containing all of the schema elements contained in
+   * this schema builder as well as the same set of schema compatibility
+   * options.
+   * <p>
+   * When this method returns this schema builder is empty and contains a
+   * default set of compatibility options.
+   *
+   * @return A {@code Schema} containing all of the schema elements contained in
+   *         this schema builder as well as the same set of schema compatibility
+   *         options
+   */
+  public Schema toSchema()
+  {
+    validate();
+    final Schema builtSchema = schema;
+    initBuilder(null);
+    return builtSchema;
+  }
+
+
+
+  void addWarning(final LocalizableMessage warning)
+  {
+    warnings.add(warning);
+  }
+
+
+
+  private void addAttributeType(final AttributeType attribute,
+      final boolean overwrite) throws ConflictingSchemaElementException
+  {
+    AttributeType conflictingAttribute;
+    if (numericOID2AttributeTypes.containsKey(attribute.getOID()))
+    {
+      conflictingAttribute = numericOID2AttributeTypes.get(attribute.getOID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_ATTRIBUTE_OID
+            .get(attribute.getNameOrOID(), attribute.getOID(),
+                conflictingAttribute.getNameOrOID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeAttributeType(conflictingAttribute);
+    }
+
+    numericOID2AttributeTypes.put(attribute.getOID(), attribute);
+    for (final String name : attribute.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      List<AttributeType> attrs;
+      if ((attrs = name2AttributeTypes.get(lowerName)) == null)
+      {
+        name2AttributeTypes
+            .put(lowerName, Collections.singletonList(attribute));
+      }
+      else if (attrs.size() == 1)
+      {
+        attrs = new ArrayList<AttributeType>(attrs);
+        attrs.add(attribute);
+        name2AttributeTypes.put(lowerName, attrs);
+      }
+      else
+      {
+        attrs.add(attribute);
+      }
+    }
+  }
+
+
+
+  private void addDITContentRule(final DITContentRule rule,
+      final boolean overwrite) throws ConflictingSchemaElementException
+  {
+    DITContentRule conflictingRule;
+    if (numericOID2ContentRules.containsKey(rule.getStructuralClassOID()))
+    {
+      conflictingRule = numericOID2ContentRules.get(rule
+          .getStructuralClassOID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_DIT_CONTENT_RULE
+            .get(rule.getNameOrOID(), rule.getStructuralClassOID(),
+                conflictingRule.getNameOrOID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeDITContentRule(conflictingRule);
+    }
+
+    numericOID2ContentRules.put(rule.getStructuralClassOID(), rule);
+    for (final String name : rule.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      List<DITContentRule> rules;
+      if ((rules = name2ContentRules.get(lowerName)) == null)
+      {
+        name2ContentRules.put(lowerName, Collections.singletonList(rule));
+      }
+      else if (rules.size() == 1)
+      {
+        rules = new ArrayList<DITContentRule>(rules);
+        rules.add(rule);
+        name2ContentRules.put(lowerName, rules);
+      }
+      else
+      {
+        rules.add(rule);
+      }
+    }
+  }
+
+
+
+  private void addDITStructureRule(final DITStructureRule rule,
+      final boolean overwrite) throws ConflictingSchemaElementException
+  {
+    DITStructureRule conflictingRule;
+    if (id2StructureRules.containsKey(rule.getRuleID()))
+    {
+      conflictingRule = id2StructureRules.get(rule.getRuleID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_DIT_STRUCTURE_RULE_ID
+            .get(rule.getNameOrRuleID(), rule.getRuleID(), conflictingRule
+                .getNameOrRuleID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeDITStructureRule(conflictingRule);
+    }
+
+    id2StructureRules.put(rule.getRuleID(), rule);
+    for (final String name : rule.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      List<DITStructureRule> rules;
+      if ((rules = name2StructureRules.get(lowerName)) == null)
+      {
+        name2StructureRules.put(lowerName, Collections.singletonList(rule));
+      }
+      else if (rules.size() == 1)
+      {
+        rules = new ArrayList<DITStructureRule>(rules);
+        rules.add(rule);
+        name2StructureRules.put(lowerName, rules);
+      }
+      else
+      {
+        rules.add(rule);
+      }
+    }
+  }
+
+
+
+  private void addMatchingRule(final MatchingRule rule, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    MatchingRule conflictingRule;
+    if (numericOID2MatchingRules.containsKey(rule.getOID()))
+    {
+      conflictingRule = numericOID2MatchingRules.get(rule.getOID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_MR_OID.get(
+            rule.getNameOrOID(), rule.getOID(), conflictingRule.getNameOrOID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeMatchingRule(conflictingRule);
+    }
+
+    numericOID2MatchingRules.put(rule.getOID(), rule);
+    for (final String name : rule.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      List<MatchingRule> rules;
+      if ((rules = name2MatchingRules.get(lowerName)) == null)
+      {
+        name2MatchingRules.put(lowerName, Collections.singletonList(rule));
+      }
+      else if (rules.size() == 1)
+      {
+        rules = new ArrayList<MatchingRule>(rules);
+        rules.add(rule);
+        name2MatchingRules.put(lowerName, rules);
+      }
+      else
+      {
+        rules.add(rule);
+      }
+    }
+  }
+
+
+
+  private void addMatchingRuleUse(final MatchingRuleUse use,
+      final boolean overwrite) throws ConflictingSchemaElementException
+  {
+    MatchingRuleUse conflictingUse;
+    if (numericOID2MatchingRuleUses.containsKey(use.getMatchingRuleOID()))
+    {
+      conflictingUse = numericOID2MatchingRuleUses
+          .get(use.getMatchingRuleOID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_MATCHING_RULE_USE
+            .get(use.getNameOrOID(), use.getMatchingRuleOID(), conflictingUse
+                .getNameOrOID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeMatchingRuleUse(conflictingUse);
+    }
+
+    numericOID2MatchingRuleUses.put(use.getMatchingRuleOID(), use);
+    for (final String name : use.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      List<MatchingRuleUse> uses;
+      if ((uses = name2MatchingRuleUses.get(lowerName)) == null)
+      {
+        name2MatchingRuleUses.put(lowerName, Collections.singletonList(use));
+      }
+      else if (uses.size() == 1)
+      {
+        uses = new ArrayList<MatchingRuleUse>(uses);
+        uses.add(use);
+        name2MatchingRuleUses.put(lowerName, uses);
+      }
+      else
+      {
+        uses.add(use);
+      }
+    }
+  }
+
+
+
+  private void addNameForm(final NameForm form, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    NameForm conflictingForm;
+    if (numericOID2NameForms.containsKey(form.getOID()))
+    {
+      conflictingForm = numericOID2NameForms.get(form.getOID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_NAME_FORM_OID
+            .get(form.getNameOrOID(), form.getOID(), conflictingForm
+                .getNameOrOID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeNameForm(conflictingForm);
+    }
+
+    numericOID2NameForms.put(form.getOID(), form);
+    for (final String name : form.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      List<NameForm> forms;
+      if ((forms = name2NameForms.get(lowerName)) == null)
+      {
+        name2NameForms.put(lowerName, Collections.singletonList(form));
+      }
+      else if (forms.size() == 1)
+      {
+        forms = new ArrayList<NameForm>(forms);
+        forms.add(form);
+        name2NameForms.put(lowerName, forms);
+      }
+      else
+      {
+        forms.add(form);
+      }
+    }
+  }
+
+
+
+  private void addObjectClass(final ObjectClass oc, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    ObjectClass conflictingOC;
+    if (numericOID2ObjectClasses.containsKey(oc.getOID()))
+    {
+      conflictingOC = numericOID2ObjectClasses.get(oc.getOID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_OBJECTCLASS_OID
+            .get(oc.getNameOrOID(), oc.getOID(), conflictingOC.getNameOrOID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeObjectClass(conflictingOC);
+    }
+
+    numericOID2ObjectClasses.put(oc.getOID(), oc);
+    for (final String name : oc.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      List<ObjectClass> classes;
+      if ((classes = name2ObjectClasses.get(lowerName)) == null)
+      {
+        name2ObjectClasses.put(lowerName, Collections.singletonList(oc));
+      }
+      else if (classes.size() == 1)
+      {
+        classes = new ArrayList<ObjectClass>(classes);
+        classes.add(oc);
+        name2ObjectClasses.put(lowerName, classes);
+      }
+      else
+      {
+        classes.add(oc);
+      }
+    }
+  }
+
+
+
+  private void addSyntax(final Syntax syntax, final boolean overwrite)
+      throws ConflictingSchemaElementException
+  {
+    Syntax conflictingSyntax;
+    if (numericOID2Syntaxes.containsKey(syntax.getOID()))
+    {
+      conflictingSyntax = numericOID2Syntaxes.get(syntax.getOID());
+      if (!overwrite)
+      {
+        final LocalizableMessage message = ERR_SCHEMA_CONFLICTING_SYNTAX_OID
+            .get(syntax.toString(), syntax.getOID(), conflictingSyntax.getOID());
+        throw new ConflictingSchemaElementException(message);
+      }
+      removeSyntax(conflictingSyntax);
+    }
+    numericOID2Syntaxes.put(syntax.getOID(), syntax);
+  }
+
+
+
+  private void initBuilder(String schemaName)
+  {
+    numericOID2Syntaxes = new LinkedHashMap<String, Syntax>();
+    numericOID2MatchingRules = new LinkedHashMap<String, MatchingRule>();
+    numericOID2MatchingRuleUses = new LinkedHashMap<String, MatchingRuleUse>();
+    numericOID2AttributeTypes = new LinkedHashMap<String, AttributeType>();
+    numericOID2ObjectClasses = new LinkedHashMap<String, ObjectClass>();
+    numericOID2NameForms = new LinkedHashMap<String, NameForm>();
+    numericOID2ContentRules = new LinkedHashMap<String, DITContentRule>();
+    id2StructureRules = new LinkedHashMap<Integer, DITStructureRule>();
+
+    name2MatchingRules = new LinkedHashMap<String, List<MatchingRule>>();
+    name2MatchingRuleUses = new LinkedHashMap<String, List<MatchingRuleUse>>();
+    name2AttributeTypes = new LinkedHashMap<String, List<AttributeType>>();
+    name2ObjectClasses = new LinkedHashMap<String, List<ObjectClass>>();
+    name2NameForms = new LinkedHashMap<String, List<NameForm>>();
+    name2ContentRules = new LinkedHashMap<String, List<DITContentRule>>();
+    name2StructureRules = new LinkedHashMap<String, List<DITStructureRule>>();
+
+    objectClass2NameForms = new HashMap<String, List<NameForm>>();
+    nameForm2StructureRules = new HashMap<String, List<DITStructureRule>>();
+    options = SchemaCompatOptions.defaultOptions();
+    warnings = new LinkedList<LocalizableMessage>();
+
+    if (schemaName == null)
+    {
+      schemaName = String.format("Schema#%d", nextSchemaID.getAndIncrement());
+    }
+
+    schema = new Schema(schemaName, numericOID2Syntaxes,
+        numericOID2MatchingRules, numericOID2MatchingRuleUses,
+        numericOID2AttributeTypes, numericOID2ObjectClasses,
+        numericOID2NameForms, numericOID2ContentRules, id2StructureRules,
+        name2MatchingRules, name2MatchingRuleUses, name2AttributeTypes,
+        name2ObjectClasses, name2NameForms, name2ContentRules,
+        name2StructureRules, objectClass2NameForms, nameForm2StructureRules,
+        options, warnings);
+  }
+
+
+
+  private void removeAttributeType(final AttributeType attributeType)
+  {
+    numericOID2AttributeTypes.remove(attributeType.getOID());
+    for (final String name : attributeType.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      final List<AttributeType> attributes = name2AttributeTypes.get(lowerName);
+      if (attributes != null && attributes.contains(attributeType))
+      {
+        if (attributes.size() <= 1)
+        {
+          name2AttributeTypes.remove(lowerName);
+        }
+        else
+        {
+          attributes.remove(attributeType);
+        }
+      }
+    }
+  }
+
+
+
+  private void removeDITContentRule(final DITContentRule rule)
+  {
+    numericOID2ContentRules.remove(rule.getStructuralClassOID());
+    for (final String name : rule.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      final List<DITContentRule> rules = name2ContentRules.get(lowerName);
+      if (rules != null && rules.contains(rule))
+      {
+        if (rules.size() <= 1)
+        {
+          name2AttributeTypes.remove(lowerName);
+        }
+        else
+        {
+          rules.remove(rule);
+        }
+      }
+    }
+  }
+
+
+
+  private void removeDITStructureRule(final DITStructureRule rule)
+  {
+    id2StructureRules.remove(rule.getRuleID());
+    for (final String name : rule.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      final List<DITStructureRule> rules = name2StructureRules.get(lowerName);
+      if (rules != null && rules.contains(rule))
+      {
+        if (rules.size() <= 1)
+        {
+          name2StructureRules.remove(lowerName);
+        }
+        else
+        {
+          rules.remove(rule);
+        }
+      }
+    }
+  }
+
+
+
+  private void removeMatchingRule(final MatchingRule rule)
+  {
+    numericOID2MatchingRules.remove(rule.getOID());
+    for (final String name : rule.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      final List<MatchingRule> rules = name2MatchingRules.get(lowerName);
+      if (rules != null && rules.contains(rule))
+      {
+        if (rules.size() <= 1)
+        {
+          name2MatchingRules.remove(lowerName);
+        }
+        else
+        {
+          rules.remove(rule);
+        }
+      }
+    }
+  }
+
+
+
+  private void removeMatchingRuleUse(final MatchingRuleUse use)
+  {
+    numericOID2MatchingRuleUses.remove(use.getMatchingRuleOID());
+    for (final String name : use.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      final List<MatchingRuleUse> uses = name2MatchingRuleUses.get(lowerName);
+      if (uses != null && uses.contains(use))
+      {
+        if (uses.size() <= 1)
+        {
+          name2MatchingRuleUses.remove(lowerName);
+        }
+        else
+        {
+          uses.remove(use);
+        }
+      }
+    }
+  }
+
+
+
+  private void removeNameForm(final NameForm form)
+  {
+    numericOID2NameForms.remove(form.getOID());
+    name2NameForms.remove(form.getOID());
+    for (final String name : form.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      final List<NameForm> forms = name2NameForms.get(lowerName);
+      if (forms != null && forms.contains(form))
+      {
+        if (forms.size() <= 1)
+        {
+          name2NameForms.remove(lowerName);
+        }
+        else
+        {
+          forms.remove(form);
+        }
+      }
+    }
+  }
+
+
+
+  private void removeObjectClass(final ObjectClass oc)
+  {
+    numericOID2ObjectClasses.remove(oc.getOID());
+    name2ObjectClasses.remove(oc.getOID());
+    for (final String name : oc.getNames())
+    {
+      final String lowerName = StaticUtils.toLowerCase(name);
+      final List<ObjectClass> classes = name2ObjectClasses.get(lowerName);
+      if (classes != null && classes.contains(oc))
+      {
+        if (classes.size() <= 1)
+        {
+          name2ObjectClasses.remove(lowerName);
+        }
+        else
+        {
+          classes.remove(oc);
+        }
+      }
+    }
+  }
+
+
+
+  private void removeSyntax(final Syntax syntax)
+  {
+    numericOID2Syntaxes.remove(syntax.getOID());
+  }
+
+
+
+  private void validate()
+  {
+    // Verify all references in all elements
+    for (final Syntax syntax : numericOID2Syntaxes.values().toArray(
+        new Syntax[numericOID2Syntaxes.values().size()]))
+    {
+      try
+      {
+        syntax.validate(warnings, schema);
+      }
+      catch (final SchemaException e)
+      {
+        removeSyntax(syntax);
+        warnings.add(ERR_SYNTAX_VALIDATION_FAIL.get(syntax.toString(), e
+            .toString()));
+      }
+    }
+
+    for (final MatchingRule rule : numericOID2MatchingRules.values().toArray(
+        new MatchingRule[numericOID2MatchingRules.values().size()]))
+    {
+      try
+      {
+        rule.validate(warnings, schema);
+      }
+      catch (final SchemaException e)
+      {
+        removeMatchingRule(rule);
+        warnings.add(ERR_MR_VALIDATION_FAIL.get(rule.toString(), e.toString()));
+      }
+    }
+
+    for (final AttributeType attribute : numericOID2AttributeTypes.values()
+        .toArray(new AttributeType[numericOID2AttributeTypes.values().size()]))
+    {
+      try
+      {
+        attribute.validate(warnings, schema);
+      }
+      catch (final SchemaException e)
+      {
+        removeAttributeType(attribute);
+        warnings.add(ERR_ATTR_TYPE_VALIDATION_FAIL.get(attribute.toString(), e
+            .toString()));
+      }
+    }
+
+    for (final ObjectClass oc : numericOID2ObjectClasses.values().toArray(
+        new ObjectClass[numericOID2ObjectClasses.values().size()]))
+    {
+      try
+      {
+        oc.validate(warnings, schema);
+      }
+      catch (final SchemaException e)
+      {
+        removeObjectClass(oc);
+        warnings.add(ERR_OC_VALIDATION_FAIL.get(oc.toString(), e.toString()));
+      }
+    }
+
+    for (final MatchingRuleUse use : numericOID2MatchingRuleUses.values()
+        .toArray(
+            new MatchingRuleUse[numericOID2MatchingRuleUses.values().size()]))
+    {
+      try
+      {
+        use.validate(warnings, schema);
+      }
+      catch (final SchemaException e)
+      {
+        removeMatchingRuleUse(use);
+        warnings.add(ERR_MRU_VALIDATION_FAIL.get(use.toString(), e.toString()));
+      }
+    }
+
+    for (final NameForm form : numericOID2NameForms.values().toArray(
+        new NameForm[numericOID2NameForms.values().size()]))
+    {
+      try
+      {
+        form.validate(warnings, schema);
+
+        // build the objectClass2NameForms map
+        List<NameForm> forms;
+        final String ocOID = form.getStructuralClass().getOID();
+        if ((forms = objectClass2NameForms.get(ocOID)) == null)
+        {
+          objectClass2NameForms.put(ocOID, Collections.singletonList(form));
+        }
+        else if (forms.size() == 1)
+        {
+          forms = new ArrayList<NameForm>(forms);
+          forms.add(form);
+          objectClass2NameForms.put(ocOID, forms);
+        }
+        else
+        {
+          forms.add(form);
+        }
+      }
+      catch (final SchemaException e)
+      {
+        removeNameForm(form);
+        warnings.add(ERR_NAMEFORM_VALIDATION_FAIL.get(form.toString(), e
+            .toString()));
+      }
+    }
+
+    for (final DITContentRule rule : numericOID2ContentRules.values().toArray(
+        new DITContentRule[numericOID2ContentRules.values().size()]))
+    {
+      try
+      {
+        rule.validate(warnings, schema);
+      }
+      catch (final SchemaException e)
+      {
+        removeDITContentRule(rule);
+        warnings
+            .add(ERR_DCR_VALIDATION_FAIL.get(rule.toString(), e.toString()));
+      }
+    }
+
+    for (final DITStructureRule rule : id2StructureRules.values().toArray(
+        new DITStructureRule[id2StructureRules.values().size()]))
+    {
+      try
+      {
+        rule.validate(warnings, schema);
+
+        // build the nameForm2StructureRules map
+        List<DITStructureRule> rules;
+        final String ocOID = rule.getNameForm().getOID();
+        if ((rules = nameForm2StructureRules.get(ocOID)) == null)
+        {
+          nameForm2StructureRules.put(ocOID, Collections.singletonList(rule));
+        }
+        else if (rules.size() == 1)
+        {
+          rules = new ArrayList<DITStructureRule>(rules);
+          rules.add(rule);
+          nameForm2StructureRules.put(ocOID, rules);
+        }
+        else
+        {
+          rules.add(rule);
+        }
+      }
+      catch (final SchemaException e)
+      {
+        removeDITStructureRule(rule);
+        warnings
+            .add(ERR_DSR_VALIDATION_FAIL.get(rule.toString(), e.toString()));
+      }
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaCompatOptions.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaCompatOptions.java
new file mode 100644
index 0000000..fd57a1c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaCompatOptions.java
@@ -0,0 +1,162 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+/**
+ * This class provides various schema compatibility options which may be used to
+ * facilitate interoperability with legacy LDAP applications.
+ */
+public final class SchemaCompatOptions
+{
+  /**
+   * Creates a copy of the provided schema compatibility options.
+   *
+   * @param options
+   *          The options to be copied.
+   * @return The copy of the provided schema compatibility options.
+   */
+  public static SchemaCompatOptions copyOf(final SchemaCompatOptions options)
+  {
+    return defaultOptions().assign(options);
+  }
+
+
+
+  /**
+   * Creates a new set of schema compatibility options with default settings.
+   *
+   * @return The new schema compatibility options.
+   */
+  public static SchemaCompatOptions defaultOptions()
+  {
+    return new SchemaCompatOptions();
+  }
+
+
+
+  private boolean isTelephoneNumberSyntaxStrict = false;
+
+  private boolean isZeroLengthDirectoryStringsAllowed = false;
+
+
+
+  // Prevent direct instantiation.
+  private SchemaCompatOptions()
+  {
+    // Nothing to do.
+  }
+
+
+
+  /**
+   * Indicates whether or not the Telephone Number syntax should ensure that all
+   * values conform to the E.123 international telephone number format. By
+   * default this compatibility option is set to {@code false}.
+   *
+   * @return {@code true} if the Telephone Number syntax should ensure that all
+   *         values conform to the E.123 international telephone number format,
+   *         or {@code false} if not.
+   */
+  public boolean isTelephoneNumberSyntaxStrict()
+  {
+    return isTelephoneNumberSyntaxStrict;
+  }
+
+
+
+  /**
+   * Indicates whether or not zero-length values will be allowed by the
+   * Directory String syntax. This is technically forbidden by the LDAP
+   * specification, but it was allowed in earlier versions of the server, and
+   * the discussion of the directory string syntax in RFC 2252 does not
+   * explicitly state that they are not allowed. By default this compatibility
+   * option is set to {@code false}.
+   *
+   * @return {@code true} if zero-length values will be allowed by the Directory
+   *         String syntax, or {@code false} if not.
+   */
+  public boolean isZeroLengthDirectoryStringsAllowed()
+  {
+    return isZeroLengthDirectoryStringsAllowed;
+  }
+
+
+
+  /**
+   * Indicates whether or not the Telephone Number syntax should ensure that all
+   * values conform to the E.123 international telephone number format. By
+   * default this compatibility option is set to {@code false}.
+   *
+   * @param isStrict
+   *          {@code true} if the Telephone Number syntax should ensure that all
+   *          values conform to the E.123 international telephone number format,
+   *          or {@code false} if not.
+   * @return A reference to this {@code SchemaCompat}.
+   */
+  public SchemaCompatOptions setTelephoneNumberSyntaxStrict(
+      final boolean isStrict)
+  {
+    this.isTelephoneNumberSyntaxStrict = isStrict;
+    return this;
+  }
+
+
+
+  /**
+   * Specifies whether or not zero-length values will be allowed by the
+   * Directory String syntax. This is technically forbidden by the LDAP
+   * specification, but it was allowed in earlier versions of the server, and
+   * the discussion of the directory string syntax in RFC 2252 does not
+   * explicitly state that they are not allowed. By default this compatibility
+   * option is set to {@code false}.
+   *
+   * @param isAllowed
+   *          {@code true} if zero-length values will be allowed by the
+   *          Directory String syntax, or {@code false} if not.
+   * @return A reference to this {@code SchemaCompat}.
+   */
+  public SchemaCompatOptions setZeroLengthDirectoryStringsAllowed(
+      final boolean isAllowed)
+  {
+    this.isZeroLengthDirectoryStringsAllowed = isAllowed;
+    return this;
+  }
+
+
+
+  // Assigns the provided options to this set of options.
+  SchemaCompatOptions assign(final SchemaCompatOptions options)
+  {
+    return setTelephoneNumberSyntaxStrict(options.isTelephoneNumberSyntaxStrict)
+        .setZeroLengthDirectoryStringsAllowed(
+            options.isZeroLengthDirectoryStringsAllowed);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaConstants.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaConstants.java
new file mode 100644
index 0000000..9f0fcab
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaConstants.java
@@ -0,0 +1,1535 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class defines a number of constants used by Directory Server schema
+ * elements, like matching rules, syntaxes, attribute types, and objectclasses.
+ */
+final class SchemaConstants
+{
+  /**
+   * The IANA-assigned base OID for all things under the OpenDS umbrella.
+   */
+  public static final String OID_OPENDS_BASE = "1.3.6.1.4.1.26027";
+
+  /**
+   * The base OID that will be used for the OpenDS Directory Server project.
+   */
+  public static final String OID_OPENDS_SERVER_BASE = OID_OPENDS_BASE + ".1";
+
+  /**
+   * The base OID that will be used for OpenDS Directory Server attribute type
+   * definitions.
+   */
+  public static final String OID_OPENDS_SERVER_ATTRIBUTE_TYPE_BASE =
+    OID_OPENDS_SERVER_BASE + ".1";
+
+  /**
+   * The base OID that will be used for OpenDS Directory Server object class
+   * definitions.
+   */
+  public static final String OID_OPENDS_SERVER_OBJECT_CLASS_BASE =
+    OID_OPENDS_SERVER_BASE + ".2";
+
+  /**
+   * The base OID that will be used for OpenDS Directory Server attribute syntax
+   * definitions.
+   */
+  public static final String OID_OPENDS_SERVER_ATTRIBUTE_SYNTAX_BASE =
+    OID_OPENDS_SERVER_BASE + ".3";
+
+  /**
+   * The base OID that will be used for OpenDS Directory Server matching rule
+   * definitions.
+   */
+  public static final String OID_OPENDS_SERVER_MATCHING_RULE_BASE =
+    OID_OPENDS_SERVER_BASE + ".4";
+
+  /**
+   * The base OID that will be used for OpenDS Directory Server control
+   * definitions.
+   */
+  public static final String OID_OPENDS_SERVER_CONTROL_BASE =
+    OID_OPENDS_SERVER_BASE + ".5";
+
+  /**
+   * The base OID that will be used for OpenDS Directory Server extended
+   * operation definitions.
+   */
+  public static final String OID_OPENDS_SERVER_EXTENDED_OPERATION_BASE =
+    OID_OPENDS_SERVER_BASE + ".6";
+
+  /**
+   * The base OID that will be used for general-purpose (i.e., "other") types of
+   * OIDs that need to be allocated for the OpenDS Directory Server.
+   */
+  public static final String OID_OPENDS_SERVER_GENERAL_USE_BASE =
+    OID_OPENDS_SERVER_BASE + ".9";
+
+  /**
+   * The base OID that will be used for temporary or experimental OIDs within
+   * the OpenDS Directory Server.
+   */
+  public static final String OID_OPENDS_SERVER_EXPERIMENTAL_BASE =
+    OID_OPENDS_SERVER_BASE + ".999";
+
+  /**
+   * The description for the doubleMetaphoneApproximateMatch approximate
+   * matching rule.
+   */
+  public static final String AMR_DOUBLE_METAPHONE_DESCRIPTION =
+    "Double Metaphone Approximate Match";
+
+  /**
+   * The name for the doubleMetaphoneApproximateMatch approximate matching rule.
+   */
+  public static final String AMR_DOUBLE_METAPHONE_NAME =
+    "ds-mr-double-metaphone-approx";
+
+  /**
+   * The OID for the doubleMetaphoneApproximateMatch approximate matching rule.
+   */
+  public static final String AMR_DOUBLE_METAPHONE_OID =
+    OID_OPENDS_SERVER_MATCHING_RULE_BASE + ".1";
+
+  /**
+   * The description for the authPasswordExactMatch matching rule.
+   */
+  public static final String EMR_AUTH_PASSWORD_EXACT_DESCRIPTION =
+    "authentication password exact matching rule";
+
+  /**
+   * The name for the authPasswordExactMatch equality matching rule.
+   */
+  public static final String EMR_AUTH_PASSWORD_EXACT_NAME =
+    "authPasswordExactMatch";
+
+  /**
+   * The OID for the authPasswordExactMatch equality matching rule.
+   */
+  public static final String EMR_AUTH_PASSWORD_EXACT_OID =
+    "1.3.6.1.4.1.4203.1.2.2";
+
+  /**
+   * The description for the authPasswordMatch matching rule.
+   */
+  public static final String EMR_AUTH_PASSWORD_DESCRIPTION =
+    "authentication password matching rule";
+
+  /**
+   * The name for the authPasswordMatch equality matching rule.
+   */
+  public static final String EMR_AUTH_PASSWORD_NAME = "authPasswordMatch";
+
+  /**
+   * The OID for the authPasswordMatch equality matching rule.
+   */
+  public static final String EMR_AUTH_PASSWORD_OID = "1.3.6.1.4.1.4203.1.2.3";
+
+  /**
+   * The name for the bitStringMatch equality matching rule.
+   */
+  public static final String EMR_BIT_STRING_NAME = "bitStringMatch";
+
+  /**
+   * The OID for the bitStringMatch equality matching rule.
+   */
+  public static final String EMR_BIT_STRING_OID = "2.5.13.16";
+
+  /**
+   * The name for the booleanMatch equality matching rule.
+   */
+  public static final String EMR_BOOLEAN_NAME = "booleanMatch";
+
+  /**
+   * The OID for the booleanMatch equality matching rule.
+   */
+  public static final String EMR_BOOLEAN_OID = "2.5.13.13";
+
+  /**
+   * The name for the caseExactMatch equality matching rule.
+   */
+  public static final String EMR_CASE_EXACT_NAME = "caseExactMatch";
+
+  /**
+   * The OID for the caseExactMatch equality matching rule.
+   */
+  public static final String EMR_CASE_EXACT_OID = "2.5.13.5";
+
+  /**
+   * The name for the caseExactIA5Match equality matching rule.
+   */
+  public static final String EMR_CASE_EXACT_IA5_NAME = "caseExactIA5Match";
+
+  /**
+   * The OID for the caseExactIA5Match equality matching rule.
+   */
+  public static final String EMR_CASE_EXACT_IA5_OID =
+    "1.3.6.1.4.1.1466.109.114.1";
+
+  /**
+   * The name for the caseIgnoreMatch equality matching rule.
+   */
+  public static final String EMR_CASE_IGNORE_NAME = "caseIgnoreMatch";
+
+  /**
+   * The OID for the caseIgnoreMatch equality matching rule.
+   */
+  public static final String EMR_CASE_IGNORE_OID = "2.5.13.2";
+
+  /**
+   * The name for the caseIgnoreIA5Match equality matching rule.
+   */
+  public static final String EMR_CASE_IGNORE_IA5_NAME = "caseIgnoreIA5Match";
+
+  /**
+   * The OID for the caseIgnoreIA5Match equality matching rule.
+   */
+  public static final String EMR_CASE_IGNORE_IA5_OID =
+    "1.3.6.1.4.1.1466.109.114.2";
+
+  /**
+   * The name for the caseIgnoreListMatch equality matching rule.
+   */
+  public static final String EMR_CASE_IGNORE_LIST_NAME = "caseIgnoreListMatch";
+
+  /**
+   * The OID for the caseIgnoreListMatch equality matching rule.
+   */
+  public static final String EMR_CASE_IGNORE_LIST_OID = "2.5.13.11";
+
+  /**
+   * The name for the directoryStringFirstComponentMatch equality matching rule.
+   */
+  public static final String EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME =
+    "directoryStringFirstComponentMatch";
+
+  /**
+   * The OID for the directoryStringFirstComponentMatch equality matching rule.
+   */
+  public static final String EMR_DIRECTORY_STRING_FIRST_COMPONENT_OID =
+    "2.5.13.31";
+
+  /**
+   * The name for the distinguishedNameMatch equality matching rule.
+   */
+  public static final String EMR_DN_NAME = "distinguishedNameMatch";
+
+  /**
+   * The OID for the distinguishedNameMatch equality matching rule.
+   */
+  public static final String EMR_DN_OID = "2.5.13.1";
+
+  /**
+   * The name for the generalizedTimeMatch equality matching rule.
+   */
+  public static final String EMR_GENERALIZED_TIME_NAME = "generalizedTimeMatch";
+
+  /**
+   * The OID for the generalizedTimeMatch equality matching rule.
+   */
+  public static final String EMR_GENERALIZED_TIME_OID = "2.5.13.27";
+
+  /**
+   * The name for the integerMatch equality matching rule.
+   */
+  public static final String EMR_INTEGER_NAME = "integerMatch";
+
+  /**
+   * The OID for the integerMatch equality matching rule.
+   */
+  public static final String EMR_INTEGER_OID = "2.5.13.14";
+
+  /**
+   * The name for the integerFirstComponentMatch equality matching rule.
+   */
+  public static final String EMR_INTEGER_FIRST_COMPONENT_NAME =
+    "integerFirstComponentMatch";
+
+  /**
+   * The OID for the integerFirstComponentMatch equality matching rule.
+   */
+  public static final String EMR_INTEGER_FIRST_COMPONENT_OID = "2.5.13.29";
+
+  /**
+   * The name for the keywordMatch equality matching rule.
+   */
+  public static final String EMR_KEYWORD_NAME = "keywordMatch";
+
+  /**
+   * The OID for the keywordMatch equality matching rule.
+   */
+  public static final String EMR_KEYWORD_OID = "2.5.13.33";
+
+  /**
+   * The name for the numericStringMatch equality matching rule.
+   */
+  public static final String EMR_NUMERIC_STRING_NAME = "numericStringMatch";
+
+  /**
+   * The OID for the numericStringMatch equality matching rule.
+   */
+  public static final String EMR_NUMERIC_STRING_OID = "2.5.13.8";
+
+  /**
+   * The name for the octetStringMatch equality matching rule.
+   */
+  public static final String EMR_OCTET_STRING_NAME = "octetStringMatch";
+
+  /**
+   * The OID for the octetStringMatch equality matching rule.
+   */
+  public static final String EMR_OCTET_STRING_OID = "2.5.13.17";
+
+  /**
+   * The name for the objectIdentifierMatch equality matching rule.
+   */
+  public static final String EMR_OID_NAME = "objectIdentifierMatch";
+
+  /**
+   * The OID for the objectIdentifierMatch equality matching rule.
+   */
+  public static final String EMR_OID_OID = "2.5.13.0";
+
+  /**
+   * The name for the objectIdentifierFirstComponentMatch equality matching
+   * rule.
+   */
+  public static final String EMR_OID_FIRST_COMPONENT_NAME =
+    "objectIdentifierFirstComponentMatch";
+
+  /**
+   * The OID for the objectIdentifierFirstComponentMatch equality matching rule.
+   */
+  public static final String EMR_OID_FIRST_COMPONENT_OID = "2.5.13.30";
+
+  /**
+   * The name for the presentationAddressMatch equality matching rule.
+   */
+  public static final String EMR_PRESENTATION_ADDRESS_NAME =
+    "presentationAddressMatch";
+
+  /**
+   * The OID for the presentationAddressMatch equality matching rule.
+   */
+  public static final String EMR_PRESENTATION_ADDRESS_OID = "2.5.13.22";
+
+  /**
+   * The name for the protocolInformationMatch equality matching rule.
+   */
+  public static final String EMR_PROTOCOL_INFORMATION_NAME =
+    "protocolInformationMatch";
+
+  /**
+   * The OID for the protocolInformationMatch equality matching rule.
+   */
+  public static final String EMR_PROTOCOL_INFORMATION_OID = "2.5.13.24";
+
+  /**
+   * The name for the telephoneNumberMatch equality matching rule.
+   */
+  public static final String EMR_TELEPHONE_NAME = "telephoneNumberMatch";
+
+  /**
+   * The OID for the telephoneNumberMatch equality matching rule.
+   */
+  public static final String EMR_TELEPHONE_OID = "2.5.13.20";
+
+  /**
+   * The name for the uniqueMemberMatch equality matching rule.
+   */
+  public static final String EMR_UNIQUE_MEMBER_NAME = "uniqueMemberMatch";
+
+  /**
+   * The OID for the uniqueMemberMatch equality matching rule.
+   */
+  public static final String EMR_UNIQUE_MEMBER_OID = "2.5.13.23";
+
+  /**
+   * The description for the userPasswordExactMatch matching rule.
+   */
+  public static final String EMR_USER_PASSWORD_EXACT_DESCRIPTION =
+    "user password exact matching rule";
+
+  /**
+   * The name for the userPasswordExactMatch equality matching rule.
+   */
+  public static final String EMR_USER_PASSWORD_EXACT_NAME =
+    "ds-mr-user-password-exact";
+
+  /**
+   * The OID for the userPasswordExactMatch equality matching rule.
+   */
+  public static final String EMR_USER_PASSWORD_EXACT_OID =
+    OID_OPENDS_SERVER_MATCHING_RULE_BASE + ".2";
+
+  /**
+   * The description for the userPasswordMatch matching rule.
+   */
+  public static final String EMR_USER_PASSWORD_DESCRIPTION =
+    "user password matching rule";
+
+  /**
+   * The name for the userPasswordMatch equality matching rule.
+   */
+  public static final String EMR_USER_PASSWORD_NAME =
+    "ds-mr-user-password-equality";
+
+  /**
+   * The OID for the userPasswordMatch equality matching rule.
+   */
+  public static final String EMR_USER_PASSWORD_OID =
+    OID_OPENDS_SERVER_MATCHING_RULE_BASE + ".3";
+
+  /**
+   * The name for the uuidMatch equality matching rule.
+   */
+  public static final String EMR_UUID_NAME = "uuidMatch";
+
+  /**
+   * The OID for the uuidMatch equality matching rule.
+   */
+  public static final String EMR_UUID_OID = "1.3.6.1.1.16.2";
+
+  /**
+   * The name for the wordMatch equality matching rule.
+   */
+  public static final String EMR_WORD_NAME = "wordMatch";
+
+  /**
+   * The OID for the wordMatch equality matching rule.
+   */
+  public static final String EMR_WORD_OID = "2.5.13.32";
+
+  /**
+   * The name for the caseExactOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_CASE_EXACT_NAME = "caseExactOrderingMatch";
+
+  /**
+   * The OID for the caseExactOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_CASE_EXACT_OID = "2.5.13.6";
+
+  /**
+   * The name for the caseIgnoreOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_CASE_IGNORE_NAME = "caseIgnoreOrderingMatch";
+
+  /**
+   * The OID for the caseIgnoreOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_CASE_IGNORE_OID = "2.5.13.3";
+
+  /**
+   * The name for the generalizedTimeOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_GENERALIZED_TIME_NAME =
+    "generalizedTimeOrderingMatch";
+
+  /**
+   * The OID for the generalizedTimeOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_GENERALIZED_TIME_OID = "2.5.13.28";
+
+  /**
+   * The name for the integerOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_INTEGER_NAME = "integerOrderingMatch";
+
+  /**
+   * The OID for the integerOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_INTEGER_OID = "2.5.13.15";
+
+  /**
+   * The name for the numericStringOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_NUMERIC_STRING_NAME =
+    "numericStringOrderingMatch";
+
+  /**
+   * The OID for the numericStringOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_NUMERIC_STRING_OID = "2.5.13.9";
+
+  /**
+   * The name for the octetStringOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_OCTET_STRING_NAME = "octetStringOrderingMatch";
+
+  /**
+   * The OID for the octetStringOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_OCTET_STRING_OID = "2.5.13.18";
+
+  /**
+   * The name for the uuidOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_UUID_NAME = "uuidOrderingMatch";
+
+  /**
+   * The OID for the uuidOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_UUID_OID = "1.3.6.1.1.16.3";
+
+  /**
+   * The name for the enumOrderingMatch ordering matching rule.
+   */
+  public static final String OMR_GENERIC_ENUM_NAME = "enumOrderingMatch";
+
+  /**
+   * The oid for the generic enum syntax ordering matching rule.
+   */
+  public static final String OMR_OID_GENERIC_ENUM = "1.3.6.1.4.1.26027.1.4.8";
+
+  /**
+   * The name for the caseExactSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_EXACT_NAME = "caseExactSubstringsMatch";
+
+  /**
+   * The OID for the caseExactSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_EXACT_OID = "2.5.13.7";
+
+  /**
+   * The name for the caseExactIA5SubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_EXACT_IA5_NAME =
+    "caseExactIA5SubstringsMatch";
+
+  /**
+   * The OID for the caseExactIA5SubstringsMatch substring matching rule. //
+   * FIXME -- This needs to be updated once a real OID is assigned.
+   */
+  public static final String SMR_CASE_EXACT_IA5_OID =
+    OID_OPENDS_SERVER_MATCHING_RULE_BASE + ".902";
+
+  /**
+   * The name for the caseIgnoreSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_IGNORE_NAME = "caseIgnoreSubstringsMatch";
+
+  /**
+   * The OID for the caseIgnoreSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_IGNORE_OID = "2.5.13.4";
+
+  /**
+   * The name for the caseIgnoreIA5SubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_IGNORE_IA5_NAME =
+    "caseIgnoreIA5SubstringsMatch";
+
+  /**
+   * The OID for the caseIgnoreIA5SubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_IGNORE_IA5_OID =
+    "1.3.6.1.4.1.1466.109.114.3";
+
+  /**
+   * The name for the caseIgnoreListSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_IGNORE_LIST_NAME =
+    "caseIgnoreListSubstringsMatch";
+
+  /**
+   * The OID for the caseIgnoreListSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_CASE_IGNORE_LIST_OID = "2.5.13.12";
+
+  /**
+   * The name for the numericStringSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_NUMERIC_STRING_NAME =
+    "numericStringSubstringsMatch";
+
+  /**
+   * The OID for the numericStringSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_NUMERIC_STRING_OID = "2.5.13.10";
+
+  /**
+   * The name for the octetStringSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_OCTET_STRING_NAME =
+    "octetStringSubstringsMatch";
+
+  /**
+   * The OID for the octetStringSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_OCTET_STRING_OID = "2.5.13.19";
+
+  /**
+   * The name for the telephoneNumberSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_TELEPHONE_NAME =
+    "telephoneNumberSubstringsMatch";
+
+  /**
+   * The OID for the telephoneNumberSubstringsMatch substring matching rule.
+   */
+  public static final String SMR_TELEPHONE_OID = "2.5.13.21";
+
+  /**
+   * The OID for the absolute subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_OID =
+    OID_OPENDS_SERVER_ATTRIBUTE_SYNTAX_BASE + ".3";
+
+  /**
+   * The description for the absolute subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_DESCRIPTION =
+    "Absolute Subtree Specification";
+
+  /**
+   * The name for the absolute subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_NAME =
+    "ds-absolute-subtree-specification";
+
+  /**
+   * The OID for the aci attribute syntax.
+   */
+  public static final String SYNTAX_ACI_OID =
+    OID_OPENDS_SERVER_ATTRIBUTE_SYNTAX_BASE + ".4";
+
+  /**
+   * The description for aci attribute syntax.
+   */
+  public static final String SYNTAX_ACI_DESCRIPTION =
+    "Sun-defined Access Control Information";
+
+  /**
+   * The name for the aci attribute syntax.
+   */
+  public static final String SYNTAX_ACI_NAME = "ds-syntax-dseecompat-aci";
+
+  /**
+   * The description for the attribute type description attribute syntax.
+   */
+  public static final String SYNTAX_ATTRIBUTE_TYPE_DESCRIPTION =
+    "Attribute Type Description";
+
+  /**
+   * The name for the attribute type description attribute syntax.
+   */
+  public static final String SYNTAX_ATTRIBUTE_TYPE_NAME =
+    "AttributeTypeDescription";
+
+  /**
+   * The OID for the attribute type description attribute syntax.
+   */
+  public static final String SYNTAX_ATTRIBUTE_TYPE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.3";
+
+  /**
+   * The description for the auth password attribute syntax.
+   */
+  public static final String SYNTAX_AUTH_PASSWORD_DESCRIPTION =
+    "Authentication Password Syntax";
+
+  /**
+   * The name for the auth password attribute syntax.
+   */
+  public static final String SYNTAX_AUTH_PASSWORD_NAME =
+    "AuthenticationPasswordSyntax";
+
+  /**
+   * The OID for the auth password attribute syntax.
+   */
+  public static final String SYNTAX_AUTH_PASSWORD_OID = "1.3.6.1.4.1.4203.1.1.2";
+
+  /**
+   * The description for the binary attribute syntax.
+   */
+  public static final String SYNTAX_BINARY_DESCRIPTION = "Binary";
+
+  /**
+   * The name for the binary attribute syntax.
+   */
+  public static final String SYNTAX_BINARY_NAME = "Binary";
+
+  /**
+   * The OID for the binary attribute syntax.
+   */
+  public static final String SYNTAX_BINARY_OID = "1.3.6.1.4.1.1466.115.121.1.5";
+
+  /**
+   * The description for the bit string attribute syntax.
+   */
+  public static final String SYNTAX_BIT_STRING_DESCRIPTION = "Bit String";
+
+  /**
+   * The name for the bit string attribute syntax.
+   */
+  public static final String SYNTAX_BIT_STRING_NAME = "BitString";
+
+  /**
+   * The OID for the bit string attribute syntax.
+   */
+  public static final String SYNTAX_BIT_STRING_OID = "1.3.6.1.4.1.1466.115.121.1.6";
+
+  /**
+   * The description for the Boolean attribute syntax.
+   */
+  public static final String SYNTAX_BOOLEAN_DESCRIPTION = "Boolean";
+
+  /**
+   * The name for the Boolean attribute syntax.
+   */
+  public static final String SYNTAX_BOOLEAN_NAME = "Boolean";
+
+  /**
+   * The OID for the Boolean attribute syntax.
+   */
+  public static final String SYNTAX_BOOLEAN_OID = "1.3.6.1.4.1.1466.115.121.1.7";
+
+  /**
+   * The description for the certificate attribute syntax.
+   */
+  public static final String SYNTAX_CERTIFICATE_DESCRIPTION = "Certificate";
+
+  /**
+   * The name for the certificate attribute syntax.
+   */
+  public static final String SYNTAX_CERTIFICATE_NAME = "Certificate";
+
+  /**
+   * The OID for the certificate attribute syntax.
+   */
+  public static final String SYNTAX_CERTIFICATE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.8";
+
+  /**
+   * The description for the certificate list attribute syntax.
+   */
+  public static final String SYNTAX_CERTLIST_DESCRIPTION = "Certificate List";
+
+  /**
+   * The name for the certificate list attribute syntax.
+   */
+  public static final String SYNTAX_CERTLIST_NAME = "CertificateList";
+
+  /**
+   * The OID for the certificate list attribute syntax.
+   */
+  public static final String SYNTAX_CERTLIST_OID =
+    "1.3.6.1.4.1.1466.115.121.1.9";
+
+  /**
+   * The description for the certificate pair attribute syntax.
+   */
+  public static final String SYNTAX_CERTPAIR_DESCRIPTION = "Certificate Pair";
+
+  /**
+   * The name for the certificate pair attribute syntax.
+   */
+  public static final String SYNTAX_CERTPAIR_NAME = "CertificatePair";
+
+  /**
+   * The OID for the certificate pair attribute syntax.
+   */
+  public static final String SYNTAX_CERTPAIR_OID =
+    "1.3.6.1.4.1.1466.115.121.1.10";
+
+  /**
+   * The description for the country string attribute syntax.
+   */
+  public static final String SYNTAX_COUNTRY_STRING_DESCRIPTION =
+    "Country String";
+
+  /**
+   * The name for the country string attribute syntax.
+   */
+  public static final String SYNTAX_COUNTRY_STRING_NAME = "CountryString";
+
+  /**
+   * The OID for the country string attribute syntax.
+   */
+  public static final String SYNTAX_COUNTRY_STRING_OID =
+    "1.3.6.1.4.1.1466.115.121.1.11";
+
+  /**
+   * The description for the delivery method attribute syntax.
+   */
+  public static final String SYNTAX_DELIVERY_METHOD_DESCRIPTION =
+    "Delivery Method";
+
+  /**
+   * The name for the delivery method attribute syntax.
+   */
+  public static final String SYNTAX_DELIVERY_METHOD_NAME = "DeliveryMethod";
+
+  /**
+   * The OID for the delivery method attribute syntax.
+   */
+  public static final String SYNTAX_DELIVERY_METHOD_OID =
+    "1.3.6.1.4.1.1466.115.121.1.14";
+
+  /**
+   * The description for the Directory String attribute syntax.
+   */
+  public static final String SYNTAX_DIRECTORY_STRING_DESCRIPTION =
+    "Directory String";
+
+  /**
+   * The name for the Directory String attribute syntax.
+   */
+  public static final String SYNTAX_DIRECTORY_STRING_NAME = "DirectoryString";
+
+  /**
+   * The OID for the Directory String attribute syntax.
+   */
+  public static final String SYNTAX_DIRECTORY_STRING_OID =
+    "1.3.6.1.4.1.1466.115.121.1.15";
+
+  /**
+   * The description for the DIT content rule description attribute syntax.
+   */
+  public static final String SYNTAX_DIT_CONTENT_RULE_DESCRIPTION =
+    "DIT Content Rule Description";
+
+  /**
+   * The name for the DIT content rule description attribute syntax.
+   */
+  public static final String SYNTAX_DIT_CONTENT_RULE_NAME =
+    "DITContentRuleDescription";
+
+  /**
+   * The OID for the DIT content rule description attribute syntax.
+   */
+  public static final String SYNTAX_DIT_CONTENT_RULE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.16";
+
+  /**
+   * The description for the DIT structure rule description attribute syntax.
+   */
+  public static final String SYNTAX_DIT_STRUCTURE_RULE_DESCRIPTION =
+    "DIT Structure Rule Description";
+
+  /**
+   * The name for the DIT structure rule description attribute syntax.
+   */
+  public static final String SYNTAX_DIT_STRUCTURE_RULE_NAME =
+    "DITStructureRuleDescription";
+
+  /**
+   * The OID for the DIT structure rule description attribute syntax.
+   */
+  public static final String SYNTAX_DIT_STRUCTURE_RULE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.17";
+
+  /**
+   * The description for the distinguished name attribute syntax.
+   */
+  public static final String SYNTAX_DN_DESCRIPTION = "DN";
+
+  /**
+   * The name for the distinguished name attribute syntax.
+   */
+  public static final String SYNTAX_DN_NAME = "DN";
+
+  /**
+   * The OID for the distinguished name attribute syntax.
+   */
+  public static final String SYNTAX_DN_OID = "1.3.6.1.4.1.1466.115.121.1.12";
+
+  /**
+   * The description for the enhanced guide attribute syntax.
+   */
+  public static final String SYNTAX_ENHANCED_GUIDE_DESCRIPTION =
+    "Enhanced Guide";
+
+  /**
+   * The name for the enhanced guide attribute syntax.
+   */
+  public static final String SYNTAX_ENHANCED_GUIDE_NAME = "EnhancedGuide";
+
+  /**
+   * The OID for the enhanced guide attribute syntax.
+   */
+  public static final String SYNTAX_ENHANCED_GUIDE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.21";
+
+  /**
+   * The description for the facsimile telephone number attribute syntax.
+   */
+  public static final String SYNTAX_FAXNUMBER_DESCRIPTION =
+    "Facsimile Telephone Number";
+
+  /**
+   * The name for the facsimile telephone number attribute syntax.
+   */
+  public static final String SYNTAX_FAXNUMBER_NAME = "FacsimileTelephoneNumber";
+
+  /**
+   * The OID for the facsimile telephone number attribute syntax.
+   */
+  public static final String SYNTAX_FAXNUMBER_OID =
+    "1.3.6.1.4.1.1466.115.121.1.22";
+
+  /**
+   * The description for the fax attribute syntax.
+   */
+  public static final String SYNTAX_FAX_DESCRIPTION = "Fax";
+
+  /**
+   * The name for the fax attribute syntax.
+   */
+  public static final String SYNTAX_FAX_NAME = "Fax";
+
+  /**
+   * The OID for the fax attribute syntax.
+   */
+  public static final String SYNTAX_FAX_OID = "1.3.6.1.4.1.1466.115.121.1.23";
+
+  /**
+   * The description for the generalized time attribute syntax.
+   */
+  public static final String SYNTAX_GENERALIZED_TIME_DESCRIPTION =
+    "Generalized Time";
+
+  /**
+   * The name for the generalized time attribute syntax.
+   */
+  public static final String SYNTAX_GENERALIZED_TIME_NAME = "GeneralizedTime";
+
+  /**
+   * The OID for the generalized time attribute syntax.
+   */
+  public static final String SYNTAX_GENERALIZED_TIME_OID =
+    "1.3.6.1.4.1.1466.115.121.1.24";
+
+  /**
+   * The description for the guide attribute syntax.
+   */
+  public static final String SYNTAX_GUIDE_DESCRIPTION = "Guide";
+
+  /**
+   * The name for the guide attribute syntax.
+   */
+  public static final String SYNTAX_GUIDE_NAME = "Guide";
+
+  /**
+   * The OID for the guide attribute syntax.
+   */
+  public static final String SYNTAX_GUIDE_OID = "1.3.6.1.4.1.1466.115.121.1.25";
+
+  /**
+   * The description for the IA5 string attribute syntax.
+   */
+  public static final String SYNTAX_IA5_STRING_DESCRIPTION = "IA5 String";
+
+  /**
+   * The name for the IA5 string attribute syntax.
+   */
+  public static final String SYNTAX_IA5_STRING_NAME = "IA5String";
+
+  /**
+   * The OID for the IA5 string attribute syntax.
+   */
+  public static final String SYNTAX_IA5_STRING_OID =
+    "1.3.6.1.4.1.1466.115.121.1.26";
+
+  /**
+   * The description for the integer attribute syntax.
+   */
+  public static final String SYNTAX_INTEGER_DESCRIPTION = "Integer";
+
+  /**
+   * The name for the integer attribute syntax.
+   */
+  public static final String SYNTAX_INTEGER_NAME = "Integer";
+
+  /**
+   * The OID for the integer attribute syntax.
+   */
+  public static final String SYNTAX_INTEGER_OID =
+    "1.3.6.1.4.1.1466.115.121.1.27";
+
+  /**
+   * The description for the JPEG attribute syntax.
+   */
+  public static final String SYNTAX_JPEG_DESCRIPTION = "JPEG";
+
+  /**
+   * The name for the JPEG attribute syntax.
+   */
+  public static final String SYNTAX_JPEG_NAME = "JPEG";
+
+  /**
+   * The OID for the JPEG attribute syntax.
+   */
+  public static final String SYNTAX_JPEG_OID = "1.3.6.1.4.1.1466.115.121.1.28";
+
+  /**
+   * The description for the LDAP syntax description attribute syntax.
+   */
+  public static final String SYNTAX_LDAP_SYNTAX_DESCRIPTION =
+    "LDAP Syntax Description";
+
+  /**
+   * The name for the LDAP syntax description attribute syntax.
+   */
+  public static final String SYNTAX_LDAP_SYNTAX_NAME = "LDAPSyntaxDescription";
+
+  /**
+   * The OID for the LDAP syntax description attribute syntax.
+   */
+  public static final String SYNTAX_LDAP_SYNTAX_OID =
+    "1.3.6.1.4.1.1466.115.121.1.54";
+
+  /**
+   * The description for the matching rule description attribute syntax.
+   */
+  public static final String SYNTAX_MATCHING_RULE_DESCRIPTION =
+    "Matching Rule Description";
+
+  /**
+   * The name for the matching rule description attribute syntax.
+   */
+  public static final String SYNTAX_MATCHING_RULE_NAME =
+    "MatchingRuleDescription";
+
+  /**
+   * The OID for the matching rule description attribute syntax.
+   */
+  public static final String SYNTAX_MATCHING_RULE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.30";
+
+  /**
+   * The description for the matching rule use description attribute syntax.
+   */
+  public static final String SYNTAX_MATCHING_RULE_USE_DESCRIPTION =
+    "Matching Rule Use Description";
+
+  /**
+   * The name for the matching rule use description attribute syntax.
+   */
+  public static final String SYNTAX_MATCHING_RULE_USE_NAME =
+    "MatchingRuleUseDescription";
+
+  /**
+   * The OID for the matching rule use description attribute syntax.
+   */
+  public static final String SYNTAX_MATCHING_RULE_USE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.31";
+
+  /**
+   * The description for the name and optional uid attribute syntax.
+   */
+  public static final String SYNTAX_NAME_AND_OPTIONAL_UID_DESCRIPTION =
+    "Name and Optional UID";
+
+  /**
+   * The name for the name and optional uid attribute syntax.
+   */
+  public static final String SYNTAX_NAME_AND_OPTIONAL_UID_NAME =
+    "NameAndOptionalUID";
+
+  /**
+   * The OID for the name and optional uid attribute syntax.
+   */
+  public static final String SYNTAX_NAME_AND_OPTIONAL_UID_OID =
+    "1.3.6.1.4.1.1466.115.121.1.34";
+
+  /**
+   * The description for the name form description attribute syntax.
+   */
+  public static final String SYNTAX_NAME_FORM_DESCRIPTION =
+    "Name Form Description";
+
+  /**
+   * The name for the name form description attribute syntax.
+   */
+  public static final String SYNTAX_NAME_FORM_NAME = "NameFormDescription";
+
+  /**
+   * The OID for the name form description attribute syntax.
+   */
+  public static final String SYNTAX_NAME_FORM_OID =
+    "1.3.6.1.4.1.1466.115.121.1.35";
+
+  /**
+   * The description for the numeric string attribute syntax.
+   */
+  public static final String SYNTAX_NUMERIC_STRING_DESCRIPTION =
+    "Numeric String";
+
+  /**
+   * The name for the numeric string attribute syntax.
+   */
+  public static final String SYNTAX_NUMERIC_STRING_NAME = "NumericString";
+
+  /**
+   * The OID for the numeric string attribute syntax.
+   */
+  public static final String SYNTAX_NUMERIC_STRING_OID =
+    "1.3.6.1.4.1.1466.115.121.1.36";
+
+  /**
+   * The description for the object class description attribute syntax.
+   */
+  public static final String SYNTAX_OBJECTCLASS_DESCRIPTION =
+    "Object Class Description";
+
+  /**
+   * The name for the object class description attribute syntax.
+   */
+  public static final String SYNTAX_OBJECTCLASS_NAME = "ObjectClassDescription";
+
+  /**
+   * The OID for the object class description attribute syntax.
+   */
+  public static final String SYNTAX_OBJECTCLASS_OID =
+    "1.3.6.1.4.1.1466.115.121.1.37";
+
+  /**
+   * The description for the octet string attribute syntax.
+   */
+  public static final String SYNTAX_OCTET_STRING_DESCRIPTION = "Octet String";
+
+  /**
+   * The name for the octet string attribute syntax.
+   */
+  public static final String SYNTAX_OCTET_STRING_NAME = "OctetString";
+
+  /**
+   * The OID for the octet string attribute syntax.
+   */
+  public static final String SYNTAX_OCTET_STRING_OID =
+    "1.3.6.1.4.1.1466.115.121.1.40";
+
+  /**
+   * The description for the object identifier attribute syntax.
+   */
+  public static final String SYNTAX_OID_DESCRIPTION = "OID";
+
+  /**
+   * The name for the object identifier attribute syntax.
+   */
+  public static final String SYNTAX_OID_NAME = "OID";
+
+  /**
+   * The OID for the object identifier attribute syntax.
+   */
+  public static final String SYNTAX_OID_OID = "1.3.6.1.4.1.1466.115.121.1.38";
+
+  /**
+   * The description for the other mailbox attribute syntax.
+   */
+  public static final String SYNTAX_OTHER_MAILBOX_DESCRIPTION = "Other Mailbox";
+
+  /**
+   * The name for the other mailbox attribute syntax.
+   */
+  public static final String SYNTAX_OTHER_MAILBOX_NAME = "OtherMailbox";
+
+  /**
+   * The OID for the other mailbox attribute syntax.
+   */
+  public static final String SYNTAX_OTHER_MAILBOX_OID =
+    "1.3.6.1.4.1.1466.115.121.1.39";
+
+  /**
+   * The description for the postal address attribute syntax.
+   */
+  public static final String SYNTAX_POSTAL_ADDRESS_DESCRIPTION =
+    "Postal Address";
+
+  /**
+   * The name for the postal address attribute syntax.
+   */
+  public static final String SYNTAX_POSTAL_ADDRESS_NAME = "PostalAddress";
+
+  /**
+   * The OID for the postal address attribute syntax.
+   */
+  public static final String SYNTAX_POSTAL_ADDRESS_OID =
+    "1.3.6.1.4.1.1466.115.121.1.41";
+
+  /**
+   * The description for the presentation address attribute syntax.
+   */
+  public static final String SYNTAX_PRESENTATION_ADDRESS_DESCRIPTION =
+    "Presentation Address";
+
+  /**
+   * The name for the presentation address attribute syntax.
+   */
+  public static final String SYNTAX_PRESENTATION_ADDRESS_NAME =
+    "PresentationAddress";
+
+  /**
+   * The OID for the presentation address attribute syntax.
+   */
+  public static final String SYNTAX_PRESENTATION_ADDRESS_OID =
+    "1.3.6.1.4.1.1466.115.121.1.43";
+
+  /**
+   * The description for the printable string attribute syntax.
+   */
+  public static final String SYNTAX_PRINTABLE_STRING_DESCRIPTION =
+    "Printable String";
+
+  /**
+   * The name for the printable string attribute syntax.
+   */
+  public static final String SYNTAX_PRINTABLE_STRING_NAME = "PrintableString";
+
+  /**
+   * The OID for the printable string attribute syntax.
+   */
+  public static final String SYNTAX_PRINTABLE_STRING_OID =
+    "1.3.6.1.4.1.1466.115.121.1.44";
+
+  /**
+   * The description for the protocol information attribute syntax.
+   */
+  public static final String SYNTAX_PROTOCOL_INFORMATION_DESCRIPTION =
+    "Protocol Information";
+
+  /**
+   * The name for the protocol information attribute syntax.
+   */
+  public static final String SYNTAX_PROTOCOL_INFORMATION_NAME =
+    "ProtocolInformation";
+
+  /**
+   * The OID for the protocol information attribute syntax.
+   */
+  public static final String SYNTAX_PROTOCOL_INFORMATION_OID =
+    "1.3.6.1.4.1.1466.115.121.1.42";
+
+  /**
+   * The OID for the relative subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_OID =
+    OID_OPENDS_SERVER_ATTRIBUTE_SYNTAX_BASE + ".2";
+
+  /**
+   * The description for the relative subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_DESCRIPTION =
+    "Relative Subtree Specification";
+
+  /**
+   * The name for the relative subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_NAME =
+    "ds-relative-subtree-specification";
+
+  /**
+   * The OID for the RFC3672 subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_OID =
+    "1.3.6.1.4.1.1466.115.121.1.45";
+
+  /**
+   * The description for the RFC3672 subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_DESCRIPTION =
+    "RFC3672 Subtree Specification";
+
+  /**
+   * The name for the RFC3672 subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_NAME =
+    "SubtreeSpecification";
+
+  /**
+   * The description for the substring assertion attribute syntax.
+   */
+  public static final String SYNTAX_SUBSTRING_ASSERTION_DESCRIPTION =
+    "Substring Assertion";
+
+  /**
+   * The name for the substring assertion attribute syntax.
+   */
+  public static final String SYNTAX_SUBSTRING_ASSERTION_NAME =
+    "SubstringAssertion";
+
+  /**
+   * The OID for the Substring Assertion syntax used for assertion values in
+   * extensible match filters.
+   */
+  public static final String SYNTAX_SUBSTRING_ASSERTION_OID =
+    "1.3.6.1.4.1.1466.115.121.1.58";
+
+  /**
+   * The description for the supported algorithm attribute syntax.
+   */
+  public static final String SYNTAX_SUPPORTED_ALGORITHM_DESCRIPTION =
+    "Supported Algorithm";
+
+  /**
+   * The name for the supported algorithm attribute syntax.
+   */
+  public static final String SYNTAX_SUPPORTED_ALGORITHM_NAME =
+    "SupportedAlgorithm";
+
+  /**
+   * The OID for the Substring Assertion syntax used for assertion values in
+   * extensible match filters.
+   */
+  public static final String SYNTAX_SUPPORTED_ALGORITHM_OID =
+    "1.3.6.1.4.1.1466.115.121.1.49";
+
+  /**
+   * The description for the telephone number attribute syntax.
+   */
+  public static final String SYNTAX_TELEPHONE_DESCRIPTION = "Telephone Number";
+
+  /**
+   * The name for the telephone number attribute syntax.
+   */
+  public static final String SYNTAX_TELEPHONE_NAME = "TelephoneNumber";
+
+  /**
+   * The OID for the telephone number attribute syntax.
+   */
+  public static final String SYNTAX_TELEPHONE_OID =
+    "1.3.6.1.4.1.1466.115.121.1.50";
+
+  /**
+   * The description for the teletex terminal identifier attribute syntax.
+   */
+  public static final String SYNTAX_TELETEX_TERM_ID_DESCRIPTION =
+    "Teletex Terminal Identifier";
+
+  /**
+   * The name for the teletex terminal identifier attribute syntax.
+   */
+  public static final String SYNTAX_TELETEX_TERM_ID_NAME =
+    "TeletexTerminalIdentifier";
+
+  /**
+   * The OID for the teletex terminal identifier attribute syntax.
+   */
+  public static final String SYNTAX_TELETEX_TERM_ID_OID =
+    "1.3.6.1.4.1.1466.115.121.1.51";
+
+  /**
+   * The description for the telex number attribute syntax.
+   */
+  public static final String SYNTAX_TELEX_DESCRIPTION = "Telex Number";
+
+  /**
+   * The name for the telex number attribute syntax.
+   */
+  public static final String SYNTAX_TELEX_NAME = "TelexNumber";
+
+  /**
+   * The OID for the telex number attribute syntax.
+   */
+  public static final String SYNTAX_TELEX_OID = "1.3.6.1.4.1.1466.115.121.1.52";
+
+  /**
+   * The description for the user password attribute syntax.
+   */
+  public static final String SYNTAX_USER_PASSWORD_DESCRIPTION = "User Password";
+
+  /**
+   * The name for the user password attribute syntax.
+   */
+  public static final String SYNTAX_USER_PASSWORD_NAME =
+    "ds-syntax-user-password";
+
+  /**
+   * The OID for the user password attribute syntax.
+   */
+  public static final String SYNTAX_USER_PASSWORD_OID =
+    OID_OPENDS_SERVER_ATTRIBUTE_SYNTAX_BASE + ".1";
+
+  /**
+   * The description for the UTC time attribute syntax.
+   */
+  public static final String SYNTAX_UTC_TIME_DESCRIPTION = "UTC Time";
+
+  /**
+   * The name for the UTC time attribute syntax.
+   */
+  public static final String SYNTAX_UTC_TIME_NAME = "UTCTime";
+
+  /**
+   * The OID for the UTC time attribute syntax.
+   */
+  public static final String SYNTAX_UTC_TIME_OID =
+    "1.3.6.1.4.1.1466.115.121.1.53";
+
+  /**
+   * The description for the UUID attribute syntax.
+   */
+  public static final String SYNTAX_UUID_DESCRIPTION = "UUID";
+
+  /**
+   * The name for the UUID attribute syntax.
+   */
+  public static final String SYNTAX_UUID_NAME = "UUID";
+
+  /**
+   * The OID for the UUID attribute syntax.
+   */
+  public static final String SYNTAX_UUID_OID = "1.3.6.1.1.16.1";
+
+  /**
+   * The description for the "top" objectclass.
+   */
+  public static final String TOP_OBJECTCLASS_DESCRIPTION = "Topmost ObjectClass";
+
+  /**
+   * The name of the "top" objectclass.
+   */
+  public static final String TOP_OBJECTCLASS_NAME = "top";
+
+  /**
+   * The OID for the "top" objectclass.
+   */
+  public static final String TOP_OBJECTCLASS_OID = "2.5.6.0";
+
+  /**
+   * The name for the relative time greater-than extensible ordering matching
+   * rule.
+   */
+  public static final String EXT_OMR_RELATIVE_TIME_GT_NAME =
+    "relativeTimeGTOrderingMatch";
+
+  /**
+   * The alternative name for the relative time greater-than extensible ordering
+   * matching rule.
+   */
+  public static final String EXT_OMR_RELATIVE_TIME_GT_ALT_NAME =
+    "relativeTimeOrderingMatch.gt";
+
+  /**
+   * The OID for the relative time greater-than extensible ordering matching
+   * rule.
+   */
+  public static final String EXT_OMR_RELATIVE_TIME_GT_OID =
+    "1.3.6.1.4.1.26027.1.4.5";
+
+  /**
+   * The name for the relative time less-than extensible ordering matching rule.
+   */
+  public static final String EXT_OMR_RELATIVE_TIME_LT_NAME =
+    "relativeTimeLTOrderingMatch";
+
+  /**
+   * The alternative name for the relative time less-than extensible ordering
+   * matching rule.
+   */
+  public static final String EXT_OMR_RELATIVE_TIME_LT_ALT_NAME =
+    "relativeTimeOrderingMatch.lt";
+
+  /**
+   * The OID for the relative time less-than extensible ordering matching rule.
+   */
+  public static final String EXT_OMR_RELATIVE_TIME_LT_OID =
+    "1.3.6.1.4.1.26027.1.4.6";
+
+  /**
+   * The OID for the partial date and time extensible matching rule.
+   */
+  public static final String EXT_PARTIAL_DATE_TIME_OID =
+    "1.3.6.1.4.1.26027.1.4.7";
+
+  /**
+   * The name for the partial date and time extensible rule.
+   */
+  public static final String EXT_PARTIAL_DATE_TIME_NAME =
+    "partialDateAndTimeMatchingRule";
+
+  /**
+   * The name of the schema extension that will be used to specify the
+   * approximate matching rule that should be used for a given attribute type.
+   */
+  public static final String SCHEMA_PROPERTY_APPROX_RULE = "X-APPROX";
+
+  /**
+   * The name of the schema property that will be used to specify the origin of
+   * a schema element.
+   */
+  public static final String SCHEMA_PROPERTY_ORIGIN = "X-ORIGIN";
+
+  /**
+   * The OID for the extensibleObject objectclass.
+   */
+  public static final String EXTENSIBLE_OBJECT_OBJECTCLASS_OID =
+    "1.3.6.1.4.1.1466.101.120.111";
+
+  /**
+   * The name for the extensibleObject objectclass.
+   */
+  public static final String EXTENSIBLE_OBJECT_OBJECTCLASS_NAME =
+    "extensibleObject";
+
+  /**
+   * The value representing just one space character.
+   */
+  public static final ByteString SINGLE_SPACE_VALUE = ByteString.valueOf(" ");
+
+  /**
+   * The normalized true value.
+   */
+  public static final ByteString TRUE_VALUE = ByteString.valueOf("TRUE");
+
+  /**
+   * The normalized false value.
+   */
+  public static final ByteString FALSE_VALUE = ByteString.valueOf("FALSE");
+
+  /**
+   * The name of the time zone for universal coordinated time (UTC).
+   */
+  public static final String TIME_ZONE_UTC = "UTC";
+
+  /**
+   * The date format string that will be used to construct and parse dates
+   * represented using generalized time with a two-digit year. It is assumed
+   * that the provided date formatter will be set to UTC.
+   */
+  public static final String DATE_FORMAT_UTC_TIME = "yyMMddHHmmss'Z'";
+
+
+
+  // Prevent instantiation.
+  private SchemaConstants()
+  {
+    // Nothing to do.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaElement.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaElement.java
new file mode 100644
index 0000000..f428fae
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaElement.java
@@ -0,0 +1,189 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * An abstract base class for LDAP schema definitions which contain an
+ * description, and an optional set of extra properties.
+ * <p>
+ * This class defines common properties and behaviour of the various types of
+ * schema definitions (e.g. object class definitions, and attribute type
+ * definitions).
+ */
+abstract class SchemaElement
+{
+  // The description for this definition.
+  final String description;
+
+  // The set of additional name-value pairs.
+  final Map<String, List<String>> extraProperties;
+
+
+
+  SchemaElement(final String description,
+      final Map<String, List<String>> extraProperties)
+  {
+    Validator.ensureNotNull(description, extraProperties);
+    this.description = description;
+
+    // Assumes caller has made the map unmodifiable.
+    this.extraProperties = extraProperties;
+  }
+
+
+
+  /**
+   * Returns the description of this schema definition.
+   *
+   * @return The description of this schema definition.
+   */
+  public final String getDescription()
+  {
+
+    return description;
+  }
+
+
+
+  /**
+   * Returns an unmodifiable list containing the values of the named "extra"
+   * property for this schema definition.
+   *
+   * @param name
+   *          The name of the "extra" property whose values are to be returned.
+   * @return Returns an unmodifiable list containing the values of the named
+   *         "extra" property for this schema definition, which may be empty if
+   *         no such property is defined.
+   */
+  public final List<String> getExtraProperty(final String name)
+  {
+
+    final List<String> values = extraProperties.get(name);
+    return values != null ? values : Collections.<String> emptyList();
+  }
+
+
+
+  /**
+   * Returns an unmodifiable set containing the names of the "extra" properties
+   * associated with this schema definition.
+   *
+   * @return Returns an unmodifiable set containing the names of the "extra"
+   *         properties associated with this schema definition.
+   */
+  public final Set<String> getExtraPropertyNames()
+  {
+
+    return extraProperties.keySet();
+  }
+
+
+
+  /**
+   * Builds a string representation of this schema definition in the form
+   * specified in RFC 2252.
+   *
+   * @return The string representation of this schema definition in the form
+   *         specified in RFC 2252.
+   */
+  final String buildDefinition()
+  {
+    final StringBuilder buffer = new StringBuilder();
+
+    buffer.append("( ");
+
+    toStringContent(buffer);
+
+    if (!extraProperties.isEmpty())
+    {
+      for (final Map.Entry<String, List<String>> e : extraProperties.entrySet())
+      {
+
+        final String property = e.getKey();
+
+        final List<String> valueList = e.getValue();
+
+        buffer.append(" ");
+        buffer.append(property);
+
+        if (valueList.size() == 1)
+        {
+          buffer.append(" '");
+          buffer.append(valueList.get(0));
+          buffer.append("'");
+        }
+        else
+        {
+          buffer.append(" ( ");
+
+          for (final String value : valueList)
+          {
+            buffer.append("'");
+            buffer.append(value);
+            buffer.append("' ");
+          }
+
+          buffer.append(")");
+        }
+      }
+    }
+
+    buffer.append(" )");
+
+    return buffer.toString();
+  }
+
+
+
+  /**
+   * Appends a string representation of this schema definition's non-generic
+   * properties to the provided buffer.
+   *
+   * @param buffer
+   *          The buffer to which the information should be appended.
+   */
+  abstract void toStringContent(StringBuilder buffer);
+
+
+
+  abstract void validate(List<LocalizableMessage> warnings, Schema schema)
+      throws SchemaException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaException.java
new file mode 100644
index 0000000..d3a7635
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaException.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.LocalizableException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * Thrown when a schema could not be decoded or validated.
+ */
+@SuppressWarnings("serial")
+final class SchemaException extends Exception implements LocalizableException
+{
+  // The I18N message associated with this exception.
+  private final LocalizableMessage message;
+
+
+
+  /**
+   * Creates a new schema exception with the provided message.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   */
+  public SchemaException(final LocalizableMessage message)
+  {
+    super(String.valueOf(message));
+    this.message = message;
+  }
+
+
+
+  /**
+   * Creates a new schema exception with the provided message and cause.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   * @param cause
+   *          The cause which may be later retrieved by the {@link #getCause}
+   *          method. A {@code null} value is permitted, and indicates that the
+   *          cause is nonexistent or unknown.
+   */
+  public SchemaException(final LocalizableMessage message, final Throwable cause)
+  {
+    super(String.valueOf(message), cause);
+    this.message = message;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public LocalizableMessage getMessageObject()
+  {
+    return this.message;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaUtils.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaUtils.java
new file mode 100644
index 0000000..3730e62
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SchemaUtils.java
@@ -0,0 +1,898 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static com.sun.opends.sdk.util.StaticUtils.isAlpha;
+import static com.sun.opends.sdk.util.StaticUtils.isDigit;
+
+import java.util.*;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * Schema utility methods.
+ */
+final class SchemaUtils
+{
+  /**
+   * Reads the value for an "extra" parameter. It will handle a single unquoted
+   * word (which is technically illegal, but we'll allow it), a single quoted
+   * string, or an open parenthesis followed by a space-delimited set of quoted
+   * strings or unquoted words followed by a close parenthesis.
+   *
+   * @param reader
+   *          The string representation of the definition.
+   * @return The "extra" parameter value that was read.
+   * @throws DecodeException
+   *           If a problem occurs while attempting to read the value.
+   */
+  static List<String> readExtensions(final SubstringReader reader)
+      throws DecodeException
+  {
+    int length = 0;
+    List<String> values;
+
+    // Skip over any leading spaces.
+    reader.skipWhitespaces();
+    reader.mark();
+
+    try
+    {
+      // Look at the next character. If it is a quote, then parse until
+      // the next quote and end. If it is an open parenthesis, then
+      // parse individual values until the close parenthesis and end.
+      // Otherwise, parse until the next space and end.
+      char c = reader.read();
+      if (c == '\'')
+      {
+        reader.mark();
+        // Parse until the closing quote.
+        while (reader.read() != '\'')
+        {
+          length++;
+        }
+
+        reader.reset();
+        values = Collections.singletonList(reader.read(length));
+        reader.read();
+      }
+      else if (c == '(')
+      {
+        // Skip over any leading spaces;
+        reader.skipWhitespaces();
+        reader.mark();
+
+        c = reader.read();
+        if (c == ')')
+        {
+          values = Collections.emptyList();
+        }
+        else
+        {
+          values = new ArrayList<String>();
+          do
+          {
+            reader.reset();
+            values.add(readQuotedString(reader));
+            reader.skipWhitespaces();
+            reader.mark();
+          }
+          while (reader.read() != ')');
+          values = Collections.unmodifiableList(values);
+        }
+      }
+      else
+      {
+        // Parse until the next space.
+        do
+        {
+          length++;
+        }
+        while (reader.read() != ' ');
+
+        reader.reset();
+        values = Collections.singletonList(reader.read(length));
+      }
+
+      return values;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  static List<String> readNameDescriptors(final SubstringReader reader)
+      throws DecodeException
+  {
+    int length = 0;
+    List<String> values;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+
+    try
+    {
+      char c = reader.read();
+      if (c == '\'')
+      {
+        reader.mark();
+        // Parse until the closing quote.
+        while (reader.read() != '\'')
+        {
+          length++;
+        }
+
+        reader.reset();
+        values = Collections.singletonList(reader.read(length));
+        reader.read();
+      }
+      else if (c == '(')
+      {
+        // Skip over any leading spaces;
+        reader.skipWhitespaces();
+        reader.mark();
+
+        c = reader.read();
+        if (c == ')')
+        {
+          values = Collections.emptyList();
+        }
+        else
+        {
+          values = new LinkedList<String>();
+          do
+          {
+            reader.reset();
+            values.add(readQuotedDescriptor(reader));
+            reader.skipWhitespaces();
+            reader.mark();
+          }
+          while (reader.read() != ')');
+          values = Collections.unmodifiableList(values);
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+            .get(String.valueOf(c), reader.pos() - 1);
+        throw DecodeException.error(message);
+      }
+
+      return values;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  /**
+   * Reads the attribute description or numeric OID, skipping over any leading
+   * or trailing spaces.
+   *
+   * @param reader
+   *          The string representation of the definition.
+   * @return The attribute description or numeric OID read from the definition.
+   * @throws DecodeException
+   *           If a problem is encountered while reading the name or OID.
+   */
+  static String readOID(final SubstringReader reader) throws DecodeException
+  {
+    int length = 0;
+    boolean enclosingQuote = false;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+    reader.mark();
+
+    if (reader.remaining() > 0)
+    {
+      // The next character must be either numeric (for an OID) or
+      // alphabetic (for an attribute description).
+      if (reader.read() == '\'')
+      {
+        enclosingQuote = true;
+        reader.mark();
+      }
+      else
+      {
+        reader.reset();
+      }
+    }
+
+    if (reader.remaining() > 0)
+    {
+      char c = reader.read();
+      length++;
+
+      if (isDigit(c))
+      {
+        // This must be a numeric OID. In that case, we will accept
+        // only digits and periods, but not consecutive periods.
+        boolean lastWasPeriod = false;
+
+        while (reader.remaining() > 0 && (c = reader.read()) != ' ' && c != ')'
+            && !(c == '\'' && enclosingQuote))
+        {
+          if (c == '.')
+          {
+            if (lastWasPeriod)
+            {
+              final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS
+                  .get(reader.getString(), reader.pos() - 1);
+              throw DecodeException.error(message);
+            }
+            else
+            {
+              lastWasPeriod = true;
+            }
+          }
+          else if (!isDigit(c))
+          {
+            // This must be an illegal character.
+            // This must have been an illegal character.
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER
+                .get(reader.getString(), reader.pos() - 1);
+            throw DecodeException.error(message);
+          }
+          else
+          {
+            lastWasPeriod = false;
+          }
+
+          length++;
+        }
+
+        if (lastWasPeriod)
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD
+              .get(reader.getString());
+          throw DecodeException.error(message);
+        }
+      }
+      else if (isAlpha(c))
+      {
+        // This must be an attribute description. In this case, we will
+        // only accept alphabetic characters, numeric digits, and the
+        // hyphen.
+        while (reader.remaining() > 0 && (c = reader.read()) != ' ' && c != ')'
+            && !(c == '\'' && enclosingQuote))
+        {
+          if (length == 0 && !isAlpha(c))
+          {
+            // This is an illegal character.
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+                .get(String.valueOf(c), reader.pos() - 1);
+            throw DecodeException.error(message);
+          }
+
+          if (!isAlpha(c) && !isDigit(c) && c != '-' && c != '.' && c != '_')
+          {
+            // This is an illegal character.
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+                .get(String.valueOf(c), reader.pos() - 1);
+            throw DecodeException.error(message);
+          }
+
+          length++;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+            .get(String.valueOf(c), reader.pos() - 1);
+        throw DecodeException.error(message);
+      }
+
+      if (enclosingQuote && c != '\'')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_EXPECTED_QUOTE_AT_POS
+            .get(reader.pos() - 1, String.valueOf(c));
+        throw DecodeException.error(message);
+      }
+    }
+
+    if (length == 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_NO_VALUE.get();
+      throw DecodeException.error(message);
+    }
+
+    reader.reset();
+    final String oid = reader.read(length);
+    if (enclosingQuote)
+    {
+      reader.read();
+    }
+
+    return oid;
+  }
+
+
+
+  /**
+   * Reads the next OID from the definition, skipping over any leading spaces.
+   * The OID may be followed by a integer length in brackets.
+   *
+   * @param reader
+   *          The string representation of the definition.
+   * @return The OID read from the definition.
+   * @throws DecodeException
+   *           If a problem is encountered while reading the token name.
+   */
+  static String readOIDLen(final SubstringReader reader) throws DecodeException
+  {
+    int length = 1;
+    boolean enclosingQuote = false;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+    reader.mark();
+
+    try
+    {
+      // The next character must be either numeric (for an OID) or
+      // alphabetic (for an attribute description).
+      char c = reader.read();
+      if (c == '\'')
+      {
+        enclosingQuote = true;
+        reader.mark();
+        c = reader.read();
+      }
+      if (isDigit(c))
+      {
+        boolean lastWasPeriod = false;
+        while ((c = reader.read()) != ' ' && c != '{'
+            && !(c == '\'' && enclosingQuote))
+        {
+          if (c == '.')
+          {
+            if (lastWasPeriod)
+            {
+              final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS
+                  .get(reader.getString(), reader.pos() - 1);
+              throw DecodeException.error(message);
+            }
+            else
+            {
+              lastWasPeriod = true;
+            }
+          }
+          else if (!isDigit(c))
+          {
+            // Technically, this must be an illegal character. However,
+            // it is possible that someone just got sloppy and did not
+            // include a space between the name/OID and a closing
+            // parenthesis. In that case, we'll assume it's the end of
+            // the value.
+            if (c == ')')
+            {
+              break;
+            }
+
+            // This must have been an illegal character.
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER
+                .get(reader.getString(), reader.pos() - 1);
+            throw DecodeException.error(message);
+          }
+          else
+          {
+            lastWasPeriod = false;
+          }
+          length++;
+        }
+
+        if (length == 0)
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_NO_VALUE.get();
+          throw DecodeException.error(message);
+        }
+      }
+
+      else if (isAlpha(c))
+      {
+        // This must be an attribute description. In this case, we will
+        // only accept alphabetic characters, numeric digits, and the
+        // hyphen.
+        while ((c = reader.read()) != ' ' && c != ')' && c != '{'
+            && !(c == '\'' && enclosingQuote))
+        {
+          if (length == 0 && !isAlpha(c))
+          {
+            // This is an illegal character.
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+                .get(String.valueOf(c), reader.pos() - 1);
+            throw DecodeException.error(message);
+          }
+
+          if (!isAlpha(c) && !isDigit(c) && c != '-' && c != '.' && c != '_')
+          {
+            // This is an illegal character.
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+                .get(String.valueOf(c), reader.pos() - 1);
+            throw DecodeException.error(message);
+          }
+
+          length++;
+        }
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+            .get(String.valueOf(c), reader.pos() - 1);
+        throw DecodeException.error(message);
+      }
+
+      reader.reset();
+
+      // Return the position of the first non-space character after the
+      // token.
+      final String oid = reader.read(length);
+
+      reader.mark();
+      if ((c = reader.read()) == '{')
+      {
+        reader.mark();
+        // The only thing we'll allow here will be numeric digits and
+        // the closing curly brace.
+        while ((c = reader.read()) != '}')
+        {
+          if (!isDigit(c))
+          {
+            final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER
+                .get(reader.getString(), reader.pos() - 1);
+            throw DecodeException.error(message);
+          }
+        }
+      }
+      else if (c == '\'')
+      {
+        reader.mark();
+      }
+      else
+      {
+        reader.reset();
+      }
+
+      return oid;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  static Set<String> readOIDs(final SubstringReader reader)
+      throws DecodeException
+  {
+    Set<String> values;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+    reader.mark();
+
+    try
+    {
+      final char c = reader.read();
+      if (c == '(')
+      {
+        values = new LinkedHashSet<String>();
+        do
+        {
+          values.add(readOID(reader));
+
+          // Skip over any trailing spaces;
+          reader.skipWhitespaces();
+        }
+        while (reader.read() != ')');
+        values = Collections.unmodifiableSet(values);
+      }
+      else
+      {
+        reader.reset();
+        values = Collections.singleton(readOID(reader));
+      }
+
+      return values;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  /**
+   * Reads the value of a string enclosed in single quotes, skipping over the
+   * quotes and any leading spaces.
+   *
+   * @param reader
+   *          The string representation of the definition.
+   * @return The string value read from the definition.
+   * @throws DecodeException
+   *           If a problem is encountered while reading the quoted string.
+   */
+  static String readQuotedString(final SubstringReader reader)
+      throws DecodeException
+  {
+    int length = 0;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+
+    try
+    {
+      // The next character must be a single quote.
+      final char c = reader.read();
+      if (c != '\'')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_EXPECTED_QUOTE_AT_POS
+            .get(reader.pos() - 1, String.valueOf(c));
+        throw DecodeException.error(message);
+      }
+
+      // Read until we find the closing quote.
+      reader.mark();
+      while (reader.read() != '\'')
+      {
+        length++;
+      }
+
+      reader.reset();
+
+      final String str = reader.read(length);
+      reader.read();
+      return str;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  /**
+   * Reads the next ruleid from the definition, skipping over any leading
+   * spaces.
+   *
+   * @param reader
+   *          The string representation of the definition.
+   * @return The ruleid read from the definition.
+   * @throws DecodeException
+   *           If a problem is encountered while reading the token name.
+   */
+  static Integer readRuleID(final SubstringReader reader)
+      throws DecodeException
+  {
+    // This must be a ruleid. In that case, we will accept
+    // only digits.
+    int length = 0;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+    reader.mark();
+
+    try
+    {
+      while (reader.read() != ' ')
+      {
+        length++;
+      }
+
+      if (length == 0)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_RULE_ID_NO_VALUE
+            .get();
+        throw DecodeException.error(message);
+      }
+
+      reader.reset();
+      final String ruleID = reader.read(length);
+
+      try
+      {
+        return Integer.valueOf(ruleID);
+      }
+      catch (final NumberFormatException e)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_RULE_ID_INVALID
+            .get(ruleID);
+        throw DecodeException.error(message);
+      }
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  static Set<Integer> readRuleIDs(final SubstringReader reader)
+      throws DecodeException
+  {
+    Set<Integer> values;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+    reader.mark();
+
+    try
+    {
+      final char c = reader.read();
+      if (c == '(')
+      {
+        values = new LinkedHashSet<Integer>();
+        do
+        {
+          values.add(readRuleID(reader));
+
+          // Skip over any trailing spaces;
+          reader.skipWhitespaces();
+        }
+        while (reader.read() != ')');
+        values = Collections.unmodifiableSet(values);
+      }
+      else
+      {
+        reader.reset();
+        values = Collections.singleton(readRuleID(reader));
+      }
+
+      return values;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  /**
+   * Reads the next token name from the definition, skipping over any leading or
+   * trailing spaces or <code>null</code> if there are no more tokens to read.
+   *
+   * @param reader
+   *          The string representation of the definition.
+   * @return The token name read from the definition or <code>null</code> .
+   * @throws DecodeException
+   *           If a problem is encountered while reading the token name.
+   */
+  static String readTokenName(final SubstringReader reader)
+      throws DecodeException
+  {
+    String token = null;
+    int length = 0;
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+    reader.mark();
+
+    try
+    {
+      // Read until we find the next space.
+      char c;
+      while ((c = reader.read()) != ' ' && c != ')')
+      {
+        length++;
+      }
+
+      if (length > 0)
+      {
+        reader.reset();
+        token = reader.read(length);
+      }
+
+      // Skip over any trailing spaces after the value.
+      reader.skipWhitespaces();
+
+      if (token == null && reader.remaining() > 0)
+      {
+        reader.reset();
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UNEXPECTED_CLOSE_PARENTHESIS
+            .get(length);
+        throw DecodeException.error(message);
+      }
+
+      return token;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  /**
+   * Returns an unmodifiable copy of the provided schema element extra
+   * properties.
+   *
+   * @param extraProperties
+   *          The schema element extra properties.
+   * @return An unmodifiable copy of the provided schema element extra
+   *         properties.
+   */
+  static Map<String, List<String>> unmodifiableCopyOfExtraProperties(
+      final Map<String, List<String>> extraProperties)
+  {
+    if (extraProperties == null || extraProperties.isEmpty())
+    {
+      return Collections.emptyMap();
+    }
+    else
+    {
+      final Map<String, List<String>> tmp = new LinkedHashMap<String, List<String>>(
+          extraProperties.size());
+      for (final Map.Entry<String, List<String>> e : extraProperties.entrySet())
+      {
+        tmp.put(e.getKey(), unmodifiableCopyOfList(e.getValue()));
+      }
+      return Collections.unmodifiableMap(tmp);
+    }
+  }
+
+
+
+  static <E> List<E> unmodifiableCopyOfList(final List<E> l)
+  {
+    if (l == null || l.isEmpty())
+    {
+      return Collections.emptyList();
+    }
+    else if (l.size() == 1)
+    {
+      return Collections.singletonList(l.get(0));
+    }
+    else
+    {
+      final List<E> copy = new LinkedList<E>(l);
+      return Collections.unmodifiableList(copy);
+    }
+  }
+
+
+
+  static <E> Set<E> unmodifiableCopyOfSet(final Set<E> s)
+  {
+    if (s == null || s.isEmpty())
+    {
+      return Collections.emptySet();
+    }
+    else if (s.size() == 1)
+    {
+      return Collections.singleton(s.iterator().next());
+    }
+    else
+    {
+      final Set<E> copy = new LinkedHashSet<E>(s);
+      return Collections.unmodifiableSet(copy);
+    }
+  }
+
+
+
+  /**
+   * Reads the value of a string enclosed in single quotes, skipping over the
+   * quotes and any leading spaces.
+   *
+   * @param reader
+   *          The string representation of the definition.
+   * @return The string value read from the definition.
+   * @throws DecodeException
+   *           If a problem is encountered while reading the quoted string.
+   */
+  private static String readQuotedDescriptor(final SubstringReader reader)
+      throws DecodeException
+  {
+    int length = 0;
+
+    // Skip over any spaces at the beginning of the value.
+    reader.skipWhitespaces();
+
+    try
+    {
+      // The next character must be a single quote.
+      char c = reader.read();
+      if (c != '\'')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_EXPECTED_QUOTE_AT_POS
+            .get(reader.pos() - 1, String.valueOf(c));
+        throw DecodeException.error(message);
+      }
+
+      // Read until we find the closing quote.
+      reader.mark();
+      while ((c = reader.read()) != '\'')
+      {
+        if (length == 0 && !isAlpha(c))
+        {
+          // This is an illegal character.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+              .get(String.valueOf(c), reader.pos() - 1);
+          throw DecodeException.error(message);
+        }
+
+        if (!isAlpha(c) && !isDigit(c) && c != '-' && c != '_' && c != '.')
+        {
+          // This is an illegal character.
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
+              .get(String.valueOf(c), reader.pos() - 1);
+          throw DecodeException.error(message);
+        }
+
+        length++;
+      }
+
+      reader.reset();
+
+      final String descr = reader.read(length);
+      reader.read();
+      return descr;
+    }
+    catch (final StringIndexOutOfBoundsException e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE.get();
+      throw DecodeException.error(message);
+    }
+  }
+
+
+
+  // Prevent instantiation.
+  private SchemaUtils()
+  {
+    // Nothing to do.
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SubstringAssertionSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SubstringAssertionSyntaxImpl.java
new file mode 100644
index 0000000..fb58f58
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SubstringAssertionSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_SUBSTRING_ASSERTION_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.messages.Messages;
+
+
+
+/**
+ * This class defines the substring assertion attribute syntax, which contains
+ * one or more substring components, as used in a substring search filter. For
+ * the purposes of matching, it will be treated like a Directory String syntax
+ * except that approximate matching will not be allowed.
+ */
+final class SubstringAssertionSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_SUBSTRING_ASSERTION_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Get the string representation of the value and check its length.
+    // A zero-length value is acceptable. A one-length value is
+    // acceptable as long as it is not an asterisk. For all other
+    // lengths, just ensure that there are no consecutive wildcards.
+    final String valueString = value.toString();
+    final int valueLength = valueString.length();
+    if (valueLength == 0)
+    {
+      return true;
+    }
+    else if (valueLength == 1)
+    {
+      if (valueString.charAt(0) == '*')
+      {
+        invalidReason.append(Messages.WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD
+            .get());
+
+        return false;
+      }
+      else
+      {
+        return true;
+      }
+    }
+    else
+    {
+      for (int i = 1; i < valueLength; i++)
+      {
+        if (valueString.charAt(i) == '*' && valueString.charAt(i - 1) == '*')
+        {
+          invalidReason
+              .append(Messages.WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS
+                  .get(valueString, i));
+          return false;
+        }
+      }
+
+      return true;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SupportedAlgorithmSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SupportedAlgorithmSyntaxImpl.java
new file mode 100644
index 0000000..f7ab726
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SupportedAlgorithmSyntaxImpl.java
@@ -0,0 +1,108 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_OCTET_STRING_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_SUPPORTED_ALGORITHM_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the supported algorithm attribute syntax. This should
+ * be restricted to holding only X.509 supported algorithms, but we will accept
+ * any set of bytes. It will be treated much like the octet string attribute
+ * syntax.
+ */
+final class SupportedAlgorithmSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_OCTET_STRING_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_SUPPORTED_ALGORITHM_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_OCTET_STRING_OID;
+  }
+
+
+
+  @Override
+  public boolean isBEREncodingRequired()
+  {
+    return true;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // All values will be acceptable for the supported algorithm syntax.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Syntax.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Syntax.java
new file mode 100644
index 0000000..ae6ec48
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/Syntax.java
@@ -0,0 +1,430 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.Validator;
+
+
+
+/**
+ * This class defines a data structure for storing and interacting with an LDAP
+ * syntaxes, which constrain the structure of attribute values stored in an LDAP
+ * directory, and determine the representation of attribute and assertion values
+ * transferred in the LDAP protocol.
+ * <p>
+ * Syntax implementations must extend the {@link SyntaxImpl} interface so they
+ * can be used by OpenDS to validate attribute values.
+ * <p>
+ * Where ordered sets of names, or extra properties are provided, the ordering
+ * will be preserved when the associated fields are accessed via their getters
+ * or via the {@link #toString()} methods.
+ */
+public final class Syntax extends SchemaElement
+{
+  private final String oid;
+  private final String definition;
+  private MatchingRule equalityMatchingRule;
+  private MatchingRule orderingMatchingRule;
+  private MatchingRule substringMatchingRule;
+  private MatchingRule approximateMatchingRule;
+  private Schema schema;
+  private SyntaxImpl impl;
+
+
+
+  Syntax(final String oid)
+  {
+    super("", Collections.singletonMap("X-SUBST", Collections
+        .singletonList(Schema.getDefaultSyntax().getOID())));
+
+    Validator.ensureNotNull(oid);
+    this.oid = oid;
+    this.definition = buildDefinition();
+    this.impl = Schema.getDefaultSyntax().impl;
+  }
+
+
+
+  Syntax(final String oid, final String description,
+      final Map<String, List<String>> extraProperties, final String definition,
+      final SyntaxImpl implementation)
+  {
+    super(description, extraProperties);
+
+    Validator.ensureNotNull(oid);
+    this.oid = oid;
+
+    if (definition != null)
+    {
+      this.definition = definition;
+    }
+    else
+    {
+      this.definition = buildDefinition();
+    }
+    this.impl = implementation;
+  }
+
+
+
+  /**
+   * Retrieves the default approximate matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default approximate matching rule that will be used for
+   *         attributes with this syntax, or {@code null} if approximate matches
+   *         will not be allowed for this type by default.
+   */
+  public MatchingRule getApproximateMatchingRule()
+  {
+    return approximateMatchingRule;
+  }
+
+
+
+  /**
+   * Retrieves the default equality matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default equality matching rule that will be used for attributes
+   *         with this syntax, or {@code null} if equality matches will not be
+   *         allowed for this type by default.
+   */
+  public MatchingRule getEqualityMatchingRule()
+  {
+    return equalityMatchingRule;
+  }
+
+
+
+  /**
+   * Retrieves the OID for this attribute syntax.
+   *
+   * @return The OID for this attribute syntax.
+   */
+  public String getOID()
+  {
+    return oid;
+  }
+
+
+
+  /**
+   * Retrieves the default ordering matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default ordering matching rule that will be used for attributes
+   *         with this syntax, or {@code null} if ordering matches will not be
+   *         allowed for this type by default.
+   */
+  public MatchingRule getOrderingMatchingRule()
+  {
+    return orderingMatchingRule;
+  }
+
+
+
+  /**
+   * Retrieves the default substring matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default substring matching rule that will be used for
+   *         attributes with this syntax, or {@code null} if substring matches
+   *         will not be allowed for this type by default.
+   */
+  public MatchingRule getSubstringMatchingRule()
+  {
+    return substringMatchingRule;
+  }
+
+
+
+  /**
+   * Retrieves the hash code for this schema element. It will be calculated as
+   * the sum of the characters in the OID.
+   *
+   * @return The hash code for this attribute syntax.
+   */
+  @Override
+  public int hashCode()
+  {
+    return getOID().hashCode();
+  }
+
+
+
+  /**
+   * Indicates whether this attribute syntax requires that values must be
+   * encoded using the Basic Encoding Rules (BER) used by X.500 directories and
+   * always include the {@code binary} attribute description option.
+   *
+   * @return {@code true} this attribute syntax requires that values must be BER
+   *         encoded and always include the {@code binary} attribute description
+   *         option, or {@code false} if not.
+   * @see <a href="http://tools.ietf.org/html/rfc4522">RFC 4522 - Lightweight
+   *      Directory Access Protocol (LDAP): The Binary Encoding Option </a>
+   */
+  public boolean isBEREncodingRequired()
+  {
+    return impl.isBEREncodingRequired();
+  }
+
+
+
+  /**
+   * Indicates whether this attribute syntax would likely be a human readable
+   * string.
+   *
+   * @return {@code true} if this attribute syntax would likely be a human
+   *         readable string or {@code false} if not.
+   */
+  public boolean isHumanReadable()
+  {
+    return impl.isHumanReadable();
+  }
+
+
+
+  /**
+   * Retrieves a string representation of this attribute syntax in the format
+   * defined in RFC 2252.
+   *
+   * @return A string representation of this attribute syntax in the format
+   *         defined in RFC 2252.
+   */
+  @Override
+  public String toString()
+  {
+    return definition;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return {@code true} if the provided value is acceptable for use with this
+   *         syntax, or {@code false} if not.
+   */
+  public boolean valueIsAcceptable(final ByteSequence value,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    return impl.valueIsAcceptable(schema, value, invalidReason);
+  }
+
+
+
+  Syntax duplicate()
+  {
+    return new Syntax(oid, description, extraProperties, definition, impl);
+  }
+
+
+
+  @Override
+  void toStringContent(final StringBuilder buffer)
+  {
+    buffer.append(oid);
+
+    if (description != null && description.length() > 0)
+    {
+      buffer.append(" DESC '");
+      buffer.append(description);
+      buffer.append("'");
+    }
+  }
+
+
+
+  @Override
+  void validate(final List<LocalizableMessage> warnings, final Schema schema)
+      throws SchemaException
+  {
+    this.schema = schema;
+    if (impl == null)
+    {
+      // See if we need to override the implementation of the syntax
+      for (final Map.Entry<String, List<String>> property : extraProperties
+          .entrySet())
+      {
+        // Enums are handled in the schema builder.
+        if (property.getKey().equalsIgnoreCase("x-subst"))
+        {
+          /**
+           * One unimplemented syntax can be substituted by another defined
+           * syntax. A substitution syntax is an LDAPSyntaxDescriptionSyntax
+           * with X-SUBST extension.
+           */
+          final Iterator<String> values = property.getValue().iterator();
+          if (values.hasNext())
+          {
+            final String value = values.next();
+            if (value.equals(oid))
+            {
+              final LocalizableMessage message = ERR_ATTR_SYNTAX_CYCLIC_SUB_SYNTAX
+                  .get(oid);
+              throw new SchemaException(message);
+            }
+            if (!schema.hasSyntax(value))
+            {
+              final LocalizableMessage message = ERR_ATTR_SYNTAX_UNKNOWN_SUB_SYNTAX
+                  .get(oid, value);
+              throw new SchemaException(message);
+            }
+            final Syntax subSyntax = schema.getSyntax(value);
+            if (subSyntax.impl == null)
+            {
+              // The substitution syntax was never validated.
+              subSyntax.validate(warnings, schema);
+            }
+            impl = subSyntax.impl;
+          }
+        }
+        else if (property.getKey().equalsIgnoreCase("x-pattern"))
+        {
+          final Iterator<String> values = property.getValue().iterator();
+          if (values.hasNext())
+          {
+            final String value = values.next();
+            try
+            {
+              final Pattern pattern = Pattern.compile(value);
+              impl = new RegexSyntaxImpl(pattern);
+            }
+            catch (final Exception e)
+            {
+              final LocalizableMessage message = WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_PATTERN
+                  .get(oid, value);
+              throw new SchemaException(message);
+            }
+          }
+        }
+      }
+
+      // Try to find an implementation in the core schema
+      if (impl == null && Schema.getDefaultSchema().hasSyntax(oid))
+      {
+        impl = Schema.getDefaultSchema().getSyntax(oid).impl;
+      }
+      if (impl == null && Schema.getCoreSchema().hasSyntax(oid))
+      {
+        impl = Schema.getCoreSchema().getSyntax(oid).impl;
+      }
+
+      if (impl == null)
+      {
+        impl = Schema.getDefaultSyntax().impl;
+        final LocalizableMessage message = WARN_ATTR_SYNTAX_NOT_IMPLEMENTED
+            .get(oid, Schema.getDefaultSyntax().getOID());
+        warnings.add(message);
+      }
+    }
+
+    // Get references to the default matching rules. It will be ok
+    // if we can't find some. Just warn.
+    if (impl.getEqualityMatchingRule() != null)
+    {
+      if (schema.hasMatchingRule(impl.getEqualityMatchingRule()))
+      {
+        equalityMatchingRule = schema.getMatchingRule(impl
+            .getEqualityMatchingRule());
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE
+            .get(impl.getEqualityMatchingRule(), impl.getName());
+        warnings.add(message);
+      }
+    }
+
+    if (impl.getOrderingMatchingRule() != null)
+    {
+      if (schema.hasMatchingRule(impl.getOrderingMatchingRule()))
+      {
+        orderingMatchingRule = schema.getMatchingRule(impl
+            .getOrderingMatchingRule());
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE
+            .get(impl.getOrderingMatchingRule(), impl.getName());
+        warnings.add(message);
+      }
+    }
+
+    if (impl.getSubstringMatchingRule() != null)
+    {
+      if (schema.hasMatchingRule(impl.getSubstringMatchingRule()))
+      {
+        substringMatchingRule = schema.getMatchingRule(impl
+            .getSubstringMatchingRule());
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE
+            .get(impl.getSubstringMatchingRule(), impl.getName());
+        warnings.add(message);
+      }
+    }
+
+    if (impl.getApproximateMatchingRule() != null)
+    {
+      if (schema.hasMatchingRule(impl.getApproximateMatchingRule()))
+      {
+        approximateMatchingRule = schema.getMatchingRule(impl
+            .getApproximateMatchingRule());
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE
+            .get(impl.getApproximateMatchingRule(), impl.getName());
+        warnings.add(message);
+      }
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SyntaxImpl.java
new file mode 100644
index 0000000..4997c32
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/SyntaxImpl.java
@@ -0,0 +1,142 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This interface defines the set of methods and structures that must be
+ * implemented to define a new attribute syntax.
+ */
+public interface SyntaxImpl
+{
+  /**
+   * Retrieves the default approximate matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default approximate matching rule that will be used for
+   *         attributes with this syntax, or {@code null} if approximate matches
+   *         will not be allowed for this type by default.
+   */
+  public String getApproximateMatchingRule();
+
+
+
+  /**
+   * Retrieves the default equality matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default equality matching rule that will be used for attributes
+   *         with this syntax, or {@code null} if equality matches will not be
+   *         allowed for this type by default.
+   */
+  public String getEqualityMatchingRule();
+
+
+
+  /**
+   * Retrieves the common name for this attribute syntax.
+   *
+   * @return The common name for this attribute syntax.
+   */
+  public String getName();
+
+
+
+  /**
+   * Retrieves the default ordering matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default ordering matching rule that will be used for attributes
+   *         with this syntax, or {@code null} if ordering matches will not be
+   *         allowed for this type by default.
+   */
+  public String getOrderingMatchingRule();
+
+
+
+  /**
+   * Retrieves the default substring matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default substring matching rule that will be used for
+   *         attributes with this syntax, or {@code null} if substring matches
+   *         will not be allowed for this type by default.
+   */
+  public String getSubstringMatchingRule();
+
+
+
+  /**
+   * Indicates whether this attribute syntax requires that values must be
+   * encoded using the Basic Encoding Rules (BER) used by X.500 directories and
+   * always include the {@code binary} attribute description option.
+   *
+   * @return {@code true} this attribute syntax requires that values must be BER
+   *         encoded and always include the {@code binary} attribute description
+   *         option, or {@code false} if not.
+   * @see <a href="http://tools.ietf.org/html/rfc4522">RFC 4522 - Lightweight
+   *      Directory Access Protocol (LDAP): The Binary Encoding Option </a>
+   */
+  public boolean isBEREncodingRequired();
+
+
+
+  /**
+   * Indicates whether this attribute syntax would likely be a human readable
+   * string.
+   *
+   * @return {@code true} if this attribute syntax would likely be a human
+   *         readable string or {@code false} if not.
+   */
+  boolean isHumanReadable();
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return {@code true} if the provided value is acceptable for use with this
+   *         syntax, or {@code false} if not.
+   */
+  boolean valueIsAcceptable(Schema schema, ByteSequence value,
+      LocalizableMessageBuilder invalidReason);
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..4365add
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberEqualityMatchingRuleImpl.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class implements the telephoneNumberMatch matching rule defined in X.520
+ * and referenced in RFC 2252. Note that although the specification calls for a
+ * very rigorous format, this is widely ignored so this matching will compare
+ * only numeric digits and strip out everything else.
+ */
+final class TelephoneNumberEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final String valueString = value.toString();
+    final int valueLength = valueString.length();
+    final StringBuilder buffer = new StringBuilder(valueLength);
+
+    // Iterate through the characters in the value and filter out
+    // everything that isn't a digit.
+    for (int i = 0; i < valueLength; i++)
+    {
+      final char c = valueString.charAt(i);
+      if (StaticUtils.isDigit(c))
+      {
+        buffer.append(c);
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSubstringMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSubstringMatchingRuleImpl.java
new file mode 100644
index 0000000..0894a95
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSubstringMatchingRuleImpl.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class implements the telephoneNumberSubstringsMatch matching rule
+ * defined in X.520 and referenced in RFC 2252. Note that although the
+ * specification calls for a very rigorous format, this is widely ignored so
+ * this matching will compare only numeric digits and strip out everything else.
+ */
+final class TelephoneNumberSubstringMatchingRuleImpl extends
+    AbstractSubstringMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    final String valueString = value.toString();
+    final int valueLength = valueString.length();
+    final StringBuilder buffer = new StringBuilder(valueLength);
+
+    // Iterate through the characters in the value and filter out
+    // everything that isn't a digit.
+    for (int i = 0; i < valueLength; i++)
+    {
+      final char c = valueString.charAt(i);
+      if (StaticUtils.isDigit(c))
+      {
+        buffer.append(c);
+      }
+    }
+
+    return ByteString.valueOf(buffer.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSyntaxImpl.java
new file mode 100644
index 0000000..9371051
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelephoneNumberSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEPHONE_EMPTY;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS;
+import static com.sun.opends.sdk.util.StaticUtils.isDigit;
+import static org.opends.sdk.schema.SchemaConstants.EMR_TELEPHONE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_TELEPHONE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_TELEPHONE_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the telephone number attribute syntax, which is defined
+ * in RFC 2252. Note that this can have two modes of operation, depending on its
+ * configuration. Most of the time, it will be very lenient when deciding what
+ * to accept, and will allow anything but only pay attention to the digits.
+ * However, it can also be configured in a "strict" mode, in which case it will
+ * only accept values in the E.123 international telephone number format.
+ */
+final class TelephoneNumberSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_TELEPHONE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_TELEPHONE_NAME;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_TELEPHONE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // No matter what, the value can't be empty or null.
+    String valueStr;
+    if (value == null || (valueStr = value.toString().trim()).length() == 0)
+    {
+      invalidReason.append(ERR_ATTR_SYNTAX_TELEPHONE_EMPTY.get());
+      return false;
+    }
+
+    final int length = valueStr.length();
+
+    if (schema.getSchemaCompatOptions().isTelephoneNumberSyntaxStrict())
+    {
+      // If the value does not start with a plus sign, then that's not
+      // acceptable.
+      if (valueStr.charAt(0) != '+')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS
+            .get(valueStr);
+        invalidReason.append(message);
+        return false;
+      }
+
+      // Iterate through the remaining characters in the value. There
+      // must be at least one digit, and it must contain only valid
+      // digits and separator characters.
+      boolean digitSeen = false;
+      for (int i = 1; i < length; i++)
+      {
+        final char c = valueStr.charAt(i);
+        if (isDigit(c))
+        {
+          digitSeen = true;
+        }
+        else if (!isSeparator(c))
+        {
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR
+              .get(valueStr, String.valueOf(c), i);
+          invalidReason.append(message);
+          return false;
+        }
+      }
+
+      if (!digitSeen)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS
+            .get(valueStr);
+        invalidReason.append(message);
+        return false;
+      }
+
+      // If we've gotten here, then we'll consider it acceptable.
+      return true;
+    }
+    else
+    {
+      // If we are not in strict mode, then all non-empty values
+      // containing at least one digit will be acceptable.
+      for (int i = 0; i < length; i++)
+      {
+        if (isDigit(valueStr.charAt(i)))
+        {
+          return true;
+        }
+      }
+
+      // If we made it here, then we didn't find any digits.
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS
+          .get(valueStr);
+      invalidReason.append(message);
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Indicates whether the provided character is a valid separator for telephone
+   * number components when operating in strict mode.
+   *
+   * @param c
+   *          The character for which to make the determination.
+   * @return <CODE>true</CODE> if the provided character is a valid separator,
+   *         or <CODE>false</CODE> if it is not.
+   */
+  private boolean isSeparator(final char c)
+  {
+    switch (c)
+    {
+    case ' ':
+    case '-':
+      return true;
+    default:
+      return false;
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TeletexTerminalIdentifierSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TeletexTerminalIdentifierSyntaxImpl.java
new file mode 100644
index 0000000..9256bd2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TeletexTerminalIdentifierSyntaxImpl.java
@@ -0,0 +1,268 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_TELETEX_TERM_ID_NAME;
+
+import java.util.HashSet;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the teletex terminal identifier attribute syntax, which
+ * contains a printable string (the terminal identifier) followed by zero or
+ * more parameters, which start with a dollar sign and are followed by a
+ * parameter name, a colon, and a value. The parameter value should consist of
+ * any string of bytes (the dollar sign and backslash must be escaped with a
+ * preceding backslash), and the parameter name must be one of the following
+ * strings:
+ * <UL>
+ * <LI>graphic</LI>
+ * <LI>control</LI>
+ * <LI>misc</LI>
+ * <LI>page</LI>
+ * <LI>private</LI>
+ * </UL>
+ */
+final class TeletexTerminalIdentifierSyntaxImpl extends AbstractSyntaxImpl
+{
+  /**
+   * The set of allowed fax parameter values, formatted entirely in lowercase
+   * characters.
+   */
+  private static final HashSet<String> ALLOWED_TTX_PARAMETERS = new HashSet<String>(
+      5);
+
+  static
+  {
+    ALLOWED_TTX_PARAMETERS.add("graphic");
+    ALLOWED_TTX_PARAMETERS.add("control");
+    ALLOWED_TTX_PARAMETERS.add("misc");
+    ALLOWED_TTX_PARAMETERS.add("page");
+    ALLOWED_TTX_PARAMETERS.add("private");
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_TELETEX_TERM_ID_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Get a lowercase string representation of the value and find its
+    // length.
+    final String valueString = value.toString();
+    final int valueLength = valueString.length();
+
+    // The value must contain at least one character.
+    if (valueLength == 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_EMPTY.get());
+      return false;
+    }
+
+    // The first character must be a printable string character.
+    char c = valueString.charAt(0);
+    if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE.get(
+          valueString, String.valueOf(c), 0));
+      return false;
+    }
+
+    // Continue reading until we find a dollar sign or the end of the
+    // string. Every intermediate character must be a printable string
+    // character.
+    int pos = 1;
+    for (; pos < valueLength; pos++)
+    {
+      c = valueString.charAt(pos);
+      if (c == '$')
+      {
+        pos++;
+        break;
+      }
+      else
+      {
+        if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE.get(
+              valueString, String.valueOf(c), pos));
+        }
+      }
+    }
+
+    if (pos >= valueLength)
+    {
+      // We're at the end of the value, so it must be valid unless the
+      // last character was a dollar sign.
+      if (c == '$')
+      {
+
+        invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR
+            .get(valueString));
+        return false;
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    // Continue reading until we find the end of the string. Each
+    // substring must be a valid teletex terminal identifier parameter
+    // followed by a colon and the value. Dollar signs must be escaped
+    int paramStartPos = pos;
+    boolean escaped = false;
+    while (pos < valueLength)
+    {
+      if (escaped)
+      {
+        pos++;
+        continue;
+      }
+
+      c = valueString.charAt(pos++);
+      if (c == '\\')
+      {
+        escaped = true;
+        continue;
+      }
+      else if (c == '$')
+      {
+        final String paramStr = valueString.substring(paramStartPos, pos);
+
+        final int colonPos = paramStr.indexOf(':');
+        if (colonPos < 0)
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON
+              .get(valueString));
+          return false;
+        }
+
+        final String paramName = paramStr.substring(0, colonPos);
+        if (!ALLOWED_TTX_PARAMETERS.contains(paramName))
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER.get(
+              valueString, paramName));
+          return false;
+        }
+
+        paramStartPos = pos;
+      }
+    }
+
+    // We must be at the end of the value. Read the last parameter and
+    // make sure it is valid.
+    final String paramStr = valueString.substring(paramStartPos);
+    final int colonPos = paramStr.indexOf(':');
+    if (colonPos < 0)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON
+          .get(valueString));
+      return false;
+    }
+
+    final String paramName = paramStr.substring(0, colonPos);
+    if (!ALLOWED_TTX_PARAMETERS.contains(paramName))
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER.get(
+          valueString, paramName));
+      return false;
+    }
+
+    // If we've gotten here, then the value must be valid.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelexNumberSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelexNumberSyntaxImpl.java
new file mode 100644
index 0000000..0806f62
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/TelexNumberSyntaxImpl.java
@@ -0,0 +1,226 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEX_TOO_SHORT;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_TELEX_TRUNCATED;
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.OMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_TELEX_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the telex number attribute syntax, which contains three
+ * printable strings separated by dollar sign characters. Equality, ordering,
+ * and substring matching will be allowed by default.
+ */
+final class TelexNumberSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_TELEX_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_CASE_IGNORE_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Get a string representation of the value and find its length.
+    final String valueString = value.toString();
+    final int valueLength = valueString.length();
+
+    if (valueLength < 5)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELEX_TOO_SHORT.get(valueString));
+      return false;
+    }
+
+    // The first character must be a printable string character.
+    char c = valueString.charAt(0);
+    if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE.get(valueString,
+          String.valueOf(c), 0));
+      return false;
+    }
+
+    // Continue reading until we find a dollar sign. Every intermediate
+    // character must be a printable string character.
+    int pos = 1;
+    for (; pos < valueLength; pos++)
+    {
+      c = valueString.charAt(pos);
+      if (c == '$')
+      {
+        pos++;
+        break;
+      }
+      else
+      {
+        if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR.get(
+              valueString, String.valueOf(c), pos));
+        }
+      }
+    }
+
+    if (pos >= valueLength)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELEX_TRUNCATED.get(valueString));
+      return false;
+    }
+
+    // The next character must be a printable string character.
+    c = valueString.charAt(pos++);
+    if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE.get(valueString,
+          String.valueOf(c), (pos - 1)));
+      return false;
+    }
+
+    // Continue reading until we find another dollar sign. Every
+    // intermediate character must be a printable string character.
+    for (; pos < valueLength; pos++)
+    {
+      c = valueString.charAt(pos);
+      if (c == '$')
+      {
+        pos++;
+        break;
+      }
+      else
+      {
+        if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+        {
+
+          invalidReason.append(ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR.get(
+              valueString, String.valueOf(c), pos));
+          return false;
+        }
+      }
+    }
+
+    if (pos >= valueLength)
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELEX_TRUNCATED.get(valueString));
+      return false;
+    }
+
+    // The next character must be a printable string character.
+    c = valueString.charAt(pos++);
+    if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+    {
+
+      invalidReason.append(ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE.get(valueString,
+          String.valueOf(c), (pos - 1)));
+      return false;
+    }
+
+    // Continue reading until the end of the value. Every intermediate
+    // character must be a printable string character.
+    for (; pos < valueLength; pos++)
+    {
+      c = valueString.charAt(pos);
+      if (!PrintableStringSyntaxImpl.isPrintableCharacter(c))
+      {
+
+        invalidReason.append(ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR.get(
+            valueString, String.valueOf(c), pos));
+        return false;
+      }
+    }
+
+    // If we've gotten here, then we're at the end of the value and it
+    // is acceptable.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UTCTimeSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UTCTimeSyntaxImpl.java
new file mode 100644
index 0000000..3f1e3a6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UTCTimeSyntaxImpl.java
@@ -0,0 +1,734 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.*;
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class implements the UTC time attribute syntax. This is very similar to
+ * the generalized time syntax (and actually has been deprecated in favor of
+ * that), but requires that the minute be provided and does not allow for
+ * sub-second times. All matching will be performed using the generalized time
+ * matching rules, and equality, ordering, and substring matching will be
+ * allowed.
+ */
+final class UTCTimeSyntaxImpl extends AbstractSyntaxImpl
+{
+
+  /**
+   * The lock that will be used to provide threadsafe access to the date
+   * formatter.
+   */
+  private final static Object DATE_FORMAT_LOCK;
+
+  /**
+   * The date formatter that will be used to convert dates into UTC time values.
+   * Note that all interaction with it must be synchronized.
+   */
+  private final static SimpleDateFormat DATE_FORMAT;
+
+  /*
+   * Create the date formatter that will be used to construct and parse
+   * normalized UTC time values.
+   */
+  static
+  {
+    DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_UTC_TIME);
+    DATE_FORMAT.setLenient(false);
+    DATE_FORMAT.setTimeZone(TimeZone.getTimeZone(TIME_ZONE_UTC));
+
+    DATE_FORMAT_LOCK = new Object();
+  }
+
+
+
+  /**
+   * Retrieves an string containing a UTC time representation of the provided
+   * date.
+   *
+   * @param d
+   *          The date for which to retrieve the UTC time value.
+   * @return The attribute value created from the date.
+   */
+  static String createUTCTimeValue(final Date d)
+  {
+    synchronized (DATE_FORMAT_LOCK)
+    {
+      return DATE_FORMAT.format(d);
+    }
+  }
+
+
+
+  /**
+   * Decodes the provided normalized value as a UTC time value and retrieves a
+   * Java <CODE>Date</CODE> object containing its representation.
+   *
+   * @param valueString
+   *          The normalized UTC time value to decode to a Java
+   *          <CODE>Date</CODE>.
+   * @return The Java <CODE>Date</CODE> created from the provided UTC time
+   *         value.
+   * @throws DecodeException
+   *           If the provided value cannot be parsed as a valid UTC time
+   *           string.
+   */
+  static Date decodeUTCTimeValue(final String valueString)
+      throws DecodeException
+  {
+    try
+    {
+      synchronized (DATE_FORMAT_LOCK)
+      {
+        return DATE_FORMAT.parse(valueString);
+      }
+    }
+    catch (final Exception e)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE
+          .get(valueString, String.valueOf(e));
+      final DecodeException de = DecodeException.error(message, e);
+      StaticUtils.DEBUG_LOG.throwing("UTCTimeSyntax", "decodeUTCTimeValue", de);
+      throw de;
+    }
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_GENERALIZED_TIME_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_UTC_TIME_NAME;
+  }
+
+
+
+  @Override
+  public String getOrderingMatchingRule()
+  {
+    return OMR_GENERALIZED_TIME_OID;
+  }
+
+
+
+  @Override
+  public String getSubstringMatchingRule()
+  {
+    return SMR_CASE_IGNORE_OID;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return false;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // Get the value as a string and verify that it is at least long
+    // enough for "YYYYMMDDhhmmZ", which is the shortest allowed value.
+    final String valueString = value.toString().toUpperCase();
+    final int length = valueString.length();
+    if (length < 11)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT
+          .get(valueString);
+      invalidReason.append(message);
+      return false;
+    }
+
+    // The first two characters are the year, and they must be numeric
+    // digits between 0 and 9.
+    for (int i = 0; i < 2; i++)
+    {
+      switch (valueString.charAt(i))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR
+            .get(valueString, String.valueOf(valueString.charAt(i)));
+        invalidReason.append(message);
+        return false;
+      }
+    }
+
+    // The next two characters are the month, and they must form the
+    // string representation of an integer between 01 and 12.
+    char m1 = valueString.charAt(2);
+    final char m2 = valueString.charAt(3);
+    switch (m1)
+    {
+    case '0':
+      // m2 must be a digit between 1 and 9.
+      switch (m2)
+      {
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH
+            .get(valueString, valueString.substring(2, 4));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    case '1':
+      // m2 must be a digit between 0 and 2.
+      switch (m2)
+      {
+      case '0':
+      case '1':
+      case '2':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH
+            .get(valueString, valueString.substring(2, 4));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    default:
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH
+          .get(valueString, valueString.substring(2, 4));
+      invalidReason.append(message);
+      return false;
+    }
+
+    // The next two characters should be the day of the month, and they
+    // must form the string representation of an integer between 01 and
+    // 31. This doesn't do any validation against the year or month, so
+    // it will allow dates like April 31, or February 29 in a non-leap
+    // year, but we'll let those slide.
+    final char d1 = valueString.charAt(4);
+    final char d2 = valueString.charAt(5);
+    switch (d1)
+    {
+    case '0':
+      // d2 must be a digit between 1 and 9.
+      switch (d2)
+      {
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY
+            .get(valueString, valueString.substring(4, 6));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    case '1':
+      // Treated the same as '2'.
+    case '2':
+      // d2 must be a digit between 0 and 9.
+      switch (d2)
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY
+            .get(valueString, valueString.substring(4, 6));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    case '3':
+      // d2 must be either 0 or 1.
+      switch (d2)
+      {
+      case '0':
+      case '1':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY
+            .get(valueString, valueString.substring(4, 6));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    default:
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY
+          .get(valueString, valueString.substring(4, 6));
+      invalidReason.append(message);
+      return false;
+    }
+
+    // The next two characters must be the hour, and they must form the
+    // string representation of an integer between 00 and 23.
+    final char h1 = valueString.charAt(6);
+    final char h2 = valueString.charAt(7);
+    switch (h1)
+    {
+    case '0':
+      // This is treated the same as '1'.
+    case '1':
+      switch (h2)
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR
+            .get(valueString, valueString.substring(6, 8));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    case '2':
+      // This must be a digit between 0 and 3.
+      switch (h2)
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR
+            .get(valueString, valueString.substring(6, 8));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    default:
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR
+          .get(valueString, valueString.substring(6, 8));
+      invalidReason.append(message);
+      return false;
+    }
+
+    // Next, there should be two digits comprising an integer between 00
+    // and 59 for the minute.
+    m1 = valueString.charAt(8);
+    switch (m1)
+    {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+      // There must be at least two more characters, and the next one
+      // must be a digit between 0 and 9.
+      if (length < 11)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(m1), 8);
+        invalidReason.append(message);
+        return false;
+      }
+
+      switch (valueString.charAt(9))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE
+            .get(valueString, valueString.substring(8, 10));
+        invalidReason.append(message);
+        return false;
+      }
+
+      break;
+
+    default:
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+          .get(valueString, String.valueOf(m1), 8);
+      invalidReason.append(message);
+      return false;
+    }
+
+    // Next, there should be either two digits comprising an integer
+    // between 00 and 60 (for the second, including a possible leap
+    // second), a letter 'Z' (for the UTC specifier), or a plus or minus
+    // sign followed by four digits (for the UTC offset).
+    final char s1 = valueString.charAt(10);
+    switch (s1)
+    {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+      // There must be at least two more characters, and the next one
+      // must be a digit between 0 and 9.
+      if (length < 13)
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 10);
+        invalidReason.append(message);
+        return false;
+      }
+
+      switch (valueString.charAt(11))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND
+            .get(valueString, valueString.substring(10, 12));
+        invalidReason.append(message);
+        return false;
+      }
+
+      break;
+    case '6':
+      // There must be at least two more characters and the next one
+      // must be a 0.
+      if (length < 13)
+      {
+
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 10);
+        invalidReason.append(message);
+        return false;
+      }
+
+      if (valueString.charAt(11) != '0')
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND
+            .get(valueString, valueString.substring(10, 12));
+        invalidReason.append(message);
+        return false;
+      }
+
+      break;
+    case 'Z':
+      // This is fine only if we are at the end of the value.
+      if (length == 11)
+      {
+        return true;
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 10);
+        invalidReason.append(message);
+        return false;
+      }
+
+    case '+':
+    case '-':
+      // These are fine only if there are exactly four more digits that
+      // specify a valid offset.
+      if (length == 15)
+      {
+        return hasValidOffset(valueString, 11, invalidReason);
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(s1), 10);
+        invalidReason.append(message);
+        return false;
+      }
+
+    default:
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+          .get(valueString, String.valueOf(s1), 10);
+      invalidReason.append(message);
+      return false;
+    }
+
+    // The last element should be either a letter 'Z' (for the UTC
+    // specifier), or a plus or minus sign followed by four digits (for
+    // the UTC offset).
+    switch (valueString.charAt(12))
+    {
+    case 'Z':
+      // This is fine only if we are at the end of the value.
+      if (length == 13)
+      {
+        return true;
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(valueString.charAt(12)), 12);
+        invalidReason.append(message);
+        return false;
+      }
+
+    case '+':
+    case '-':
+      // These are fine only if there are four or two more digits that
+      // specify a valid offset.
+      if (length == 17 || length == 15)
+      {
+        return hasValidOffset(valueString, 13, invalidReason);
+      }
+      else
+      {
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+            .get(valueString, String.valueOf(valueString.charAt(12)), 12);
+        invalidReason.append(message);
+        return false;
+      }
+
+    default:
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR
+          .get(valueString, String.valueOf(valueString.charAt(12)), 12);
+      invalidReason.append(message);
+      return false;
+    }
+  }
+
+
+
+  /**
+   * Indicates whether the provided string contains a valid set of two or four
+   * UTC offset digits. The provided string must have either two or four
+   * characters from the provided start position to the end of the value.
+   *
+   * @param value
+   *          The whole value, including the offset.
+   * @param startPos
+   *          The position of the first character that is contained in the
+   *          offset.
+   * @param invalidReason
+   *          The buffer to which the invalid reason may be appended if the
+   *          string does not contain a valid set of UTC offset digits.
+   * @return <CODE>true</CODE> if the provided offset string is valid, or
+   *         <CODE>false</CODE> if it is not.
+   */
+  private boolean hasValidOffset(final String value, final int startPos,
+      final LocalizableMessageBuilder invalidReason)
+  {
+    final int offsetLength = value.length() - startPos;
+    if (offsetLength < 2)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT
+          .get(value);
+      invalidReason.append(message);
+      return false;
+    }
+
+    // The first two characters must be an integer between 00 and 23.
+    switch (value.charAt(startPos))
+    {
+    case '0':
+    case '1':
+      switch (value.charAt(startPos + 1))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET
+            .get(value, value.substring(startPos, startPos + offsetLength));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    case '2':
+      switch (value.charAt(startPos + 1))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+        // These are all fine.
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET
+            .get(value, value.substring(startPos, startPos + offsetLength));
+        invalidReason.append(message);
+        return false;
+      }
+      break;
+    default:
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET
+          .get(value, value.substring(startPos, startPos + offsetLength));
+      invalidReason.append(message);
+      return false;
+    }
+
+    // If there are two more characters, then they must be an integer
+    // between 00 and 59.
+    if (offsetLength == 4)
+    {
+      switch (value.charAt(startPos + 2))
+      {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+        switch (value.charAt(startPos + 3))
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+          // These are all fine.
+          break;
+        default:
+          final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET
+              .get(value, value.substring(startPos, startPos + offsetLength));
+          invalidReason.append(message);
+          return false;
+        }
+        break;
+      default:
+        final LocalizableMessage message = ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET
+            .get(value, value.substring(startPos, startPos + offsetLength));
+        invalidReason.append(message);
+        return false;
+      }
+    }
+
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..b3e306c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDEqualityMatchingRuleImpl.java
@@ -0,0 +1,130 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class defines the uuidMatch matching rule defined in RFC 4530. It will
+ * be used as the default equality matching rule for the UUID syntax.
+ */
+final class UUIDEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    if (value.length() != 36)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH
+          .get(value.toString(), value.length());
+      throw DecodeException.error(message);
+    }
+
+    final StringBuilder builder = new StringBuilder(36);
+    char c;
+    for (int i = 0; i < 36; i++)
+    {
+      // The 9th, 14th, 19th, and 24th characters must be dashes. All
+      // others must be hex. Convert all uppercase hex characters to
+      // lowercase.
+      c = (char) value.byteAt(i);
+      switch (i)
+      {
+      case 8:
+      case 13:
+      case 18:
+      case 23:
+        if (c != '-')
+        {
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH
+              .get(value.toString(), i, String.valueOf(c));
+          throw DecodeException.error(message);
+        }
+        builder.append(c);
+        break;
+      default:
+        switch (c)
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case 'a':
+        case 'b':
+        case 'c':
+        case 'd':
+        case 'e':
+        case 'f':
+          // These are all fine.
+          builder.append(c);
+          break;
+        case 'A':
+          builder.append('a');
+          break;
+        case 'B':
+          builder.append('b');
+          break;
+        case 'C':
+          builder.append('c');
+          break;
+        case 'D':
+          builder.append('d');
+          break;
+        case 'E':
+          builder.append('e');
+          break;
+        case 'F':
+          builder.append('f');
+          break;
+        default:
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX
+              .get(value.toString(), i, String.valueOf(value.byteAt(i)));
+          throw DecodeException.error(message);
+        }
+      }
+    }
+
+    return ByteString.valueOf(builder.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDOrderingMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDOrderingMatchingRuleImpl.java
new file mode 100644
index 0000000..7452582
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDOrderingMatchingRuleImpl.java
@@ -0,0 +1,131 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+
+
+
+/**
+ * This class defines the uuidOrderingMatch matching rule defined in RFC 4530.
+ * This will be the default ordering matching rule for the UUID syntax.
+ */
+final class UUIDOrderingMatchingRuleImpl extends
+    AbstractOrderingMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    if (value.length() != 36)
+    {
+      final LocalizableMessage message = WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH
+          .get(value.toString(), value.length());
+      throw DecodeException.error(message);
+    }
+
+    final StringBuilder builder = new StringBuilder(36);
+    char c;
+    for (int i = 0; i < 36; i++)
+    {
+      // The 9th, 14th, 19th, and 24th characters must be dashes. All
+      // others must be hex. Convert all uppercase hex characters to
+      // lowercase.
+      c = (char) value.byteAt(i);
+      switch (i)
+      {
+      case 8:
+      case 13:
+      case 18:
+      case 23:
+        if (c != '-')
+        {
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH
+              .get(value.toString(), i, String.valueOf(c));
+          throw DecodeException.error(message);
+        }
+        builder.append(c);
+        break;
+      default:
+        switch (c)
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case 'a':
+        case 'b':
+        case 'c':
+        case 'd':
+        case 'e':
+        case 'f':
+          // These are all fine.
+          builder.append(c);
+          break;
+        case 'A':
+          builder.append('a');
+          break;
+        case 'B':
+          builder.append('b');
+          break;
+        case 'C':
+          builder.append('c');
+          break;
+        case 'D':
+          builder.append('d');
+          break;
+        case 'E':
+          builder.append('e');
+          break;
+        case 'F':
+          builder.append('f');
+          break;
+        default:
+          final LocalizableMessage message = WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX
+              .get(value.toString(), i, String.valueOf(value.byteAt(i)));
+          throw DecodeException.error(message);
+        }
+      }
+    }
+
+    return ByteString.valueOf(builder.toString());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDSyntaxImpl.java
new file mode 100644
index 0000000..0dc82a8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UUIDSyntaxImpl.java
@@ -0,0 +1,150 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX;
+import static com.sun.opends.sdk.messages.Messages.WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_UUID_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class implements the UUID syntax, which is defined in RFC 4530. Equality
+ * and ordering matching will be allowed by default.
+ */
+final class UUIDSyntaxImpl extends AbstractSyntaxImpl
+{
+  public String getName()
+  {
+    return SYNTAX_UUID_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an attribute
+   * with this syntax. If it is not, then the reason may be appended to the
+   * provided buffer.
+   *
+   * @param schema
+   *          The schema in which this syntax is defined.
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for use with
+   *         this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We will only accept values that look like valid UUIDs. This means
+    // that all values must be in the form
+    // HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where "H" represents a
+    // hexadecimal digit. First, make sure that the value is exactly 36
+    // bytes long.
+    final String valueString = value.toString();
+    if (valueString.length() != 36)
+    {
+
+      invalidReason.append(WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH.get(
+          valueString, valueString.length()));
+      return false;
+    }
+
+    // Next, iterate through each character. Make sure that the 9th,
+    // 14th, 19th, and 24th characters are dashes and the rest are hex
+    // digits.
+    for (int i = 0; i < 36; i++)
+    {
+      switch (i)
+      {
+      case 8:
+      case 13:
+      case 18:
+      case 23:
+        if (valueString.charAt(i) != '-')
+        {
+
+          invalidReason.append(WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH.get(
+              valueString, i, String.valueOf(valueString.charAt(i))));
+          return false;
+        }
+        break;
+      default:
+        switch (valueString.charAt(i))
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case 'a':
+        case 'b':
+        case 'c':
+        case 'd':
+        case 'e':
+        case 'f':
+        case 'A':
+        case 'B':
+        case 'C':
+        case 'D':
+        case 'E':
+        case 'F':
+          break;
+        default:
+
+          invalidReason.append(WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX.get(
+              valueString, i, String.valueOf(valueString.charAt(i))));
+          return false;
+        }
+      }
+    }
+
+    // If we've gotten here, then the value is acceptable.
+    return true;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UniqueMemberEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UniqueMemberEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..884f0f0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UniqueMemberEqualityMatchingRuleImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * This class implements the uniqueMemberMatch matching rule defined in X.520
+ * and referenced in RFC 2252. It is based on the name and optional UID syntax,
+ * and will compare values with a distinguished name and optional bit string
+ * suffix.
+ */
+final class UniqueMemberEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return value.toByteString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UnknownSchemaElementException.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UnknownSchemaElementException.java
new file mode 100644
index 0000000..63c90f7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UnknownSchemaElementException.java
@@ -0,0 +1,55 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+
+
+
+/**
+ * Thrown when a schema query fails because the requested schema element could
+ * not be found or is ambiguous.
+ */
+@SuppressWarnings("serial")
+public class UnknownSchemaElementException extends
+    LocalizedIllegalArgumentException
+{
+  /**
+   * Creates a new unknown schema element exception with the provided message.
+   *
+   * @param message
+   *          The message that explains the problem that occurred.
+   */
+  public UnknownSchemaElementException(final LocalizableMessage message)
+  {
+    super(message);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordExactEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordExactEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..fb00329
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordExactEqualityMatchingRuleImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * This class implements the userPasswordExactMatch matching rule, which will
+ * simply compare encoded hashed password values to see if they are exactly
+ * equal to each other.
+ */
+final class UserPasswordExactEqualityMatchingRuleImpl extends
+    AbstractMatchingRuleImpl
+{
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value) throws DecodeException
+  {
+    // The normalized form of this matching rule is exactly equal to the
+    // non-normalized form, except that the scheme needs to be converted
+    // to lowercase (if there is one).
+
+    if (UserPasswordSyntaxImpl.isEncoded(value))
+    {
+      final StringBuilder builder = new StringBuilder(value.length());
+      int closingBracePos = -1;
+      for (int i = 1; i < value.length(); i++)
+      {
+        if (value.byteAt(i) == '}')
+        {
+          closingBracePos = i;
+          break;
+        }
+      }
+      final ByteSequence seq1 = value.subSequence(0, closingBracePos + 1);
+      final ByteSequence seq2 = value.subSequence(closingBracePos + 1, value
+          .length());
+      StaticUtils.toLowerCase(seq1, builder);
+      builder.append(seq2);
+      return ByteString.valueOf(builder.toString());
+    }
+    else
+    {
+      return value.toByteString();
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordSyntaxImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordSyntaxImpl.java
new file mode 100644
index 0000000..06ac246
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/UserPasswordSyntaxImpl.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_USERPW_NO_SCHEME;
+import static com.sun.opends.sdk.messages.Messages.ERR_ATTR_SYNTAX_USERPW_NO_VALUE;
+import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
+import static org.opends.sdk.schema.SchemaConstants.EMR_USER_PASSWORD_EXACT_OID;
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_USER_PASSWORD_NAME;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessage;
+import org.opends.sdk.LocalizableMessageBuilder;
+
+
+
+/**
+ * This class defines an attribute syntax used for storing values that have been
+ * encoded using a password storage scheme. The format for attribute values with
+ * this syntax is the concatenation of the following elements in the given
+ * order: <BR>
+ * <UL>
+ * <LI>An opening curly brace ("{") character.</LI>
+ * <LI>The name of the storage scheme used to encode the value.</LI>
+ * <LI>A closing curly brace ("}") character.</LI>
+ * <LI>The encoded value.</LI>
+ * </UL>
+ */
+final class UserPasswordSyntaxImpl extends AbstractSyntaxImpl
+{
+  /**
+   * Decodes the provided user password value into its component parts.
+   *
+   * @param userPasswordValue
+   *          The user password value to be decoded.
+   * @return A two-element string array whose elements are the storage scheme
+   *         name (in all lowercase characters) and the encoded value, in that
+   *         order.
+   * @throws DecodeException
+   *           If a problem is encountered while attempting to decode the value.
+   */
+  static String[] decodeUserPassword(final String userPasswordValue)
+      throws DecodeException
+  {
+    // Make sure that there actually is a value to decode.
+    if (userPasswordValue == null || userPasswordValue.length() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_USERPW_NO_VALUE.get();
+      throw DecodeException.error(message);
+    }
+
+    // The first character of an encoded value must be an opening curly
+    // brace.
+    if (userPasswordValue.charAt(0) != '{')
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    // There must be a corresponding closing brace.
+    final int closePos = userPasswordValue.indexOf('}');
+    if (closePos < 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE
+          .get();
+      throw DecodeException.error(message);
+    }
+
+    // Get the storage scheme name and encoded value.
+    final String schemeName = userPasswordValue.substring(1, closePos);
+    final String encodedValue = userPasswordValue.substring(closePos + 1);
+
+    if (schemeName.length() == 0)
+    {
+      final LocalizableMessage message = ERR_ATTR_SYNTAX_USERPW_NO_SCHEME.get();
+      throw DecodeException.error(message);
+    }
+
+    return new String[] { toLowerCase(schemeName), encodedValue };
+  }
+
+
+
+  /**
+   * Indicates whether the provided value is encoded using the user password
+   * syntax.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @return <CODE>true</CODE> if the value appears to be encoded using the user
+   *         password syntax, or <CODE>false</CODE> if not.
+   */
+  static boolean isEncoded(final ByteSequence value)
+  {
+    // If the value is null or empty, then it's not.
+    if (value == null || value.length() == 0)
+    {
+      return false;
+    }
+
+    // If the value doesn't start with an opening curly brace, then it's
+    // not.
+    if (value.byteAt(0) != '{')
+    {
+      return false;
+    }
+
+    // There must be a corresponding closing curly brace, and there must
+    // be at least one character inside the brace.
+    int closingBracePos = -1;
+    for (int i = 1; i < value.length(); i++)
+    {
+      if (value.byteAt(i) == '}')
+      {
+        closingBracePos = i;
+        break;
+      }
+    }
+
+    if (closingBracePos < 0 || closingBracePos == 1)
+    {
+      return false;
+    }
+
+    // The closing curly brace must not be the last character of the
+    // password.
+    if (closingBracePos == value.length() - 1)
+    {
+      return false;
+    }
+
+    // If we've gotten here, then it looks to be encoded.
+    return true;
+  }
+
+
+
+  @Override
+  public String getEqualityMatchingRule()
+  {
+    return EMR_USER_PASSWORD_EXACT_OID;
+  }
+
+
+
+  public String getName()
+  {
+    return SYNTAX_USER_PASSWORD_NAME;
+  }
+
+
+
+  public boolean isHumanReadable()
+  {
+    return true;
+  }
+
+
+
+  public boolean valueIsAcceptable(final Schema schema,
+      final ByteSequence value, final LocalizableMessageBuilder invalidReason)
+  {
+    // We have to accept any value here because in many cases the value
+    // will not have been encoded by the time this method is called.
+    // TODO: Is this correct for client-side use?
+    return true;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/WordEqualityMatchingRuleImpl.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/WordEqualityMatchingRuleImpl.java
new file mode 100644
index 0000000..c1f15e4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/WordEqualityMatchingRuleImpl.java
@@ -0,0 +1,179 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static com.sun.opends.sdk.util.StringPrepProfile.CASE_FOLD;
+import static com.sun.opends.sdk.util.StringPrepProfile.TRIM;
+import static com.sun.opends.sdk.util.StringPrepProfile.prepareUnicode;
+
+import org.opends.sdk.*;
+
+
+
+/**
+ * This class implements the wordMatch matching rule defined in X.520. That
+ * document defines "word" as implementation-specific, but in this case we will
+ * consider it a match if the assertion value is contained within the attribute
+ * value and is bounded by the edge of the value or any of the following
+ * characters: <BR>
+ * <UL>
+ * <LI>A space</LI>
+ * <LI>A period</LI>
+ * <LI>A comma</LI>
+ * <LI>A slash</LI>
+ * <LI>A dollar sign</LI>
+ * <LI>A plus sign</LI>
+ * <LI>A dash</LI>
+ * <LI>An underscore</LI>
+ * <LI>An octothorpe</LI>
+ * <LI>An equal sign</LI>
+ * </UL>
+ */
+final class WordEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl
+{
+  @Override
+  public Assertion getAssertion(final Schema schema, final ByteSequence value)
+      throws DecodeException
+  {
+    final String normalStr = normalize(value);
+
+    return new Assertion()
+    {
+      public ConditionResult matches(final ByteSequence attributeValue)
+      {
+        // See if the assertion value is contained in the attribute
+        // value. If not, then it isn't a match.
+        final String valueStr1 = attributeValue.toString();
+
+        final int pos = valueStr1.indexOf(normalStr);
+        if (pos < 0)
+        {
+          return ConditionResult.FALSE;
+        }
+
+        if (pos > 0)
+        {
+          final char c = valueStr1.charAt(pos - 1);
+          switch (c)
+          {
+          case ' ':
+          case '.':
+          case ',':
+          case '/':
+          case '$':
+          case '+':
+          case '-':
+          case '_':
+          case '#':
+          case '=':
+            // These are all acceptable.
+            break;
+
+          default:
+            // Anything else is not.
+            return ConditionResult.FALSE;
+          }
+        }
+
+        if (valueStr1.length() > pos + normalStr.length())
+        {
+          final char c = valueStr1.charAt(pos + normalStr.length());
+          switch (c)
+          {
+          case ' ':
+          case '.':
+          case ',':
+          case '/':
+          case '$':
+          case '+':
+          case '-':
+          case '_':
+          case '#':
+          case '=':
+            // These are all acceptable.
+            break;
+
+          default:
+            // Anything else is not.
+            return ConditionResult.FALSE;
+          }
+        }
+
+        // If we've gotten here, then we can assume it is a match.
+        return ConditionResult.TRUE;
+      }
+    };
+  }
+
+
+
+  public ByteString normalizeAttributeValue(final Schema schema,
+      final ByteSequence value)
+  {
+    return ByteString.valueOf(normalize(value));
+  }
+
+
+
+  private String normalize(final ByteSequence value)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    prepareUnicode(buffer, value, TRIM, CASE_FOLD);
+
+    final int bufferLength = buffer.length();
+    if (bufferLength == 0)
+    {
+      if (value.length() > 0)
+      {
+        // This should only happen if the value is composed entirely of
+        // spaces. In that case, the normalized value is a single space.
+        return " ".intern();
+      }
+      else
+      {
+        // The value is empty, so it is already normalized.
+        return "".intern();
+      }
+    }
+
+    // Replace any consecutive spaces with a single space.
+    for (int pos = bufferLength - 1; pos > 0; pos--)
+    {
+      if (buffer.charAt(pos) == ' ')
+      {
+        if (buffer.charAt(pos - 1) == ' ')
+        {
+          buffer.delete(pos, pos + 1);
+        }
+      }
+    }
+
+    return buffer.toString();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/package-info.java b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/package-info.java
new file mode 100755
index 0000000..388c61e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/java/org/opends/sdk/schema/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+/**
+ * Classes and interfaces for constructing and querying LDAP schemas.
+ */
+package org.opends.sdk.schema;
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/javadoc/overview.html b/opendj3/opendj-modules/opendj-sdk/src/main/javadoc/overview.html
new file mode 100644
index 0000000..abcc487
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/javadoc/overview.html
@@ -0,0 +1,103 @@
+<html>
+<body>
+    The OpenDS SDK for Java provides a high performance easy to use
+    library of classes and interfaces for accessing and implementing
+    LDAP Directory Services as defined in <a
+      href="http://tools.ietf.org/html/rfc4510">RFC 4510</a>.
+    <br>
+    <h1>Getting started</h1>
+    The following example shows how the OpenDS SDK may be used to
+    connect to a Directory Server, authenticate, and then perform a
+    search. The search results are output as LDIF to the standard
+    output:
+    <br>
+    <table bgcolor="#cccccc" border="0" cellpadding="2" cellspacing="2"
+      width="100%">
+      <tbody>
+        <tr>
+          <pre>    // Create an LDIF writer which will write the search results to stdout.
+    final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
+    Connection connection = null;
+    try
+    {
+      // Connect and bind to the server.
+      final LDAPConnectionFactory factory = new LDAPConnectionFactory("localhost", 1389);
+
+      connection = factory.getConnection();
+      connection.bind(userName, password);
+
+      // Read the entries and output them as LDIF.
+      final ConnectionEntryReader reader = connection.search(baseDN, scope, filter, attributes);
+      while (reader.hasNext())
+      {
+        if (!reader.isReference())
+        {
+          // Got an entry.
+          final SearchResultEntry entry = reader.readEntry();
+          writer.writeComment("Search result entry: " + entry.getName().toString());
+          writer.writeEntry(entry);
+        }
+        else
+        {
+          // Got a continuation reference.
+          final SearchResultReference ref = reader.readReference();
+          writer.writeComment("Search result reference: " + ref.getURIs().toString());
+        }
+      }
+      writer.flush();
+    }
+    catch (final Exception e)
+    {
+      // Handle exceptions...
+      System.err.println(e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+    }</pre>
+        </tr>
+      </tbody>
+    </table>
+    <br>
+    Additional examples can be found in the file examples.zip which is
+    included with this SDK.
+    <br>
+    <h1>Creating connections</h1>
+    The following classes can be used to create and manage connections to
+    LDAP Directory Servers:
+    <ul>
+      <li>{@link org.opends.sdk.LDAPConnectionFactory}</li>
+      <li>{@link org.opends.sdk.Connection}</li>
+      <li>{@link org.opends.sdk.Connections}</li>
+    </ul>
+    <br>
+    <h1>Creating requests</h1>
+    The following classes can be used to create LDAP requests:
+    <ul>
+      <li>{@link org.opends.sdk.requests.Requests}</li>
+      <li>{@link org.opends.sdk.requests.Request}</li>
+    </ul>
+    <br>
+    <h1>Using controls</h1>
+    Common LDAP control implementations can be found in
+    {@link org.opends.sdk.controls}.
+    <br>
+    <br>
+    <h1>Core types</h1>
+    The following classes and interfaces represent core types:
+    <ul>
+      <li>{@link org.opends.sdk.AttributeDescription}</li>
+      <li>{@link org.opends.sdk.Attribute}</li>
+      <li>{@link org.opends.sdk.DN}</li>
+      <li>{@link org.opends.sdk.Entry}</li>
+      <li>{@link org.opends.sdk.Filter}</li>
+    </ul>
+    <br>
+@see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight
+      Directory Access Protocol (LDAP): The Protocol </a>
+@see org.opends.sdk
+</body>
+</html>
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages.properties
new file mode 100755
index 0000000..99aa95f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages.properties
@@ -0,0 +1,5870 @@
+#
+# 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
+#
+#
+#      Copyright 2010 Sun Microsystems, Inc.
+#
+
+
+
+#
+# Global directives
+#
+global.ordinal=-1
+
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+
+#
+# Schema messages
+#
+SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE=Unable to retrieve \
+ approximate matching rule %s used as the default for the %s attribute syntax. \
+ Approximate matching will not be allowed by default for attributes with this \
+ syntax
+SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE=Unable to retrieve \
+ equality matching rule %s used as the default for the %s attribute syntax. \
+ Equality matching will not be allowed by default for attributes with this \
+ syntax
+SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE=Unable to retrieve \
+ ordering matching rule %s used as the default for the %s attribute syntax. \
+ Ordering matches will not be allowed by default for attributes with this \
+ syntax
+SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE=Unable to retrieve \
+ substring matching rule %s used as the default for the %s attribute syntax. \
+ Substring matching will not be allowed by default for attributes with this \
+ syntax
+SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN=The provided value "%s" is not \
+ allowed for attributes with a Boolean syntax.  The only allowed values are \
+ 'TRUE' and 'FALSE'
+SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT=The provided value "%s" is too \
+ short to be a valid bit string.  A bit string must be a series of binary \
+ digits surrounded by single quotes and followed by a capital letter B
+SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED=The provided value "%s" is not \
+ a valid bit string because it is not surrounded by single quotes and followed \
+ by a capital letter B
+SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT=The provided value "%s" is \
+ not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH=The provided value "%s" \
+ is not a valid country string because the length is not exactly two characters
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE=The provided value "%s" \
+ is not a valid country string because it contains one or more non-printable \
+ characters
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS=The provided value "%s" is \
+ not a valid delivery method value because it does not contain any elements
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT=The provided value \
+ "%s" is not a valid delivery method value because "%s" is not a valid method
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT=The provided value "%s" \
+ is too short to be a valid generalized time value
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR=The provided value \
+ "%s" is not a valid generalized time value because the '%s' character is not \
+ allowed in the century or year specification
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH=The provided value \
+ "%s" is not a valid generalized time value because "%s" is not a valid month \
+ specification
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY=The provided value \
+ "%s" is not a valid generalized time value because "%s" is not a valid day \
+ specification
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR=The provided value \
+ "%s" is not a valid generalized time value because "%s" is not a valid hour \
+ specification
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE=The provided value \
+ "%s" is not a valid generalized time value because "%s" is not a valid minute \
+ specification
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND=The provided value \
+ "%s" is not a valid generalized time value because "%s" is not a valid second \
+ specification
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND=The provided \
+ value "%s" is not a valid generalized time value because the sub-second \
+ component is not valid (between 1 and 3 numeric digits)
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND=The provided value \
+ "%s" is not a valid generalized time value because the sub-second value may \
+ not contain more than three digits
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET=The provided value \
+ "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+ offset
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR=The provided value \
+ "%s" is not a valid generalized time value because it contains an invalid \
+ character '%s' at position %d
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE=The provided value \
+ "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID=The provided value "%s" could not be parsed \
+ as a valid distinguished name:  %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA=The provided value "%s" could not be \
+ parsed as a valid distinguished name because the last non-space character was \
+ a comma or semicolon
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT=The provided value "%s" could \
+ not be parsed as a valid distinguished name because numeric digit '%s' is not \
+ allowed as the first character in an attribute name
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR=The provided value "%s" could not \
+ be parsed as a valid distinguished name because character '%c' at position %d \
+ is not allowed in an attribute name
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR=The provided value \
+ "%s" could not be parsed as a valid distinguished name because the underscore \
+ character is not allowed in an attribute name unless the %s configuration \
+ option is enabled
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH=The provided value "%s" \
+ could not be parsed as a valid distinguished name because the hyphen \
+ character is not allowed as the first character of an attribute name
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE=The provided value \
+ "%s" could not be parsed as a valid distinguished name because the underscore \
+ character is not allowed as the first character of an attribute name even if \
+ the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT=The provided value "%s" \
+ could not be parsed as a valid distinguished name because the digit '%c' is \
+ not allowed as the first character of an attribute name unless the \
+ name is specified as an OID or the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME=The provided value "%s" could not be \
+ parsed as a valid distinguished name because it contained an RDN containing \
+ an empty attribute name
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD=The provided value "%s" could \
+ not be parsed as a valid distinguished name because the parsed attribute name \
+ %s included a period but that name did not appear to be a valid OID
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME=The provided value "%s" could \
+ not be parsed as a valid distinguished name because the last non-space \
+ character was part of the attribute name '%s'
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL=The provided value "%s" could not be \
+ parsed as a valid distinguished name because the next non-space character \
+ after attribute name "%s" should have been an equal sign but instead was '%c'
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR=The provided value "%s" could not be \
+ parsed as a valid distinguished name because character '%c' at position %d is \
+ not valid
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT=The provided value "%s" could \
+ not be parsed as a valid distinguished name because an attribute value \
+ started with an octothorpe (#) but was not followed by a positive multiple of \
+ two hexadecimal digits
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT=The provided value "%s" could not \
+ be parsed as a valid distinguished name because an attribute value started \
+ with an octothorpe (#) but contained a character %c that was not a valid \
+ hexadecimal digit
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE=The provided value "%s" \
+ could not be parsed as a valid distinguished name because an unexpected \
+ failure occurred while attempting to parse an attribute value from one of the \
+ RDN components:  "%s"
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE=The provided value "%s" could not \
+ be parsed as a valid distinguished name because one of the RDN components \
+ included a quoted value that did not have a corresponding closing quotation \
+ mark
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID=The provided value "%s" \
+ could not be parsed as a valid distinguished name because one of the RDN \
+ components included a value with an escaped hexadecimal digit that was not \
+ followed by a second hexadecimal digit
+SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO=The provided value "%s" could \
+ not be parsed as a valid integer because the first digit may not be zero \
+ unless it is the only digit
+SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH=The provided value "%s" \
+ could not be parsed as a valid integer because the dash may only appear if it \
+ is the first character of the value followed by one or more digits
+SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER=The provided value "%s" \
+ could not be parsed as a valid integer because character '%c' at position %d \
+ is not allowed in an integer value
+SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE=The provided value "%s" could \
+ not be parsed as a valid integer because it did not contain any digits
+SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE=The provided value "%s" \
+ could not be parsed as a valid integer because it contained only a dash not \
+ followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE=The provided value could not be parsed \
+ as a valid OID because it did not contain any characters
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER=The provided value "%s" could not \
+ be parsed as a valid OID because it had an illegal character at position %d
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS=The provided value "%s" could \
+ not be parsed as a valid OID because it had two consecutive periods at or \
+ near position %d
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD=The provided value "%s" could not \
+ be parsed as a valid OID because it ends with a period
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE=The provided value could not be \
+ parsed as a valid attribute type description because it was empty or \
+ contained only whitespace
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS=The provided value \
+ "%s" could not be parsed as an attribute type description because an open \
+ parenthesis was expected at position %d but instead a '%s' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE=The provided value "%s" \
+ could not be parsed as an attribute type description because the end of the \
+ value was encountered while the Directory Server expected more data to be \
+ provided
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as an attribute type description because the \
+ numeric OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as an attribute type description because the \
+ numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID=The provided \
+ value "%s" could not be parsed as an attribute type description because the \
+ non-numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR=The provided value "%s" could \
+ not be parsed as an attribute type description because it contained an \
+ illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS=The provided \
+ value "%s" could not be parsed as an attribute type description because it \
+ contained an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE=The provided value "%s" could \
+ not be parsed as an attribute type description because a single quote was \
+ expected as the first non-blank character following token %s.  However, the \
+ character %s was found instead
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE=The definition for \
+ the attribute type with OID %s declared a superior type with an OID of %s. \
+ No attribute type with this OID exists in the server schema
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR=The definition for \
+ the attribute type with OID %s declared that approximate matching should be \
+ performed using the matching rule "%s".  No such approximate matching rule is \
+ configured for use in the Directory Server
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR=The definition for \
+ the attribute type with OID %s declared that equality matching should be \
+ performed using the matching rule "%s".  No such equality matching rule is \
+ configured for use in the Directory Server
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR=The definition for \
+ the attribute type with OID %s declared that ordering matching should be \
+ performed using the matching rule "%s".  No such ordering matching rule is \
+ configured for use in the Directory Server
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR=The definition for \
+ the attribute type with OID %s declared that substring matching should be \
+ performed using the matching rule "%s".  No such substring matching rule is \
+ configured for use in the Directory Server
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX=The definition for the \
+ attribute type with OID %s declared that it should have a syntax with OID %s. \
+ No such syntax is configured for use in the Directory Server
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE=The definition \
+ for the attribute type with OID %s declared that it should have an attribute \
+ usage of %s.  This is an invalid usage
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS=The provided value \
+ "%s" could not be parsed as an attribute type description because a single \
+ quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE=The provided value could not \
+ be parsed as a valid objectclass description because it was empty or \
+ contained only whitespace
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS=The provided \
+ value "%s" could not be parsed as an objectclass description because an open \
+ parenthesis was expected at position %d but instead a '%s' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE=The provided value "%s" \
+ could not be parsed as an objectclass description because the end of the \
+ value was encountered while the Directory Server expected more data to be \
+ provided
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as an objectclass description because the \
+ numeric OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as an objectclass description because the \
+ numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID=The provided \
+ value "%s" could not be parsed as an objectclass description because the \
+ non-numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR=The provided value "%s" \
+ could not be parsed as an objectclass description because it contained an \
+ illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS=The provided \
+ value "%s" could not be parsed as an objectclass description because it \
+ contained an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE=The provided value "%s" \
+ could not be parsed as an objectclass description because a single quote was \
+ expected as the first non-blank character following token %s.  However, the \
+ character %s was found instead
+SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS=The definition \
+ for the objectclass with OID %s declared a superior objectclass with an OID \
+ of %s.  No objectclass with this OID exists in the server schema
+SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS=The provided \
+ value "%s" could not be parsed as an objectclass description because a single \
+ quote was expected at position %d but the character %s was found instead
+SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR=The definition \
+ for the objectclass with OID %s declared that it should include required \
+ attribute "%s".  No attribute type matching this name or OID exists in the \
+ server schema
+SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR=The definition \
+ for the objectclass with OID %s declared that it should include optional \
+ attribute "%s".  No attribute type matching this name or OID exists in the \
+ server schema
+SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER=The provided value "%s" \
+ cannot be parsed as a valid IA5 string because it contains an illegal \
+ character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE=This indicates whether \
+ the telephone number attribute syntax should use a strict mode in which it \
+ will only accept values in the ITU-T E.123 format.  If this is enabled, then \
+ any value not in this format will be rejected.  If this is disabled, then any \
+ value will be accepted, but only the digits will be considered when \
+ performing matching
+SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE=An error \
+ occurred while trying to retrieve attribute \
+ ds-cfg-strict-format from configuration entry %s:  %s.  The \
+ Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+ for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY=The provided value is not a valid \
+ telephone number because it is empty or null
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS=The provided value "%s" is not a \
+ valid telephone number because strict telephone number checking is enabled \
+ and the value does not start with a plus sign in compliance with the ITU-T \
+ E.123 specification
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR=The provided value "%s" is not \
+ a valid telephone number because strict telephone number checking is enabled \
+ and the character %s at position %d is not allowed by the ITU-T E.123 \
+ specification
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS=The provided value "%s" is not a \
+ valid telephone number because it does not contain any numeric digits
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE=The value of configuration \
+ attribute ds-cfg-strict-format, which indicates whether to \
+ use strict telephone number syntax checking, has been updated to %s in \
+ configuration entry %s
+SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR=The provided value \
+ "%s" is not a valid numeric string because it contained character %s at \
+ position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE=The provided value is not \
+ a valid numeric string because it did not contain any characters.  A numeric \
+ string value must contain at least one numeric digit or space
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE=The provided value could not \
+ be parsed as a valid attribute syntax description because it was empty or \
+ contained only whitespace
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS=The provided \
+ value "%s" could not be parsed as an attribute syntax description because an \
+ open parenthesis was expected at position %d but instead a '%s' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE=The provided value "%s" \
+ could not be parsed as an attribute syntax description because the end of the \
+ value was encountered while the Directory Server expected more data to be \
+ provided
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as an attribute syntax description because the \
+ numeric OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as an attribute syntax description because the \
+ numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID=The provided \
+ value "%s" could not be parsed as an attribute syntax description because the \
+ non-numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS=The provided \
+ value "%s" could not be parsed as an attribute syntax description because it \
+ contained an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN=The provided value \
+ "%s" could not be parsed as an attribute syntax description because an \
+ unexpected error occurred while trying to read the "DESC" token from the \
+ string at or near position %d:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC=The provided value "%s" \
+ could not be parsed as an attribute syntax description because the "DESC" \
+ token was expected but the string "%s" was found instead
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE=The provided value \
+ "%s" could not be parsed as an attribute syntax description because an \
+ unexpected error occurred while trying to read the value of the "DESC" token \
+ from the string at or near position %d:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS=The provided \
+ value "%s" could not be parsed as an attribute syntax description because a \
+ close parenthesis was expected at position %d but instead a '%s' character \
+ was found
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE=The provided \
+ value "%s" could not be parsed as an attribute syntax description because an \
+ illegal character %s was found at position %d after the close parenthesis
+SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS=The provided \
+ value "%s" could not be parsed as an attribute syntax description because a \
+ single quote was expected at position %d but the character %s was found \
+ instead
+SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE=The provided value \
+ could not be parsed as a printable string because it was null or empty.  A \
+ printable string must contain at least one character
+SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER=The provided \
+ value "%s" could not be parsed as a printable string because it contained an \
+ invalid character %s at position %d
+SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD=The provided value "*" \
+ could not be parsed as a substring assertion because it consists only of a \
+ wildcard character and zero-length substrings are not allowed
+SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS=The provided \
+ value "%s" could not be parsed as a substring assertion because it contains \
+ consecutive wildcard characters at position %d and zero-length substrings are \
+ not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT=The provided value %s is too \
+ short to be a valid UTC time value
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR=The provided value %s is not a \
+ valid UTC time value because the %s character is not allowed in the century \
+ or year specification
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH=The provided value %s is not \
+ a valid UTC time value because %s is not a valid month specification
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY=The provided value %s is not a \
+ valid UTC time value because %s is not a valid day specification
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR=The provided value %s is not a \
+ valid UTC time value because %s is not a valid hour specification
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE=The provided value %s is not \
+ a valid UTC time value because %s is not a valid minute specification
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR=The provided value %s is not a \
+ valid UTC time value because it contains an invalid character %s at position \
+ %d
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND=The provided value %s is not \
+ a valid UTC time value because %s is not a valid second specification
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET=The provided value %s is not \
+ a valid UTC time value because %s is not a valid GMT offset
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE=The provided value %s could \
+ not be parsed as a valid UTC time:  %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE=The provided value could not be \
+ parsed as a valid DIT content rule description because it was empty or \
+ contained only whitespace
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS=The provided value \
+ "%s" could not be parsed as a DIT content rule description because an open \
+ parenthesis was expected at position %d but instead a '%s' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE=The provided value "%s" could \
+ not be parsed as a DIT content rule description because the end of the value \
+ was encountered while the Directory Server expected more data to be provided
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided value \
+ "%s" could not be parsed as a DIT content rule description because the \
+ numeric OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided value \
+ "%s" could not be parsed as a DIT content rule description because the \
+ numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID=The provided value \
+ "%s" could not be parsed as a DIT content rule description because the \
+ non-numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS=The provided value \
+ "%s" could not be parsed as a DIT content rule description because it \
+ contained an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR=The provided value "%s" could not \
+ be parsed as a DIT content rule description because it contained an illegal \
+ character %s at position %d
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS=The DIT content rule \
+ "%s" is associated with a structural objectclass %s that is not defined in \
+ the server schema
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL=The DIT content \
+ rule "%s" is associated with the objectclass with OID %s (%s).  This \
+ objectclass exists in the server schema but is defined as %s rather than \
+ structural
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS=The DIT content rule \
+ "%s" is associated with an auxiliary objectclass %s that is not defined in \
+ the server schema
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY=The DIT content \
+ rule "%s" is associated with an auxiliary objectclass %s.  This objectclass \
+ exists in the server schema but is defined as %s rather than auxiliary
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR=The DIT content rule "%s" \
+ is associated with a required attribute type %s that is not defined in the \
+ server schema
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR=The DIT content rule "%s" \
+ is associated with an optional attribute type %s that is not defined in the \
+ server schema
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR=The DIT content rule \
+ "%s" is associated with a prohibited attribute type %s that is not defined in \
+ the server schema
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS=The provided value "%s" \
+ could not be parsed as a DIT content rule description because a single quote \
+ was expected at position %d but the %s character was found instead
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE=The provided value could not \
+ be parsed as a valid name form description because it was empty or contained \
+ only whitespace
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS=The provided \
+ value "%s" could not be parsed as a name form description because an open \
+ parenthesis was expected at position %d but instead a '%c' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE=The provided value "%s" \
+ could not be parsed as a name form description because the end of the value \
+ was encountered while the Directory Server expected more data to be provided
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as a name form description because the numeric \
+ OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as a name form description because the numeric \
+ OID contained an illegal character %c at position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID=The provided \
+ value "%s" could not be parsed as a name form description because the \
+ non-numeric OID contained an illegal character %c at position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS=The provided \
+ value "%s" could not be parsed as a name form description because it \
+ contained an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR=The provided value "%s" could \
+ not be parsed as a name form description because it contained an illegal \
+ character %c at position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS=The name form \
+ description "%s" is associated with a structural objectclass %s that is not \
+ defined in the server schema
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL=The name \
+ form description "%s" is associated with the objectclass with OID %s (%s). \
+ This objectclass exists in the server schema but is defined as %s rather than \
+ structural
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR=The definition for \
+ the name form with OID %s declared that it should include required attribute \
+ "%s".  No attribute type matching this name or OID exists in the server \
+ schema
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR=The definition for \
+ the name form with OID %s declared that it should include optional attribute \
+ "%s".  No attribute type matching this name or OID exists in the server \
+ schema
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS=The provided value \
+ "%s" could not be parsed as a name form description because it does not \
+ specify the structural objectclass with which it is associated
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS=The provided value \
+ "%s" could not be parsed as a name form description because a single quote \
+ was expected at position %d but the %c character was found instead
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE=The provided value could not be \
+ parsed as a valid matching rule description because it was empty or contained \
+ only whitespace
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS=The provided value "%s" \
+ could not be parsed as a matching rule description because an open \
+ parenthesis was expected at position %d but instead a '%s' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE=The provided value "%s" could not \
+ be parsed as a matching rule description because the end of the value was \
+ encountered while the Directory Server expected more data to be provided
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided value \
+ "%s" could not be parsed as a matching rule description because the numeric \
+ OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided value \
+ "%s" could not be parsed as a matching rule description because the numeric \
+ OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID=The provided value \
+ "%s" could not be parsed as a matching rule description because the \
+ non-numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS=The provided value \
+ "%s" could not be parsed as a matching rule description because it contained \
+ an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR=The provided value "%s" could not be \
+ parsed as a matching rule description because it contained an illegal \
+ character %s at position %d
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX=The matching rule description "%s" \
+ is associated with attribute syntax %s that is not defined in the server \
+ schema
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX=The provided value "%s" could not be \
+ parsed as a matching rule description because it does not specify the \
+ attribute syntax with which it is associated
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS=The provided value "%s" \
+ could not be parsed as a matching rule description because a single quote was \
+ expected at position %d but the %s character was found instead
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE=The provided value could not be \
+ parsed as a valid matching rule use description because it was empty or \
+ contained only whitespace
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS=The provided value \
+ "%s" could not be parsed as a matching rule use description because an open \
+ parenthesis was expected at position %d but instead a '%s' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE=The provided value "%s" could \
+ not be parsed as a matching rule use description because the end of the value \
+ was encountered while the Directory Server expected more data to be provided
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided \
+ value "%s" could not be parsed as a matching rule use description because the \
+ numeric OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided value \
+ "%s" could not be parsed as a matching rule use description because the \
+ numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID=The provided value \
+ "%s" could not be parsed as a matching rule use description because the \
+ non-numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE=The provided value "%s" \
+ could not be parsed as a matching rule use description because the specified \
+ matching rule %s is unknown
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS=The provided \
+ value "%s" could not be parsed as a matching rule use description because it \
+ contained an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR=The provided value "%s" could not \
+ be parsed as a matching rule use description because it contained an illegal \
+ character %s at position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR=The matching rule use description \
+ "%s" is associated with attribute type %s that is not defined in the server \
+ schema
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR=The provided value "%s" could not be \
+ parsed as a matching rule description because it does not specify the set of \
+ attribute types that may be used with the associated OID
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS=The provided value "%s" \
+ could not be parsed as a matching rule use description because a single quote \
+ was expected at position %d but the %s character was found instead
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE=The provided value could not be \
+ parsed as a valid DIT structure rule description because it was empty or \
+ contained only whitespace
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS=The provided value \
+ "%s" could not be parsed as a DIT structure rule description because an open \
+ parenthesis was expected at position %d but instead a '%s' character was \
+ found
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE=The provided value "%s" could \
+ not be parsed as a DIT structure rule description because the end of the \
+ value was encountered while the Directory Server expected more data to be \
+ provided
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID=The provided value "%s" \
+ could not be parsed as a DIT structure rule description because the rule ID \
+ contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS=The provided value \
+ "%s" could not be parsed as a DIT structure rule description because it \
+ contained an unexpected closing parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR=The provided value "%s" could not \
+ be parsed as a DIT structure rule description because it contained an illegal \
+ character %s at position %d
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM=The provided value "%s" could \
+ not be parsed as a DIT structure rule description because it referenced an \
+ unknown name form %s
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID=The provided value "%s" could \
+ not be parsed as a DIT structure rule description because it referenced an \
+ unknown rule ID %d for a superior DIT structure rule
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM=The provided value "%s" could not \
+ be parsed as a DIT structure rule description because it did not specify the \
+ name form for the rule
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS=The provided value "%s" \
+ could not be parsed as a DIT structure rule description because a single \
+ quote was expected at position %d but the %s character was found instead
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID=The provided value \
+ "%s" could not be parsed as a DIT structure rule description because the \
+ numeric OID contained two consecutive periods at position %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID=The provided value \
+ "%s" could not be parsed as a DIT structure rule description because the \
+ numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID=The provided value \
+ "%s" could not be parsed as a DIT structure rule description because the \
+ non-numeric OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT=The provided value "%s" is too short \
+ to be a valid telex number value
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE=The provided value "%s" does not \
+ hold a valid telex number because a character %s at position %d was not a \
+ valid printable string character
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR=The provided value "%s" does not \
+ hold a valid telex number because character %s at position %d was neither a \
+ valid printable string character nor a dollar sign to separate the telex \
+ number components
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED=The provided value "%s" does not \
+ hold a valid telex number because the end of the value was found before three \
+ dollar-delimited printable strings could be read
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY=The provided value could not be \
+ parsed as a valid facsimile telephone number because it was empty
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE=The provided value "%s" \
+ could not be parsed as a valid facsimile telephone number because character \
+ %s at position %d was not a valid printable string character
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR=The provided value "%s" \
+ could not be parsed as a valid facsimile telephone number because it ends \
+ with a dollar sign, but that dollar sign should have been followed by a fax \
+ parameter
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER=The provided value "%s" \
+ could not be parsed as a valid facsimile telephone number because the string \
+ "%s" between positions %d and %d was not a valid fax parameter
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN=The provided value "%s" could \
+ not be parsed as a valid name and optional UID value because an error \
+ occurred while trying to parse the DN portion:  %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT=The provided value \
+ "%s" could not be parsed as a valid name and optional UID value because the \
+ UID portion contained an illegal binary digit %s at position %d
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY=The provided value could not be \
+ parsed as a valid teletex terminal identifier because it was empty
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE=The provided value "%s" \
+ could not be parsed as a valid teletex terminal identifier because character \
+ %s at position %d was not a valid printable string character
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR=The provided value "%s" \
+ could not be parsed as a valid teletex terminal identifier because it ends \
+ with a dollar sign, but that dollar sign should have been followed by a TTX \
+ parameter
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON=The provided value "%s" \
+ could not be parsed as a valid teletex terminal identifier because the \
+ parameter string does not contain a colon to separate the name from the value
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER=The provided value "%s" \
+ could not be parsed as a valid teletex terminal identifier because the string \
+ "%s" is not a valid TTX parameter name
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE=The provided value could \
+ not be parsed as an other mailbox value because it was empty
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE=The provided value "%s" \
+ could not be parsed as an other mailbox value because there was no mailbox \
+ type before the dollar sign
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR=The provided value \
+ "%s" could not be parsed as an other mailbox value because the mailbox type \
+ contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX=The provided value "%s" \
+ could not be parsed as an other mailbox value because there was no mailbox \
+ after the dollar sign
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR=The provided value \
+ "%s" could not be parsed as an other mailbox value because the mailbox \
+ contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC=The provided value "%s" could not be \
+ parsed as a guide value because it did not contain an objectclass name or OID \
+ before the octothorpe (#) character
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR=The provided value "%s" could not \
+ be parsed as a guide value because the criteria portion %s contained an \
+ illegal character %c at position %d
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN=The provided value "%s" \
+ could not be parsed as a guide value because the criteria portion %s did not \
+ contain a close parenthesis that corresponded to the initial open parenthesis
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK=The provided value "%s" \
+ could not be parsed as a guide value because the criteria portion %s started \
+ with a question mark but was not followed by the string "true" or "false"
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR=The provided value "%s" could not be \
+ parsed as a guide value because the criteria portion %s did not contain a \
+ dollar sign to separate the attribute type from the match type
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR=The provided value "%s" could not be \
+ parsed as a guide value because the criteria portion %s did not specify an \
+ attribute type before the dollar sign
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE=The provided value "%s" could \
+ not be parsed as a guide value because the criteria portion %s did not \
+ specify a match type after the dollar sign
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE=The provided value "%s" \
+ could not be parsed as a guide value because the criteria portion %s had an \
+ invalid match type starting at position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP=The provided value "%s" could \
+ not be parsed as an enhanced guide value because it did not contain an \
+ octothorpe (#) character to separate the objectclass from the criteria
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC=The provided value "%s" could \
+ not be parsed as an enhanced guide value because it did not contain an \
+ objectclass name or OID before the octothorpe (#) character
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID=The provided \
+ value "%s" could not be parsed as an enhanced guide value because the numeric \
+ OID %s specifying the objectclass contained two consecutive periods at \
+ position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID=The provided \
+ value "%s" could not be parsed as an enhanced guide value because the numeric \
+ OID %s specifying the objectclass contained an illegal character %s at \
+ position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME=The provided \
+ value "%s" could not be parsed as an enhanced guide value because the \
+ objectclass name %s contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP=The provided value "%s" \
+ could not be parsed as an enhanced guide value because it did not have an \
+ octothorpe (#) character to separate the criteria from the scope
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE=The provided value "%s" could \
+ not be parsed as an enhanced guide value because no scope was provided after \
+ the final octothorpe (#) character
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE=The provided value "%s" \
+ could not be parsed as an enhanced guide value because the specified scope %s \
+ was invalid
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA=The provided value "%s" \
+ could not be parsed as an enhanced guide value because it did not specify any \
+ criteria between the octothorpe (#) characters
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE=The provided value %s could not be \
+ parsed as a valid OID:  %s
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE=An unexpected \
+ error occurred while trying to normalize value %s as a generalized time \
+ value:  %s
+SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE=An error occurred \
+ while attempting to compare two AttributeValue objects using the \
+ caseExactOrderingMatch matching rule because the normalized form of one of \
+ those values could not be retrieved:  %s
+SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE=An error occurred while \
+ attempting to compare two objects using the caseExactOrderingMatch matching \
+ rule because the objects were of an unsupported type %s.  Only byte arrays, \
+ ASN.1 octet strings, and attribute value objects may be compared
+SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE=An error occurred \
+ while attempting to compare two AttributeValue objects using the \
+ caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+ those values could not be retrieved:  %s
+SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE=An error occurred while \
+ attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+ rule because the objects were of an unsupported type %s.  Only byte arrays, \
+ ASN.1 octet strings, and attribute value objects may be compared
+SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE=An error \
+ occurred while attempting to compare two AttributeValue objects using the \
+ generalizedTimeOrderingMatch matching rule because the normalized form of one \
+ of those values could not be retrieved:  %s
+SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE=An error occurred \
+ while attempting to compare two objects using the \
+ generalizedTimeOrderingMatch matching rule because the objects were of an \
+ unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+ value objects may be compared
+SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE=An error occurred while \
+ attempting to compare two AttributeValue objects using the \
+ integerOrderingMatch matching rule because the normalized form of one of \
+ those values could not be retrieved:  %s
+SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE=An error occurred while \
+ attempting to compare two objects using the integerOrderingMatch matching \
+ rule because the objects were of an unsupported type %s.  Only byte arrays, \
+ ASN.1 octet strings, and attribute value objects may be compared
+SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE=An error occurred \
+ while attempting to compare two AttributeValue objects using the \
+ numericStringOrderingMatch matching rule because the normalized form of one \
+ of those values could not be retrieved:  %s
+SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE=An error occurred \
+ while attempting to compare two objects using the numericStringOrderingMatch \
+ matching rule because the objects were of an unsupported type %s.  Only byte \
+ arrays, ASN.1 octet strings, and attribute value objects may be compared
+SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE=An error occurred \
+ while attempting to compare two AttributeValue objects using the \
+ octetStringOrderingMatch matching rule because the normalized form of one of \
+ those values could not be retrieved:  %s
+SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE=An error occurred while \
+ attempting to compare two objects using the octetStringOrderingMatch matching \
+ rule because the objects were of an unsupported type %s.  Only byte arrays, \
+ ASN.1 octet strings, and attribute value objects may be compared
+SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH=The provided value "%s" has \
+ an invalid length for a UUID.  All UUID values must have a length of exactly \
+ 36 bytes, but the provided value had a length of %d bytes
+SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH=The provided value "%s" should \
+ have had a dash at position %d, but the character '%s' was found instead
+SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX=The provided value "%s" should \
+ have had a hexadecimal digit at position %d, but the character '%s' was found \
+ instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH=Indicates \
+ whether attributes with the directory string syntax will be allowed to have \
+ zero-length values.  This is technically not allowed by the LDAP \
+ specifications, but it may be useful for backward compatibility with previous \
+ Directory Server releases
+SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH=An \
+ error occurred while trying to determine the value of the %s configuration \
+ attribute, which indicates whether directory string attributes should be \
+ allowed to have zero-length values:  %s
+SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE=The \
+ operation attempted to assign a zero-length value to an attribute with the \
+ directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH=The %s \
+ attribute in configuration entry %s has been updated with a new value of %s
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR=The provided \
+ authPassword value had an invalid scheme character at position %d
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME=The provided authPassword value \
+ had a zero-length scheme element
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR=The provided \
+ authPassword value was missing the separator character or had an illegal \
+ character between the scheme and authInfo elements
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR=The provided \
+ authPassword value had an invalid authInfo character at position %d
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO=The provided authPassword \
+ value had a zero-length authInfo element
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR=The provided \
+ authPassword value was missing the separator character or had an illegal \
+ character between the authInfo and authValue elements
+SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS=The provided value \
+ "%s" could not be parsed by the integer first component matching rule because \
+ it did not start with a parenthesis
+SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE=The provided value "%s" could not \
+ be parsed by the integer first component matching rule because it did not \
+ have any non-space characters after the opening parenthesis
+SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT=The provided value "%s" \
+ could not be parsed by the integer first component matching rule because it \
+ did not have any space characters after the first component
+SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT=The provided value \
+ "%s" could not be parsed by the integer first component matching rule because \
+ the first component does not appear to be an integer value
+SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE=No value was given to decode by \
+ the user password attribute syntax
+SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE=Unable to decode the \
+ provided value according to the user password syntax because the value does \
+ not start with the opening curly brace ("{") character
+SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE=Unable to decode the \
+ provided value according to the user password syntax because the value does \
+ not contain a closing curly brace ("}") character
+SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME=Unable to decode the provided \
+ value according to the user password syntax because the value does not \
+ contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID=The provided \
+ value "%s" could not be parsed as a valid RFC 3672 subtree specification
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID=The provided \
+ value "%s" could not be parsed as a valid absolute subtree specification
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID=The provided \
+ value "%s" could not be parsed as a valid relative subtree specification
+SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER=The provided value %s is not \
+ allowed for attributes with a Integer syntax
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR=The provided \
+ authPassword value had an invalid authValue character at position %d
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE=The provided authPassword \
+ value had a zero-length authValue element
+SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR=The provided \
+ authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER=The provided \
+ value "%s" could not be parsed as an attribute syntax extension because an \
+ invalid character was found at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION=The attribute syntax \
+ could not be parsed because of an invalid extension.%s
+SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE=The definition \
+ for objectclass %s is invalid because it has an objectclass type of %s but \
+ this is incompatible with the objectclass type %s for the superior class %s
+SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP=The \
+ definition for objectclass %s is invalid because it is defined as a \
+ structural class but its superior chain does not include the "top" \
+ objectclass
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE=The definition \
+ for attribute type %s is invalid because its attribute usage %s is not the \
+ same as the usage for its superior type %s
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE=The \
+ definition for attribute type %s is invalid because it is defined as a \
+ collective type but the superior type %s is not collective
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE=The \
+ definition for attribute type %s is invalid because it is not defined as a \
+ collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL=The DIT \
+ content rule "%s" is not valid because it prohibits the use of attribute type \
+ %s which is required by the associated structural object class %s
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY=The DIT content \
+ rule "%s" is not valid because it prohibits the use of attribute type %s \
+ which is required by the associated auxiliary object class %s
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL=The definition \
+ for attribute type %s is invalid because it is declared COLLECTIVE but does \
+ not have a usage of userApplications
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL=The \
+ definition for attribute type %s is invalid because it is declared \
+ NO-USER-MODIFICATION but does not have an operational usage
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR=The \
+ provided value %s is not a valid generalized time value because it contains \
+ illegal character %s in the fraction component
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION=The provided \
+ value %s is not a valid generalized time value because it does not contain at \
+ least one digit after the period to use as the fractional component
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO=The provided \
+ value %s is not a valid generalized time value because it does not end with \
+ 'Z' or a time zone offset
+SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME=The provided value \
+ %s is not a valid generalized time value because it represents an invalid \
+ time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED=A schema element could not be imported: %s, %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE=The collation \
+ rule %s under matching rule entry %s is invalid as the locale %s is not supported \
+ by JVM
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT=The provided \
+ collation rule %s does not contain a valid format of OID:LOCALE
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR=The provided \
+ value "%s" could not be parsed as a valid distinguished name because an \
+ attribute value started with a character at position %d that needs to be escaped
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR=The provided value "%s" could not \
+ be parsed as a valid attribute type definition because character '%c' at \
+ position %d is not allowed in an attribute type name
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR=The provided value \
+ "%s" could not be parsed as a valid attribute type definition because the \
+ underscore character is not allowed in an attribute type name unless the \
+ %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH=The provided value "%s" \
+ could not be parsed as a valid attribute type definition because the hyphen \
+ character is not allowed as the first character of an attribute type name
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE=The provided value \
+ "%s" could not be parsed as a valid attribute type definition because the \
+ underscore character is not allowed as the first character of an attribute \
+ type name even if the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT=The provided value "%s" \
+ could not be parsed as a valid attribute type definition because the \
+ digit '%c' is not allowed as the first character of an attribute type name \
+ unless the name is specified as an OID or the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR=The provided value "%s" could not \
+ be parsed as a valid object class definition because character '%c' at \
+ position %d is not allowed in an object class name
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR=The provided value \
+ "%s" could not be parsed as a valid object class definition because the \
+ underscore character is not allowed in an object class name unless the \
+ %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH=The provided value "%s" \
+ could not be parsed as a valid object class definition because the hyphen \
+ character is not allowed as the first character of an object class name
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE=The provided value \
+ "%s" could not be parsed as a valid object class definition because the \
+ underscore character is not allowed as the first character of an object \
+ class name even if the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT=The provided value "%s" \
+ could not be parsed as a valid object class definition because the \
+ digit '%c' is not allowed as the first character of an object class name \
+ unless the name is specified as an OID or the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_MULTIPLE_SUPERIOR_CLASS=The provided "%s" \
+ value could not be parsed as a valid superior object class definition because \
+ definition for the objectclass with OID %s has already  declared a superior objectclass with an OID \
+ of %s. Multiple inheritance of objectclasses is not yet supported
+MILD_WARN_ATTR_INVALID_RELATIVE_TIME_ASSERTION_FORMAT=The provided \
+ value "%s" could not be parsed as a valid assertion value because the \
+ character '%c' is not allowed. The acceptable values are s(second),m(minute), \
+ ,h(hour),d(day) and w(week)
+MILD_WARN_ATTR_INVALID_PARTIAL_TIME_ASSERTION_FORMAT=The provided \
+ value "%s" could not be parsed as a valid assertion value because the \
+ character '%c' is not allowed. The acceptable values are DD (date),MM(month) \
+ and YYYY(year)
+MILD_WARN_ATTR_MISSING_CHAR_PARTIAL_TIME_ASSERTION_FORMAT=The provided \
+ value "%s" could not be parsed as a valid assertion value because an invalid \
+ character '%c' is  found instead of '%c' at position %d
+MILD_WARN_ATTR_INVALID_DATE_ASSERTION_FORMAT=The provided \
+  value "%s" could not be parsed as a valid assertion value because "%d" is not \
+  a valid date specification
+MILD_WARN_ATTR_INVALID_MONTH_ASSERTION_FORMAT=The provided \
+  value "%s" could not be parsed as a valid assertion value because "%d" is not \
+  a valid month specification
+MILD_WARN_ATTR_INVALID_YEAR_ASSERTION_FORMAT=The provided \
+  value "%s" could not be parsed as a valid assertion value because "%d" is not \
+  a valid year specification
+MILD_WARN_ATTR_DUPLICATE_DATE_ASSERTION_FORMAT=The provided \
+  value "%s" could not be parsed as a valid assertion value because there is  \
+  conflicting  value "%d" for DD(Date) specification
+MILD_WARN_ATTR_DUPLICATE_MONTH_ASSERTION_FORMAT=The provided \
+  value "%s" could not be parsed as a valid assertion value because there is  \
+  conflicting  value "%d" for MM(Month) specification
+MILD_WARN_ATTR_DUPLICATE_YEAR_ASSERTION_FORMAT=The provided \
+  value "%s" could not be parsed as a valid assertion value because there is  \
+  conflicting  value "%d" for YYYY(Year) specification
+MILD_WARN_ATTR_MISSING_YEAR_PARTIAL_TIME_ASSERTION_FORMAT=The provided \
+ value "%s" could not be parsed as a valid assertion value because it does \
+ not contain year in YYYY format
+MILD_WARN_ATTR_CONFLICTING_ASSERTION_FORMAT=The provided \
+ value "%s" could not be parsed as a valid assertion value because more than  \
+ one time units are not allowed
+MILD_WARN_ATTR_LDAP_SYNTAX_ILLEGAL_CHAR_IN_OID=The provided value "%s" \
+ could not be parsed as an ldap syntax because the OID contained an illegal \
+ character %s at position %d
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_UNKNOWN_EXT=The provided value "%s" \
+ could not be parsed as an ldap syntax because it contains an unrecognized \
+ extension %s at position %d
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_VALUE=The provided value \
+  "%s" cannot be parsed as a valid regex syntax because it does not match  \
+  the pattern "%s"
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_NO_PATTERN=The provided value "%s" \
+ could not be parsed as a regex syntax because it does not contain a regex pattern
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_REGEX_INVALID_PATTERN=The definition for the \
+ syntax with OID "%s" could not be parsed as a regex syntax because the provided \
+ regex pattern "%s" is invalid
+MILD_ERR_ATTR_SYNTAX_UNEXPECTED_CLOSE_PARENTHESIS=Unexpected closing \
+  parenthesis at position %d
+MILD_ERR_ATTR_SYNTAX_EXPECTED_QUOTE_AT_POS=A single quote was \
+  expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID=Non-numeric \
+  OID contained an illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_ILLEGAL_CHAR=Illegal character %s at position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_REQUIRED_ATTR=The provided value \
+ "%s" could not be parsed as a name form description because it does not \
+ specify a required naming attribute
+MILD_ERR_ATTR_SYNTAX_RULE_ID_NO_VALUE= The provided value could not \
+  be parsed as a valid rule ID because it did not contain any characters
+MILD_ERR_ATTR_SYNTAX_RULE_ID_INVALID=The value "%s" \
+  could not be parsed as a valid rule ID
+MILD_ERR_ATTR_SYNTAX_UNKNOWN_SUB_SYNTAX=The definition for the \
+ syntax with OID %s declared that it should have a substitution syntax with \
+ OID %s. No such syntax is defined
+MILD_WARN_ATTR_SYNTAX_NOT_IMPLEMENTED=The syntax with OID %s is not \
+ implemented. It will be substituted by the default syntax with OID %s
+MILD_WARN_MATCHING_RULE_NOT_IMPLEMENTED=The matching rule with OID %s is \
+  not implemented. It will be substituted by the default matching rule %s
+MILD_ERR_ATTR_SYNTAX_ILLEGAL_TOKEN=Illegal token %s
+MILD_ERR_ATTR_SYNTAX_TRUNCATED_VALUE=Unexpected end of value
+MILD_ERR_ATTR_SYNTAX_CYCLIC_SUB_SYNTAX=The definition for the \
+ syntax with OID %s declared a cyclic substitution.
+MILD_ERR_SCHEMA_REPLACE_CORE_ELEMENT=Unable to add schema element with \
+ OID %s because it conflicts with a core element %s
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE=The provided value \
+  "%s" cannot be parsed because it is not allowed by enumeration syntax \
+  with OID "%s"
+MILD_WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_DUPLICATE_VALUE=The provided value \
+  "%s" cannot be parsed as an enumeration syntax  because it contains a \
+  duplicate value "%s" at position %d
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_BAD_APPROXIMATE_MR=The definition for \
+ the attribute type with OID %s declared that approximate matching should be \
+ performed using the matching rule "%s".  This matching rule is defined in \
+ the schema, but it is not an approximate matching rule
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_BAD_EQUALITY_MR=The definition for \
+ the attribute type with OID %s declared that equality matching should be \
+ performed using the matching rule "%s".  This matching rule is defined in \
+ the schema, but it is not an equality matching rule
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_BAD_ORDERING_MR=The definition for \
+ the attribute type with OID %s declared that ordering matching should be \
+ performed using the matching rule "%s".  This matching rule is defined in \
+ the schema, but it is not an ordering matching rule
+SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_BAD_SUBSTRING_MR=The definition for \
+ the attribute type with OID %s declared that substring matching should be \
+ performed using the matching rule "%s".  This matching rule is defined in \
+ the schema, but it is not an substring matching rule
+MILD_ERR_ATTR_SYNTAX_EMPTY_VALUE=The provided value could not be \
+ parsed because it was empty or contained only whitespace
+MILD_ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS=The provided value \
+ "%s" could not be parsed because an open parenthesis was expected at \
+ position %d but instead a '%s' character was found
+SEVERE_WARN_ATTR_TYPE_UNKNOWN=No attribute type with name or \
+  OID "%s" exists in the schema
+SEVERE_WARN_OBJECTCLASS_UNKNOWN=No object class with name or \
+  OID "%s" exists in the schema
+SEVERE_WARN_MR_UNKNOWN=No matching rule with name or \
+  OID "%s" exists in the schema
+SEVERE_WARN_MRU_UNKNOWN=No matching rule use with name or \
+  OID "%s" exists in the schema
+SEVERE_WARN_DCR_UNKNOWN=No DIT content rule with name or \
+  OID "%s" exists in the schema
+SEVERE_WARN_DSR_UNKNOWN=No DIT structure rule with ID "%s" exists \
+  in the schema
+SEVERE_WARN_NAMEFORM_UNKNOWN=No name form with name or \
+  OID "%s" exists in the schema
+SEVERE_WARN_SYNTAX_UNKNOWN=No syntax with OID "%s" exists in the \
+  schema
+SEVERE_WARN_ATTR_TYPE_AMBIGIOUS=Multiple attribute types with name %s \
+  exists in the schema
+SEVERE_WARN_OBJECTCLASS_AMBIGIOUS=Multiple object classes with name \
+  %s exists in the schema
+SEVERE_WARN_MR_AMBIGIOUS=Multiple matching rules with name %s \
+  exists in the schema
+SEVERE_WARN_MRU_AMBIGIOUS=Multiple matching rule uses with name %s \
+  exists in the schema
+SEVERE_WARN_DCR_AMBIGIOUS=Multiple DIT content rules with name %s \
+  exists in the schema
+SEVERE_WARN_NAMEFORM_AMBIGIOUS=Multiple name forms with name %s \
+  exists in the schema
+SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_NO_WILDCARDS=The provided \
+ value "%s" could not be parsed as a substring assertion because it does not \
+ contain any wildcard characters
+SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_EMPTY=The provided value \
+ could not be parsed as a substring assertion because it is zero-length
+SEVERE_ERR_SYNTAX_VALIDATION_FAIL=Validation of syntax definition %s \
+ failed and will be removed from the schema: %s
+SEVERE_ERR_OC_VALIDATION_FAIL=Validation of object class definition %s \
+ failed and will be removed from the schema: %s
+SEVERE_ERR_ATTR_TYPE_VALIDATION_FAIL=Validation of attribute type \
+ definition %s failed and will be removed from the schema: %s
+SEVERE_ERR_MR_VALIDATION_FAIL=Validation of matching rule definition %s \
+ failed and will be removed from the schema: %s
+SEVERE_ERR_MRU_VALIDATION_FAIL=Validation of matching rule use definition \
+ %s failed and will be removed from the schema: %s
+SEVERE_ERR_DCR_VALIDATION_FAIL=Validation of DIT content rule definition \
+ %s failed and will be removed from the schema: %s
+SEVERE_ERR_DSR_VALIDATION_FAIL=Validation of DIT structure rule definition \
+ %s failed and will be removed from the schema: %s
+SEVERE_ERR_NAMEFORM_VALIDATION_FAIL=Validation of name form definition %s \
+ failed and will be removed from the schema: %s
+SEVERE_ERR_NO_SUBSCHEMA_SUBENTRY_ATTR=The entry %s does not include \
+ a subschemaSubentry attribute 
+MILD_ERR_ATTRIBUTE_DESCRIPTION_TYPE_NOT_FOUND=The attribute description "%s" \
+ could not be parsed due to the following reason: %s
+MILD_ERR_RDN_TYPE_NOT_FOUND=The RDN "%s" could not be parsed due to the \
+ following reason: %s
+MILD_ERR_DN_TYPE_NOT_FOUND=The DN "%s" could not be parsed due to the \
+ following reason: %s
+MILD_ERR_ATTRIBUTE_DESCRIPTION_EMPTY=The attribute description \
+ "%s" could not be parsed because it was empty
+MILD_ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER=The attribute description \
+ "%s" could not be parsed because it contains an invalid character "%c" at \
+ position %d
+MILD_ERR_ATTRIBUTE_DESCRIPTION_NO_TYPE=The attribute description \
+ "%s" could not be parsed because it does not contain an attribute type name
+MILD_ERR_ATTRIBUTE_DESCRIPTION_EMPTY_OPTION=The attribute description \
+ "%s" could not be parsed because it contains a zero length option
+MILD_ERR_ATTRIBUTE_DESCRIPTION_INTERNAL_WHITESPACE=The attribute \
+ description "%s" could not be parsed because it contains internal white space
+SEVERE_ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR=The entry %s includes \
+ a subschemaSubentry attribute but it contains an invalid distinguished \
+ name "%s": %s
+MILD_WARN_ATTR_TYPE_NOT_DEFINED=The definition for the \
+ attribute type with OID %s declared that it should have a syntax \
+ with OID %s which is is not defined in the schema. The missing syntax \
+ will be substituted by the core schema syntax: %s
+#
+# Core messages
+#
+MILD_ERR_SCHEMA_CONFLICTING_ATTRIBUTE_OID=Unable to register attribute \
+ type %s with the server schema because its OID %s conflicts with the OID of \
+ an existing attribute type %s
+MILD_ERR_SCHEMA_CONFLICTING_ATTRIBUTE_NAME=Unable to register attribute \
+ type %s with the server schema because its name %s conflicts with the name of \
+ an existing attribute type %s
+MILD_ERR_SCHEMA_CONFLICTING_OBJECTCLASS_OID=Unable to register \
+ objectclass %s with the server schema because its OID %s conflicts with the \
+ OID of an existing objectclass %s
+MILD_ERR_SCHEMA_CONFLICTING_OBJECTCLASS_NAME=Unable to register \
+ objectclass %s with the server schema because its name %s conflicts with the \
+ name of an existing objectclass %s
+MILD_ERR_SCHEMA_CONFLICTING_SYNTAX_OID=Unable to register attribute \
+ syntax %s with the server schema because its OID %s conflicts with the OID of \
+ an existing syntax %s
+MILD_ERR_SCHEMA_CONFLICTING_MR_OID=Unable to register matching rule %s \
+ with the server schema because its OID %s conflicts with the OID of an \
+ existing matching rule %s
+MILD_ERR_SCHEMA_CONFLICTING_MR_NAME=Unable to register matching rule %s \
+ with the server schema because its name %s conflicts with the name of an \
+ existing matching rule %s
+MILD_ERR_SCHEMA_CONFLICTING_MATCHING_RULE_USE=Unable to register matching \
+ rule use %s with the server schema because its matching rule %s conflicts \
+ with the matching rule for an existing matching rule use %s
+MILD_ERR_SCHEMA_CONFLICTING_DIT_CONTENT_RULE=Unable to register DIT \
+ content rule %s with the server schema because its structural objectclass %s \
+ conflicts with the structural objectclass for an existing DIT content rule %s
+MILD_ERR_SCHEMA_CONFLICTING_DIT_STRUCTURE_RULE_NAME_FORM=Unable to \
+ register DIT structure rule %s with the server schema because its name form \
+ %s conflicts with the name form for an existing DIT structure rule %s
+MILD_ERR_SCHEMA_CONFLICTING_DIT_STRUCTURE_RULE_ID=Unable to register DIT \
+ structure rule %s with the server schema because its rule ID %d conflicts \
+ with the rule ID for an existing DIT structure rule %s
+MILD_ERR_SCHEMA_CONFLICTING_NAME_FORM_OC=Unable to register name form %s \
+ with the server schema because its structural objectclass %s conflicts with \
+ the structural objectclass for an existing name form %s
+MILD_ERR_SCHEMA_CONFLICTING_NAME_FORM_OID=Unable to register name form %s \
+ with the server schema because its OID %s conflicts with the OID for an \
+ existing name form %s
+MILD_ERR_SCHEMA_CONFLICTING_NAME_FORM_NAME=Unable to register name form \
+ %s with the server schema because its name %s conflicts with the name for an \
+ existing name form %s
+INFO_RESULT_SUCCESS=Success
+INFO_RESULT_OPERATIONS_ERROR=Operations Error
+INFO_RESULT_PROTOCOL_ERROR=Protocol Error
+INFO_RESULT_TIME_LIMIT_EXCEEDED=Time Limit Exceeded
+INFO_RESULT_SIZE_LIMIT_EXCEEDED=Size Limit Exceeded
+INFO_RESULT_COMPARE_FALSE=Compare False
+INFO_RESULT_COMPARE_TRUE=Compare True
+INFO_RESULT_AUTH_METHOD_NOT_SUPPORTED=Authentication Method Not Supported
+INFO_RESULT_STRONG_AUTH_REQUIRED=Strong Authentication Required
+INFO_RESULT_REFERRAL=Referral
+INFO_RESULT_ADMIN_LIMIT_EXCEEDED=Administrative Limit Exceeded
+INFO_RESULT_UNAVAILABLE_CRITICAL_EXTENSION=Unavailable Critical Extension
+INFO_RESULT_CONFIDENTIALITY_REQUIRED=Confidentiality Required
+INFO_RESULT_SASL_BIND_IN_PROGRESS=SASL Bind in Progress
+INFO_RESULT_NO_SUCH_ATTRIBUTE=No Such Attribute
+INFO_RESULT_UNDEFINED_ATTRIBUTE_TYPE=Undefined Attribute Type
+INFO_RESULT_INAPPROPRIATE_MATCHING=Inappropriate Matching
+INFO_RESULT_CONSTRAINT_VIOLATION=Constraint Violation
+INFO_RESULT_ATTRIBUTE_OR_VALUE_EXISTS=Attribute or Value Exists
+INFO_RESULT_INVALID_ATTRIBUTE_SYNTAX=Invalid Attribute Syntax
+INFO_RESULT_NO_SUCH_OBJECT=No Such Entry
+INFO_RESULT_ALIAS_PROBLEM=Alias Problem
+INFO_RESULT_INVALID_DN_SYNTAX=Invalid DN Syntax
+INFO_RESULT_ALIAS_DEREFERENCING_PROBLEM=Alias Dereferencing Problem
+INFO_RESULT_INAPPROPRIATE_AUTHENTICATION=Inappropriate Authentication
+INFO_RESULT_INVALID_CREDENTIALS=Invalid Credentials
+INFO_RESULT_INSUFFICIENT_ACCESS_RIGHTS=Insufficient Access Rights
+INFO_RESULT_BUSY=Busy
+INFO_RESULT_UNAVAILABLE=Unavailable
+INFO_RESULT_UNWILLING_TO_PERFORM=Unwilling to Perform
+INFO_RESULT_LOOP_DETECT=Loop Detected
+INFO_RESULT_NAMING_VIOLATION=Naming Violation
+INFO_RESULT_OBJECTCLASS_VIOLATION=Object Class Violation
+INFO_RESULT_NOT_ALLOWED_ON_NONLEAF=Not Allowed on Non-Leaf
+INFO_RESULT_NOT_ALLOWED_ON_RDN=Not Allowed on RDN
+INFO_RESULT_ENTRY_ALREADY_EXISTS=Entry Already Exists
+INFO_RESULT_OBJECTCLASS_MODS_PROHIBITED=Object Class Modifications \
+ Prohibited
+INFO_RESULT_AFFECTS_MULTIPLE_DSAS=Affects Multiple DSAs
+INFO_RESULT_CANCELED=Canceled
+INFO_RESULT_NO_SUCH_OPERATION=No Such Operation
+INFO_RESULT_TOO_LATE=Too Late
+INFO_RESULT_CANNOT_CANCEL=Cannot Cancel
+INFO_RESULT_OTHER=Other
+INFO_RESULT_CLIENT_SIDE_SERVER_DOWN=Server Connection Closed
+INFO_RESULT_CLIENT_SIDE_LOCAL_ERROR=Local Error
+INFO_RESULT_CLIENT_SIDE_ENCODING_ERROR=Encoding Error
+INFO_RESULT_CLIENT_SIDE_DECODING_ERROR=Decoding Error
+INFO_RESULT_CLIENT_SIDE_TIMEOUT=Client-Side Timeout
+INFO_RESULT_CLIENT_SIDE_AUTH_UNKNOWN=Unknown Authentication Mechanism
+INFO_RESULT_CLIENT_SIDE_FILTER_ERROR=Filter Error
+INFO_RESULT_CLIENT_SIDE_USER_CANCELLED=Cancelled by User
+INFO_RESULT_CLIENT_SIDE_PARAM_ERROR=Parameter Error
+INFO_RESULT_CLIENT_SIDE_NO_MEMORY=Out of Memory
+INFO_RESULT_CLIENT_SIDE_CONNECT_ERROR=Connect Error
+INFO_RESULT_CLIENT_SIDE_NOT_SUPPORTED=Operation Not Supported
+INFO_RESULT_CLIENT_SIDE_CONTROL_NOT_FOUND=Control Not Found
+INFO_RESULT_CLIENT_SIDE_NO_RESULTS_RETURNED=No Results Returned
+INFO_RESULT_CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED=Unexpected Results Returned
+INFO_RESULT_CLIENT_SIDE_CLIENT_LOOP=Referral Loop Detected
+INFO_RESULT_CLIENT_SIDE_REFERRAL_LIMIT_EXCEEDED=Referral Hop Limit Exceeded
+INFO_RESULT_AUTHORIZATION_DENIED=Authorization Denied
+INFO_RESULT_ASSERTION_FAILED=Assertion Failed
+INFO_RESULT_SORT_CONTROL_MISSING=Sort Control Missing
+INFO_RESULT_OFFSET_RANGE_ERROR=Offset Range Error
+INFO_RESULT_VIRTUAL_LIST_VIEW_ERROR=Virtual List View Error
+INFO_RESULT_NO_OPERATION=No Operation
+#
+# Protocol messages
+#
+MILD_ERR_ASN1_TRUCATED_TYPE_BYTE=Cannot decode the ASN.1 element because an \
+ unexpected end of file was reached while reading the type byte
+MILD_ERR_ASN1_TRUNCATED_LENGTH_BYTE=Cannot decode the ASN.1 element because \
+ an unexpected end of file was reached while reading the first length byte
+MILD_ERR_ASN1_INVALID_NUM_LENGTH_BYTES=Cannot decode the ASN.1 element \
+ because it contained a multi-byte length with an invalid number of bytes (%d)
+MILD_ERR_ASN1_TRUNCATED_LENGTH_BYTES=Cannot decode the ASN.1 element because \
+ an unexpected end of file was reached while reading a multi-byte length of \
+ %d bytes
+MILD_ERR_ASN1_BOOLEAN_TRUNCATED_VALUE=Cannot decode the ASN.1 boolean \
+ element of because an unexpected end of file was reached while reading value \
+ bytes (%d)
+MILD_ERR_ASN1_BOOLEAN_INVALID_LENGTH=Cannot decode the ASN.1 \
+ boolean element because the decoded value length was not exactly one byte \
+ (decoded length was %d)
+MILD_ERR_ASN1_NULL_TRUNCATED_VALUE=Cannot decode the ASN.1 null \
+ element of because an unexpected end of file was reached while reading value \
+ bytes (%d)
+MILD_ERR_ASN1_NULL_INVALID_LENGTH=Cannot decode the ASN.1 null element \
+ because the decoded value length was not exactly zero bytes \
+ (decoded length was %d)
+MILD_ERR_ASN1_OCTET_STRING_TRUNCATED_VALUE=Cannot decode the ASN.1 octet \
+ string element of because an unexpected end of file was reached while reading \
+ value bytes (%d)
+MILD_ERR_ASN1_INTEGER_TRUNCATED_VALUE=Cannot decode the ASN.1 integer \
+ element of because an unexpected end of file was reached while reading \
+ value bytes (%d)
+MILD_ERR_ASN1_INTEGER_INVALID_LENGTH=Cannot decode the \
+ provided ASN.1 integer element because the length of the \
+ element value was not between one and four bytes (actual length was %d)
+MILD_ERR_ASN1_SEQUENCE_READ_NOT_STARTED=Cannot decode the end of the ASN.1 \
+ sequence or set because the start of the sequence was not read
+MILD_ERR_ASN1_SEQUENCE_READ_NOT_ENDED=Cannot decode the end of the ASN.1 \
+ sequence or set because %d bytes are not read from the sequence of %d bytes \
+ in length
+MILD_ERR_ASN1_SKIP_TRUNCATED_VALUE=Cannot skip the ASN.1 element of because \
+ an unexpected end of file was reached while reading value bytes (%d)
+MILD_ERR_ASN1_SEQUENCE_SET_TRUNCATED_VALUE=Cannot decode the ASN.1 sequence \
+ or set element of because an unexpected end of file was reached while reading \
+ value bytes (%d)
+MILD_ERR_LDAP_MESSAGE_DECODE_NULL=Cannot decode the provided ASN.1 \
+ sequence as an LDAP message because the sequence was null
+MILD_ERR_LDAP_MESSAGE_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 sequence as an LDAP message because the sequence contained an \
+ invalid number of elements (expected 2 or 3, got %d)
+MILD_ERR_LDAP_MESSAGE_DECODE_MESSAGE_ID=Cannot decode the provided ASN.1 \
+ sequence as an LDAP message because the first element of the sequence could \
+ not be decoded as an integer message ID:  %s
+MILD_ERR_LDAP_MESSAGE_DECODE_PROTOCOL_OP=Cannot decode the provided ASN.1 \
+ sequence as an LDAP message because the second element of the sequence could \
+ not be decoded as the protocol op:  %s
+MILD_ERR_LDAP_MESSAGE_DECODE_CONTROLS=Cannot decode the provided ASN.1 \
+ sequence as an LDAP message because the third element of the sequence could \
+ not be decoded as the set of controls:  %s
+MILD_ERR_LDAP_CONTROL_DECODE_NULL=Cannot decode the provided ASN.1 element \
+ as an LDAP control because the element was null
+MILD_ERR_LDAP_CONTROL_DECODE_SEQUENCE=Cannot decode the provided ASN.1 \
+ element as an LDAP control because the element could not be decoded as a \
+ sequence:  %s
+MILD_ERR_LDAP_CONTROL_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP control because the control sequence \
+ contained an invalid number of elements (expected 1 to 3, got %d)
+MILD_ERR_LDAP_CONTROL_DECODE_OID=Cannot decode the provided ASN.1 element \
+ as an LDAP control because the OID could not be decoded as a string:  %s
+MILD_ERR_LDAP_CONTROL_DECODE_CRITICALITY=Cannot decode the provided ASN.1 \
+ element as an LDAP control because the criticality could not be decoded as \
+ Boolean value:  %s
+MILD_ERR_LDAP_CONTROL_DECODE_VALUE=Cannot decode the provided ASN.1 \
+ element as an LDAP control because the value could not be decoded as an octet \
+ string:  %s
+MILD_ERR_LDAP_CONTROL_DECODE_INVALID_TYPE=Cannot decode the provided ASN.1 \
+ element as an LDAP control because the BER type for the second element in the \
+ sequence was invalid (expected 01 or 04, got %x)
+MILD_ERR_LDAP_CONTROL_DECODE_CONTROLS_NULL=Cannot decode the provided \
+ ASN.1 element as a set of LDAP controls because the element was null
+MILD_ERR_LDAP_CONTROL_DECODE_CONTROLS_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as a set of LDAP controls because the element could not be \
+ decoded as a sequence:  %s
+MILD_ERR_LDAP_ABANDON_REQUEST_DECODE_ID=Cannot decode the provided ASN.1 \
+ element as an LDAP abandon request protocol op because a problem occurred \
+ while trying to obtain the message ID of the operation to abandon:  %s
+MILD_ERR_LDAP_RESULT_DECODE_SEQUENCE=Cannot decode the provided ASN.1 \
+ element as an LDAP result protocol op because a problem occurred while trying \
+ to parse the result sequence:  %s
+MILD_ERR_LDAP_RESULT_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP result protocol op because the result \
+ sequence did not contain a valid number of elements (expected 3 or 4, got %d)
+MILD_ERR_LDAP_RESULT_DECODE_RESULT_CODE=Cannot decode the provided ASN.1 \
+ element as an LDAP result protocol op because the first element in the result \
+ sequence could not be decoded as an integer result code:  %s
+MILD_ERR_LDAP_RESULT_DECODE_MATCHED_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP result protocol op because the second element in the \
+ result sequence could not be decoded as the matched DN:  %s
+MILD_ERR_LDAP_RESULT_DECODE_ERROR_MESSAGE=Cannot decode the provided ASN.1 \
+ element as an LDAP result protocol op because the third element in the result \
+ sequence could not be decoded as the error message:  %s
+MILD_ERR_LDAP_RESULT_DECODE_REFERRALS=Cannot decode the provided ASN.1 \
+ element as an LDAP result protocol op because the fourth element in the \
+ result sequence could not be decoded as a set of referral URLs:  %s
+MILD_ERR_LDAP_BIND_RESULT_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP bind response protocol op because the \
+ result sequence did not contain a valid number of elements (expected 3 to 5, \
+ got %d)
+MILD_ERR_LDAP_BIND_RESULT_DECODE_SERVER_SASL_CREDENTIALS=Cannot decode the \
+ provided ASN.1 element as an LDAP bind response protocol op because the final \
+ element in the result sequence could not be decoded as the server SASL \
+ credentials:  %s
+MILD_ERR_LDAP_BIND_RESULT_DECODE_INVALID_TYPE=Cannot decode the provided \
+ ASN.1 element as an LDAP bind response protocol op because the BER type for \
+ the fourth element in the sequence was invalid (expected A3 or 87, got %x)
+MILD_ERR_LDAP_EXTENDED_RESULT_DECODE_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP bind response protocol op because the \
+ result sequence did not contain a valid number of elements (expected 3 to 6, \
+ got %d)
+MILD_ERR_LDAP_EXTENDED_RESULT_DECODE_REFERRALS=Cannot decode the provided \
+ ASN.1 element as an LDAP bind response protocol op because the set of \
+ referral URLs could not be decoded:  %s
+MILD_ERR_LDAP_EXTENDED_RESULT_DECODE_OID=Cannot decode the provided ASN.1 \
+ element as an LDAP bind response protocol op because the response OID could \
+ not be decoded:  %s
+MILD_ERR_LDAP_EXTENDED_RESULT_DECODE_VALUE=Cannot decode the provided \
+ ASN.1 element as an LDAP bind response protocol op because the response value \
+ could not be decoded:  %s
+MILD_ERR_LDAP_EXTENDED_RESULT_DECODE_INVALID_TYPE=Cannot decode the \
+ provided ASN.1 element as an LDAP extended response protocol op because one \
+ of the elements it contained had an invalid BER type (expected A3, 8A, or 8B, \
+ got %x)
+MILD_ERR_LDAP_UNBIND_DECODE=Cannot decode the provided ASN.1 element as an \
+ LDAP unbind request protocol op:  %s
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP bind request protocol op because the element could \
+ not be decoded as a sequence:  %s
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP bind request protocol op because the \
+ request sequence had an invalid number of elements (expected 3, got %d)
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_VERSION=Cannot decode the provided ASN.1 \
+ element as an LDAP bind request protocol op because the protocol version \
+ could not be decoded as an integer:  %s
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP bind request protocol op because the bind DN could not be \
+ properly decoded:  %s
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_PASSWORD=Cannot decode the provided \
+ ASN.1 element as an LDAP bind request protocol op because the password to use \
+ for simple authentication could not be decoded:  %s
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_SASL_INFO=Cannot decode the provided \
+ ASN.1 element as an LDAP bind request protocol op because the SASL \
+ authentication information could not be decoded:  %s
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_INVALID_CRED_TYPE=Cannot decode the \
+ provided ASN.1 element as an LDAP bind request protocol op because the \
+ authentication info element had an invalid BER type (expected 80 or A3, got \
+ %x)
+MILD_ERR_LDAP_BIND_REQUEST_DECODE_CREDENTIALS=Cannot decode the provided \
+ ASN.1 element as an LDAP bind request protocol op because an unexpected error \
+ occurred while trying to decode the authentication info element:  %s
+MILD_ERR_LDAP_COMPARE_REQUEST_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP compare request protocol op because the element \
+ could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_COMPARE_REQUEST_DECODE_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP compare request protocol op because the \
+ request sequence had an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_COMPARE_REQUEST_DECODE_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP compare request protocol op because the target DN could \
+ not be properly decoded:  %s
+MILD_ERR_LDAP_COMPARE_REQUEST_DECODE_AVA=Cannot decode the provided ASN.1 \
+ element as an LDAP compare request protocol op because the attribute value \
+ assertion could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_COMPARE_REQUEST_DECODE_AVA_COUNT=Cannot decode the provided \
+ ASN.1 element as an LDAP compare request protocol op because the attribute \
+ value assertion sequence had an invalid number of elements (expected 2, got \
+ %d)
+MILD_ERR_LDAP_COMPARE_REQUEST_DECODE_TYPE=Cannot decode the provided ASN.1 \
+ element as an LDAP compare request protocol op because the attribute type \
+ could not be properly decoded:  %s
+MILD_ERR_LDAP_COMPARE_REQUEST_DECODE_VALUE=Cannot decode the provided \
+ ASN.1 element as an LDAP compare request protocol op because the assertion \
+ value could not be properly decoded:  %s
+MILD_ERR_LDAP_DELETE_REQUEST_DECODE_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP delete request protocol op because the target DN could not \
+ be properly decoded:  %s
+MILD_ERR_LDAP_EXTENDED_REQUEST_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP extended request protocol op because the element \
+ could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_EXTENDED_REQUEST_DECODE_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP extended request protocol op because \
+ the request sequence had an invalid number of elements (expected 1 or 2, got \
+ %d)
+MILD_ERR_LDAP_EXTENDED_REQUEST_DECODE_OID=Cannot decode the provided ASN.1 \
+ element as an LDAP extended request protocol op because the OID could not be \
+ properly decoded:  %s
+MILD_ERR_LDAP_EXTENDED_REQUEST_DECODE_VALUE=Cannot decode the provided \
+ ASN.1 element as an LDAP extended request protocol op because the value could \
+ not be properly decoded:  %s
+MILD_ERR_LDAP_MODIFY_DN_REQUEST_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP modify DN request protocol op because the element \
+ could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_MODIFY_DN_REQUEST_DECODE_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP modify DN request protocol op because \
+ the request sequence had an invalid number of elements (expected 3 or 4, got \
+ %d)
+MILD_ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP modify DN request protocol op because the entry DN could \
+ not be properly decoded:  %s
+MILD_ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_RDN=Cannot decode the provided \
+ ASN.1 element as an LDAP modify DN request protocol op because the new RDN \
+ could not be properly decoded:  %s
+MILD_ERR_LDAP_MODIFY_DN_REQUEST_DECODE_DELETE_OLD_RDN=Cannot decode the \
+ provided ASN.1 element as an LDAP modify DN request protocol op because the \
+ deleteOldRDN flag could not be properly decoded:  %s
+MILD_ERR_LDAP_MODIFY_DN_REQUEST_DECODE_NEW_SUPERIOR=Cannot decode the \
+ provided ASN.1 element as an LDAP modify DN request protocol op because the \
+ new superior DN could not be properly decoded:  %s
+MILD_ERR_LDAP_ATTRIBUTE_DECODE_SEQUENCE=Cannot decode the provided ASN.1 \
+ element as an LDAP attribute because the element could not be decoded as a \
+ sequence:  %s
+MILD_ERR_LDAP_ATTRIBUTE_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP attribute because the request sequence had \
+ an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_ATTRIBUTE_DECODE_TYPE=Cannot decode the provided ASN.1 \
+ element as an LDAP attribute because the attribute type could not be decoded: \
+ %s
+MILD_ERR_LDAP_ATTRIBUTE_DECODE_VALUES=Cannot decode the provided ASN.1 \
+ element as an LDAP attribute because the set of values could not be decoded: \
+ %s
+MILD_ERR_LDAP_ADD_REQUEST_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP add request protocol op because the element could \
+ not be decoded as a sequence:  %s
+MILD_ERR_LDAP_ADD_REQUEST_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP add request protocol op because the request \
+ sequence had an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_ADD_REQUEST_DECODE_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP add request protocol op because the entry DN could not be \
+ decoded:  %s
+MILD_ERR_LDAP_ADD_REQUEST_DECODE_ATTRS=Cannot decode the provided ASN.1 \
+ element as an LDAP add request protocol op because the set of attributes \
+ could not be decoded:  %s
+MILD_ERR_LDAP_MODIFICATION_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP modification because the element could not be \
+ decoded as a sequence:  %s
+MILD_ERR_LDAP_MODIFICATION_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP modification because the request sequence \
+ had an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE=Cannot decode the \
+ provided ASN.1 element as an LDAP modification because it contained an \
+ invalid modification type (%d)
+MILD_ERR_LDAP_MODIFICATION_DECODE_MOD_TYPE=Cannot decode the provided \
+ ASN.1 element as an LDAP modification because the modification type could not \
+ be decoded:  %s
+MILD_ERR_LDAP_MODIFICATION_DECODE_ATTR=Cannot decode the provided ASN.1 \
+ element as an LDAP modification because the attribute could not be decoded: \
+ %s
+MILD_ERR_LDAP_MODIFY_REQUEST_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP modify request protocol op because the element could \
+ not be decoded as a sequence:  %s
+MILD_ERR_LDAP_MODIFY_REQUEST_DECODE_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP modify request protocol op because the \
+ request sequence had an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_MODIFY_REQUEST_DECODE_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP modify request protocol op because the entry DN could not \
+ be decoded:  %s
+MILD_ERR_LDAP_MODIFY_REQUEST_DECODE_MODS=Cannot decode the provided ASN.1 \
+ element as an LDAP modify request protocol op because the set of \
+ modifications could not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_ENTRY_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP search result entry protocol op because the element \
+ could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_SEARCH_ENTRY_DECODE_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP search result entry protocol op because the \
+ request sequence had an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_SEARCH_ENTRY_DECODE_DN=Cannot decode the provided ASN.1 \
+ element as an LDAP search result entry protocol op because the entry DN could \
+ not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_ENTRY_DECODE_ATTRS=Cannot decode the provided ASN.1 \
+ element as an LDAP search result entry protocol op because the set of \
+ attributes could not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REFERENCE_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP search result reference protocol op because the \
+ element could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_SEARCH_REFERENCE_DECODE_URLS=Cannot decode the provided \
+ ASN.1 element as an LDAP search result reference protocol op because a \
+ problem occurred while trying to decode the sequence elements as referral \
+ URLs:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the element could \
+ not be decoded as a sequence:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP search request protocol op because the \
+ request sequence had an invalid number of elements (expected 8, got %d)
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_BASE=Cannot decode the provided ASN.1 \
+ element as an LDAP search request protocol op because the base DN could not \
+ be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE=Cannot decode the \
+ provided ASN.1 element as an LDAP search request protocol op because the \
+ provided scope value (%d) is invalid
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_SCOPE=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the scope could \
+ not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF=Cannot decode the \
+ provided ASN.1 element as an LDAP search request protocol op because the \
+ provided alias dereferencing policy value (%d) is invalid
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_DEREF=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the alias \
+ dereferencing policy could not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_SIZE_LIMIT=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the size limit \
+ could not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_TIME_LIMIT=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the time limit \
+ could not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_TYPES_ONLY=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the typesOnly \
+ flag could not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_FILTER=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the filter could \
+ not be decoded:  %s
+MILD_ERR_LDAP_SEARCH_REQUEST_DECODE_ATTRIBUTES=Cannot decode the provided \
+ ASN.1 element as an LDAP search request protocol op because the requested \
+ attribute set could not be decoded:  %s
+MILD_ERR_LDAP_PROTOCOL_OP_DECODE_NULL=Cannot decode the provided ASN.1 \
+ element as an LDAP protocol op because the element was null
+MILD_ERR_LDAP_PROTOCOL_OP_DECODE_INVALID_TYPE=Cannot decode the provided \
+ ASN.1 element as an LDAP protocol op because the element had an invalid BER \
+ type (%x) for an LDAP protocol op
+MILD_ERR_LDAP_FILTER_DECODE_NULL=Cannot decode the provided ASN.1 element \
+ as an LDAP search filter because the element was null
+MILD_ERR_LDAP_FILTER_DECODE_INVALID_TYPE=Cannot decode the provided ASN.1 \
+ element as an LDAP search filter because the element had an invalid BER type \
+ (%x) for a search filter
+MILD_ERR_LDAP_FILTER_DECODE_COMPOUND_SET=Cannot decode the provided ASN.1 \
+ element as an LDAP search filter because the compound filter set could not be \
+ decoded:  %s
+MILD_ERR_LDAP_FILTER_DECODE_COMPOUND_COMPONENTS=Cannot decode the \
+ provided ASN.1 element as an LDAP search filter because an unexpected error \
+ occurred while trying to decode one of the compound filter components:  %s
+MILD_ERR_LDAP_FILTER_DECODE_NOT_ELEMENT=Cannot decode the provided ASN.1 \
+ element as an LDAP search filter because the value of the element cannot \
+ itself be decoded as an ASN.1 element for a NOT filter component:  %s
+MILD_ERR_LDAP_FILTER_DECODE_NOT_COMPONENT=Cannot decode the provided \
+ ASN.1 element as an LDAP search filter because the NOT component element \
+ could not be decoded as an LDAP filter:  %s
+MILD_ERR_LDAP_FILTER_DECODE_TV_SEQUENCE=Cannot decode the provided ASN.1 \
+ element as an LDAP search filter because the element could not be decoded as \
+ a type-and-value sequence:  %s
+MILD_ERR_LDAP_FILTER_DECODE_TV_INVALID_ELEMENT_COUNT=Cannot decode the \
+ provided ASN.1 element as an LDAP search filter because the type-and-value \
+ sequence had an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_FILTER_DECODE_TV_TYPE=Cannot decode the provided ASN.1 \
+ element as an LDAP search filter because the attribute type could not be \
+ decoded from the type-and-value sequence:  %s
+MILD_ERR_LDAP_FILTER_DECODE_TV_VALUE=Cannot decode the provided ASN.1 \
+ element as an LDAP search filter because the assertion value could not be \
+ decoded from the type-and-value sequence:  %s
+MILD_ERR_LDAP_FILTER_DECODE_SUBSTRING_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP search filter because the element could not be \
+ decoded as a substring sequence:  %s
+MILD_ERR_LDAP_FILTER_DECODE_SUBSTRING_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP search filter because the substring \
+ sequence had an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_FILTER_DECODE_SUBSTRING_TYPE=Cannot decode the provided \
+ ASN.1 element as an LDAP search filter because the attribute type could not \
+ be decoded from the substring sequence:  %s
+MILD_ERR_LDAP_FILTER_DECODE_SUBSTRING_ELEMENTS=Cannot decode the provided \
+ ASN.1 element as an LDAP search filter because the substring value sequence \
+ could not be decoded:  %s
+MILD_ERR_LDAP_FILTER_DECODE_SUBSTRING_NO_SUBELEMENTS=Cannot decode the \
+ provided ASN.1 element as an LDAP search filter because the substring value \
+ sequence did not contain any elements
+MILD_ERR_LDAP_FILTER_DECODE_SUBSTRING_INVALID_SUBTYPE=Cannot decode the \
+ provided ASN.1 element as an LDAP search filter because the substring value \
+ sequence had an element with an invalid BER type (%x)
+MILD_ERR_LDAP_FILTER_DECODE_SUBSTRING_VALUES=Cannot decode the provided \
+ ASN.1 element as an LDAP search filter because a problem occurred while \
+ trying to parse the substring value elements:  %s
+MILD_ERR_LDAP_FILTER_DECODE_PRESENCE_TYPE=Cannot decode the provided \
+ ASN.1 element as an LDAP search filter because the element could not be \
+ decoded as the presence attribute type:  %s
+MILD_ERR_LDAP_FILTER_DECODE_EXTENSIBLE_SEQUENCE=Cannot decode the \
+ provided ASN.1 element as an LDAP search filter because the element could not \
+ be decoded as an extensible matching sequence:  %s
+MILD_ERR_LDAP_FILTER_DECODE_EXTENSIBLE_INVALID_TYPE=Cannot decode the \
+ provided ASN.1 element as an LDAP search filter because the extensible \
+ matching sequence had an element with an invalid BER type (%x)
+MILD_ERR_LDAP_FILTER_DECODE_EXTENSIBLE_ELEMENTS=Cannot decode the \
+ provided ASN.1 element as an LDAP search filter because a problem occurred \
+ while trying to parse the extensible match sequence elements:  %s
+MILD_ERR_LDAP_CLIENT_SEND_RESPONSE_NO_RESULT_CODE=The server attempted to \
+ send a response to the %s operation (conn=%d, op=%d), but the operation did \
+ not have a result code.  This could indicate that the operation did not \
+ complete properly or that it is one that is not allowed to have a response. \
+ Using a generic 'Operations Error' response
+MILD_ERR_LDAP_CLIENT_SEND_RESPONSE_INVALID_OP=The server attempted to \
+ send a response to the %s operation (conn=%d, op=%d), but this type of \
+ operation is not allowed to have responses.  Backtrace:  %s
+MILD_ERR_LDAP_CLIENT_SEND_MESSAGE_ENCODE_ASN1=The server was unable to \
+ encode the provided LDAP message %s (conn=%d, op=%d) into an ASN.1 element: \
+ %s
+MILD_ERR_LDAP_CLIENT_SEND_MESSAGE_ENCODE_BYTES=The server was unable to \
+ encode the ASN.1 element generated from LDAP message %s (conn=%d, op=%d) into \
+ a byte array:  %s
+MILD_ERR_LDAP_CLIENT_SEND_MESSAGE_IO_PROBLEM=The server was unable to \
+ send the LDAP message %s (conn=%d, op=%d) to the client because an I/O \
+ problem was encountered:  %s
+MILD_ERR_LDAP_CLIENT_SEND_MESSAGE_UNEXPECTED_PROBLEM=The server was \
+ unable to send the LDAP message %s (conn=%d, op=%d) to the client because an \
+ unexpected problem was encountered:  %s
+INFO_LDAP_CLIENT_GENERIC_NOTICE_OF_DISCONNECTION=The Directory Server is \
+ closing the connection to this client
+MILD_WARN_LDAP_CLIENT_DISCONNECT_IN_PROGRESS=The Directory Server is \
+ currently in the process of closing this client connection
+MILD_ERR_LDAP_CLIENT_DECODE_ZERO_BYTE_VALUE=The client sent a request to \
+ the Directory Server that was an ASN.1 element with a zero-byte value.  This \
+ cannot possibly be a valid LDAP message
+MILD_ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED=The client sent a \
+ request to the Directory Server with an ASN.1 element value length of %d \
+ bytes.  This exceeds the maximum allowed request size of %d bytes, so \
+ processing cannot continue on this connection
+MILD_ERR_LDAP_CLIENT_DECODE_INVALID_MULTIBYTE_LENGTH=The client sent a \
+ request to the Directory Server with an ASN.1 element using multiple bytes to \
+ express the value length.  The request indicated that %d bytes were needed to \
+ express the length, but this exceeds the maximum allowed limit of four bytes
+MILD_ERR_LDAP_CLIENT_DECODE_ASN1_FAILED=The client sent a request to the \
+ Directory Server that could not be properly decoded as an ASN.1 element:  %s
+MILD_ERR_LDAP_CLIENT_DECODE_LDAP_MESSAGE_FAILED=The client sent a request \
+ to the Directory Server that could not be properly decoded as an LDAP \
+ message:  %s
+SEVERE_ERR_LDAP_CLIENT_INVALID_DECODE_STATE=An internal error has \
+ occurred within the Directory Server to cause it to lose track of where it is \
+ in decoding requests on this client connection.  It had an invalid decode \
+ state of %d, and this connection must be terminated
+MILD_ERR_LDAP_CLIENT_DECODE_INVALID_REQUEST_TYPE=The client sent an LDAP \
+ message to the Directory Server that was not a valid message for a client \
+ request:  %s
+MILD_ERR_LDAP_CLIENT_CANNOT_CONVERT_MESSAGE_TO_OPERATION=The Directory \
+ Server was unable to convert the LDAP message read from the client (%s) to an \
+ internal operation for processing:  %s
+MILD_ERR_LDAP_ABANDON_INVALID_MESSAGE_TYPE=Cannot convert the provided \
+ LDAP message (%s) to an abandon operation:  %s
+MILD_ERR_LDAP_UNBIND_INVALID_MESSAGE_TYPE=Cannot convert the provided \
+ LDAP message (%s) to an unbind operation:  %s
+FATAL_ERR_LDAP_CONNHANDLER_OPEN_SELECTOR_FAILED=The LDAP connection \
+ handler defined in configuration entry %s was unable to open a selector to \
+ allow it to multiplex the associated accept sockets:  %s.  This connection \
+ handler will be disabled
+SEVERE_ERR_LDAP_CONNHANDLER_CREATE_CHANNEL_FAILED=The LDAP connection \
+ handler defined in configuration entry %s was unable to create a server \
+ socket channel to accept connections on %s:%d:  %s.  The Directory Server \
+ will not listen for new connections on that address
+FATAL_ERR_LDAP_CONNHANDLER_NO_ACCEPTORS=The LDAP connection handler \
+ defined in configuration entry %s was unable to create any of the socket \
+ channels on any of the configured addresses.  This connection handler will be \
+ disabled
+MILD_ERR_LDAP_CONNHANDLER_DENIED_CLIENT=The connection attempt from \
+ client %s to %s has been rejected because the client was included in one of \
+ the denied address ranges
+MILD_ERR_LDAP_CONNHANDLER_DISALLOWED_CLIENT=The connection attempt from \
+ client %s to %s has been rejected because the client was not included in one \
+ of the allowed address ranges
+INFO_LDAP_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT=An internal error \
+ prevented the Directory Server from properly registering the client \
+ connection from %s to %s with an appropriate request handler:  %s
+MILD_ERR_LDAP_CONNHANDLER_CANNOT_ACCEPT_CONNECTION=The LDAP connection \
+ handler defined in configuration entry %s was unable to accept a new client \
+ connection:  %s
+FATAL_ERR_LDAP_CONNHANDLER_CONSECUTIVE_ACCEPT_FAILURES=The LDAP \
+ connection handler defined in configuration entry %s has experienced \
+ consecutive failures while trying to accept client connections:  %s.  This \
+ connection handler will be disabled
+FATAL_ERR_LDAP_CONNHANDLER_UNCAUGHT_ERROR=The LDAP connection handler \
+ defined in configuration entry %s caught an unexpected error while trying to \
+ listen for new connections:  %s.  This connection handler will be disabled
+FATAL_ERR_LDAP_REQHANDLER_OPEN_SELECTOR_FAILED=%s was unable to open a \
+ selector to multiplex reads from clients:  %s.  This request handler cannot \
+ continue processing
+FATAL_ERR_LDAP_REQHANDLER_CANNOT_REGISTER=%s was unable to register this \
+ client connection with the selector:  %s
+FATAL_ERR_LDAP_REQHANDLER_REJECT_DUE_TO_SHUTDOWN=This connection could \
+ not be registered with a request handler because the Directory Server is \
+ shutting down
+FATAL_ERR_LDAP_REQHANDLER_REJECT_DUE_TO_QUEUE_FULL=This connection could \
+ not be registered with a request handler because the pending queue associated \
+ with %s is too full
+FATAL_ERR_LDAP_REQHANDLER_DEREGISTER_DUE_TO_SHUTDOWN=This client \
+ connection is being deregistered from the associated request handler because \
+ the Directory Server is shutting down
+MILD_ERR_ASN1_READER_MAX_SIZE_EXCEEDED=Cannot decode the data read as an \
+ ASN.1 element because the decoded element length of %d bytes was larger than \
+ the maximum allowed element length of %d bytes.  The underlying input stream \
+ has been closed and this reader can no longer be used
+MILD_ERR_LDAP_FILTER_STRING_NULL=Cannot decode the provided string as an \
+ LDAP search filter because the string was null
+MILD_ERR_LDAP_FILTER_UNCAUGHT_EXCEPTION=Cannot decode the provided string \
+ %s as an LDAP search filter because an unexpected exception was thrown during \
+ processing:  %s
+MILD_ERR_LDAP_FILTER_MISMATCHED_PARENTHESES=The provided search filter \
+ "%s" had mismatched parentheses around the portion between positions %d and \
+ %d
+MILD_ERR_LDAP_FILTER_NO_EQUAL_SIGN=The provided search filter "%s" was \
+ missing an equal sign in the suspected simple filter component between \
+ positions %d and %d
+MILD_ERR_LDAP_FILTER_INVALID_ESCAPED_BYTE=The provided search filter "%s" \
+ had an invalid escaped byte value at position %d.  A backslash in a value \
+ must be followed by two hexadecimal characters that define the byte that has \
+ been encoded
+MILD_ERR_LDAP_FILTER_COMPOUND_MISSING_PARENTHESES=The provided search \
+ filter "%s" could not be decoded because the compound filter between \
+ positions %d and %d did not start with an open parenthesis and end with a \
+ close parenthesis (they might be parentheses for different filter components)
+MILD_ERR_LDAP_FILTER_NO_CORRESPONDING_OPEN_PARENTHESIS=The provided \
+ search filter "%s" could not be decoded because the closing parenthesis at \
+ position %d did not have a corresponding open parenthesis
+MILD_ERR_LDAP_FILTER_NO_CORRESPONDING_CLOSE_PARENTHESIS=The provided \
+ search filter "%s" could not be decoded because the opening parenthesis at \
+ position %d did not have a corresponding close parenthesis
+MILD_ERR_LDAP_FILTER_SUBSTRING_NO_ASTERISKS=The provided search filter \
+ "%s" could not be decoded because the assumed substring filter value between \
+ positions %d and %d did not have any asterisk wildcard characters
+MILD_ERR_LDAP_FILTER_EXTENSIBLE_MATCH_NO_COLON=The provided search filter \
+ "%s" could not be decoded because the extensible match component starting at \
+ position %d did not have a colon to denote the end of the attribute type name
+MILD_ERR_LDAP_DISCONNECT_DUE_TO_INVALID_REQUEST_TYPE=Terminating this \
+ connection because the client sent an invalid message of type %s (LDAP \
+ message ID %d) that is not allowed for request messages
+SEVERE_ERR_LDAP_DISCONNECT_DUE_TO_PROCESSING_FAILURE=An unexpected \
+ failure occurred while trying to process a request of type %s (LDAP message \
+ ID %d):  %s.  The client connection will be terminated
+MILD_ERR_LDAP_INVALID_BIND_AUTH_TYPE=The bind request message (LDAP \
+ message ID %d) included an invalid authentication type of %s.  This is a \
+ protocol error, and this connection will be terminated as per RFC 2251 \
+ section 4.2.3
+MILD_ERR_LDAP_DISCONNECT_DUE_TO_BIND_PROTOCOL_ERROR=This client \
+ connection is being terminated because a protocol error occurred while trying \
+ to process a bind request.  The LDAP message ID was %d and the error message \
+ for the bind response was %s
+MILD_ERR_LDAPV2_SKIPPING_EXTENDED_RESPONSE=An extended response message \
+ would have been sent to an LDAPv2 client (connection ID=%d, operation ID=%d): \
+ %s.  LDAPv2 does not allow extended operations, so this response will not be \
+ sent
+MILD_ERR_LDAPV2_SKIPPING_SEARCH_REFERENCE=A search performed by an LDAPv2 \
+ client (connection ID=%d, operation ID=%d) would have included a search \
+ result reference %s.  Referrals are not allowed for LDAPv2 clients, so this \
+ search reference will not be sent
+MILD_ERR_LDAPV2_REFERRAL_RESULT_CHANGED=The original result code for this \
+ message was 10 but this result is not allowed for LDAPv2 clients
+MILD_ERR_LDAPV2_REFERRALS_OMITTED=The response included one or more \
+ referrals, which are not allowed for LDAPv2 clients.  The referrals included \
+ were:  %s
+MILD_ERR_LDAPV2_CLIENTS_NOT_ALLOWED=The Directory Server has been \
+ configured to deny access to LDAPv2 clients.  This connection will be closed
+MILD_ERR_LDAPV2_EXTENDED_REQUEST_NOT_ALLOWED=The client with connection \
+ ID %d authenticated to the Directory Server using LDAPv2, but attempted to \
+ send an extended operation request (LDAP message ID %d), which is not allowed \
+ for LDAPv2 clients.  The connection will be terminated
+MILD_ERR_LDAP_STATS_INVALID_MONITOR_INITIALIZATION=An attempt was made to \
+ initialize the LDAP statistics monitor provider as defined in configuration \
+ entry %s.  This monitor provider should only be dynamically created within \
+ the Directory Server itself and not from within the configuration
+SEVERE_ERR_LDAP_REQHANDLER_UNEXPECTED_SELECT_EXCEPTION=The LDAP request \
+ handler thread "%s" encountered an unexpected error that would have caused \
+ the thread to die:  %s.  The error has been caught and the request handler \
+ should continue operating as normal
+MILD_ERR_LDAP_CONNHANDLER_REJECTED_BY_SERVER=The attempt to register this \
+ connection with the Directory Server was rejected.  This might indicate that \
+ the server already has the maximum allowed number of concurrent connections \
+ established, or that it is in a restricted access mode
+INFO_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_ADDRESS=Address or \
+ set of addresses on which this connection handler can accept client \
+ connections.  If no value is specified, then the server will accept \
+ connections on all active addresses.  Changes to this configuration attribute \
+ will not take effect until the connection handler is disabled and re-enabled, \
+ or until the Directory Server is restarted
+INFO_LDAP_CONNHANDLER_DESCRIPTION_LISTEN_PORT=TCP port on \
+ which this connection handler can accept client connections.  Changes to this \
+ configuration attribute will not take effect until the connection handler is \
+ disabled and re-enabled, or until the Directory Server is restarted
+INFO_LDAP_CONNHANDLER_DESCRIPTION_ALLOWED_CLIENTS=Specifies a set of \
+ address masks that can be used to determine the addresses of the clients that \
+ are allowed to establish connections to this connection handler.  If no \
+ values are specified, then all clients with addresses that do not match an \
+ address on the deny list will be allowed.  Changes to this configuration \
+ attribute will take effect immediately but will not interfere with \
+ connections that might already be established
+INFO_LDAP_CONNHANDLER_DESCRIPTION_DENIED_CLIENTS=Specifies a set of \
+ address masks that can be used to determine the set of addresses of the \
+ clients that are not allowed to establish connections to this connection \
+ handler.  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 might \
+ already be established
+INFO_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_LDAPV2=Indicates whether to allow \
+ communication with LDAPv2 clients.  LDAPv2 is considered an obsolete \
+ protocol, and clients using it will not be allowed to take advantage of all \
+ features offered by the server.  Changes to this configuration attribute will \
+ take effect immediately, but will not interfere with connections that might \
+ already be established
+INFO_LDAP_CONNHANDLER_DESCRIPTION_NUM_REQUEST_HANDLERS=Number of threads \
+ that should be used to read requests from clients and place \
+ them in the work queue for processing.  On large systems accepting many \
+ concurrent requests, it might be more efficient to have multiple threads \
+ reading requests from clients.  Changes to this configuration attribute will \
+ not take effect until the connection handler is disabled and re-enabled, or \
+ until the Directory Server is restarted
+INFO_LDAP_CONNHANDLER_DESCRIPTION_SEND_REJECTION_NOTICE=Indicates whether \
+ to send an LDAPv3 notice of disconnection message to client connections that \
+ are rejected before closing the connection.  Changes to this configuration \
+ attribute will take effect immediately
+INFO_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_KEEPALIVE=Indicates whether to \
+ use the TCP KeepAlive feature for client connections established through this \
+ connection handler.  This is recommended because it might help the server \
+ detect client connections that are no longer valid, and might help prevent \
+ intermediate network devices from closing connections due to a lack of \
+ communication.  Changes to this configuration attribute will take effect \
+ immediately but will only be applied to connections established after the \
+ change
+INFO_LDAP_CONNHANDLER_DESCRIPTION_USE_TCP_NODELAY=Indicates whether to \
+ use the TCP NoDelay feature for client connections established through this \
+ connection handler.  This is recommended because it will generally allow \
+ faster responses to clients, although directories that frequently process \
+ searches that match multiple entries might be able to achieve higher throughput \
+ if it is disabled.  Changes to this configuration attribute will take effect \
+ immediately but will only be applied to connections established after the \
+ change
+INFO_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_REUSE_ADDRESS=Indicates whether \
+ to use the SO_REUSEADDR socket option for the socket accepting connections \
+ for this connection handler.  It should generally be enabled unless you have \
+ been instructed to disable it by support engineers.  Changes to this \
+ configuration attribute will not take effect until the connection handler is \
+ disabled and re-enabled, or until the Directory Server is restarted
+INFO_LDAP_CONNHANDLER_DESCRIPTION_MAX_REQUEST_SIZE=Maximum \
+ size in bytes that will be allowed when reading requests from clients.  This \
+ can be used to prevent denial of service attacks from clients that send \
+ extremely large requests.  A value of zero indicates that no limit should be \
+ imposed.  Changes to this configuration attribute will take effect \
+ immediately
+INFO_LDAP_CONNHANDLER_DESCRIPTION_USE_SSL=Indicates whether this \
+ connection handler should use SSL when accepting connections from clients. \
+ Changes to this configuration attribute will not take effect until the \
+ connection handler is disabled and re-enabled, or until the Directory Server \
+ is restarted
+INFO_LDAP_CONNHANDLER_DESCRIPTION_ALLOW_STARTTLS=Indicates whether this \
+ connection handler should allow clients to use the StartTLS extended \
+ operation to initiate secure communication over a non-SSL LDAP connection. \
+ This can not be used if SSL is enabled for the connection handler.  Changes \
+ to this configuration attribute will take effect immediately for LDAP clients
+INFO_LDAP_CONNHANDLER_DESCRIPTION_SSL_CLIENT_AUTH_POLICY=Policy that \
+ should be used regarding requesting or requiring the client to \
+ present its own certificate when establishing an SSL-based connection or \
+ using StartTLS to initiate a secure channel in an established connection. \
+ Changes to this configuration attribute will not take effect until the \
+ connection handler is disabled and re-enabled, or until the Directory Server \
+ is restarted
+INFO_LDAP_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME=Nickname of the \
+ certificate that the connection handler should use when \
+ accepting SSL-based connections or performing StartTLS negotiation.  Changes \
+ to this configuration attribute will not take effect until the connection \
+ handler is disabled and re-enabled, or until the Directory Server is \
+ restarted
+SEVERE_ERR_LDAP_CONNHANDLER_UNKNOWN_LISTEN_ADDRESS=The specified listen \
+ address "%s" in configuration entry "%s" could not be resolved:  %s.  Please \
+ make sure that name resolution is properly configured on this system
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_LISTEN_ADDRESS=An unexpected \
+ error occurred while processing the ds-cfg-listen-address attribute in \
+ configuration entry %s, which is used to specify the address or set of \
+ addresses on which to listen for client connections:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_NO_LISTEN_PORT=No listen port was defined \
+ using configuration ds-cfg-listen-port in configuration entry %s.  This is a \
+ required attribute
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT=An unexpected \
+ error occurred while processing the ds-cfg-listen-port attribute in \
+ configuration entry %s, which is used to specify the port on which to listen \
+ for client connections:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOWED_CLIENTS=An \
+ unexpected error occurred while processing the ds-cfg-allowed-client \
+ attribute in configuration entry %s, which is used to specify the address \
+ mask(s) of the clients that are allowed to establish connections to this \
+ connection handler:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_DENIED_CLIENTS=An unexpected \
+ error occurred while processing the ds-cfg-denied-client attribute in \
+ configuration entry %s, which is used to specify the address mask(s) of the \
+ clients that are not allowed to establish connections to this connection \
+ handler:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_LDAPV2=An unexpected \
+ error occurred while processing the ds-cfg-allow-ldap-v2 attribute in \
+ configuration entry %s, which is used to indicate whether LDAPv2 clients will \
+ be allowed to access this connection handler:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_NUM_REQUEST_HANDLERS=An \
+ unexpected error occurred while processing the ds-cfg-num-request-handlers \
+ attribute in configuration entry %s, which is used to specify the number of \
+ request handlers to use to read requests from clients: %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_SEND_REJECTION_NOTICE=An \
+ unexpected error occurred while processing the ds-cfg-send-rejection-notice \
+ attribute in configuration entry %s, which is used to indicate whether to \
+ send a notice of disconnection message to rejected client connections: %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_KEEPALIVE=An \
+ unexpected error occurred while processing the ds-cfg-use-tcp-keep-alive \
+ attribute in configuration entry %s, which is used to periodically send TCP \
+ Keep-Alive messages over idle connections:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_TCP_NODELAY=An \
+ unexpected error occurred while processing the ds-cfg-use-tcp-no-delay \
+ attribute in configuration entry %s, which is used to determine whether to \
+ immediately flush responses to clients:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_REUSE_ADDRESS=An \
+ unexpected error occurred while processing the ds-cfg-allow-tcp-reuse-address \
+ attribute in configuration entry %s, which is used to determine whether to \
+ set the SO_REUSEADDR option on the listen socket:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_MAX_REQUEST_SIZE=An \
+ unexpected error occurred while processing the ds-cfg-max-request-size \
+ attribute in configuration entry %s, which is used to determine the maximum \
+ size in bytes that can be used for a client request:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_USE_SSL=An unexpected error \
+ occurred while processing the ds-cfg-use-ssl attribute in configuration entry \
+ %s, which is used to indicate whether to use SSL when accepting client \
+ connections:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_HAVE_SSL_AND_STARTTLS=The LDAP \
+ connection handler defined in configuration entry %s is configured to \
+ communicate over SSL and also to allow clients to use the StartTLS extended \
+ operation.  These options can not be used at the same time, so clients will \
+ not be allowed to use the StartTLS operation
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_ALLOW_STARTTLS=An unexpected \
+ error occurred while processing the ds-cfg-allow-start-tls attribute in \
+ configuration entry %s, which is used to indicate whether clients can use the \
+ StartTLS extended operation:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_INVALID_SSL_CLIENT_AUTH_POLICY=The SSL client \
+ authentication policy "%s" specified in attribute \
+ ds-cfg-ssl-client-auth-policy of configuration entry %s is invalid.  The \
+ value must be one of "disabled", "optional", or "required"
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CLIENT_AUTH_POLICY=An \
+ unexpected error occurred while processing the ds-cfg-ssl-client-auth-policy \
+ attribute in configuration entry %s, which is used to specify the policy that \
+ should be used for requesting/requiring SSL client authentication:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME=An \
+ unexpected error occurred while processing the ds-cfg-ssl-cert-nickname \
+ attribute in configuration entry %s, which is used to specify the nickname of \
+ the certificate to use for accepting SSL/TLS connections:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_INVALID_ADDRESS_MASK=The string %s defined in \
+ attribute %s of configuration entry %s could not be decoded as a valid \
+ address mask:  %s
+INFO_LDAP_CONNHANDLER_NEW_ALLOWED_CLIENTS=A new set of allowed client \
+ address masks has been applied for configuration entry %s
+INFO_LDAP_CONNHANDLER_NEW_DENIED_CLIENTS=A new set of denied client \
+ address masks has been applied for configuration entry %s
+INFO_LDAP_CONNHANDLER_NEW_ALLOW_LDAPV2=The value of the \
+ ds-cfg-allow-ldap-v2 attribute has been updated to %s in configuration entry \
+ %s
+INFO_LDAP_CONNHANDLER_NEW_SEND_REJECTION_NOTICE=The value of the \
+ ds-cfg-send-rejection-notice attribute has been updated to %s in \
+ configuration entry %s
+INFO_LDAP_CONNHANDLER_NEW_USE_KEEPALIVE=The value of the \
+ ds-cfg-use-tcp-keep-alive attribute has been updated to %s in configuration \
+ entry %s
+INFO_LDAP_CONNHANDLER_NEW_USE_TCP_NODELAY=The value of the \
+ ds-cfg-use-tcp-no-delay attribute has been updated to %s in configuration \
+ entry %s
+INFO_LDAP_CONNHANDLER_NEW_MAX_REQUEST_SIZE=The value of the \
+ ds-cfg-max-request-size attribute has been updated to %s in configuration \
+ entry %s
+INFO_LDAP_CONNHANDLER_NEW_ALLOW_STARTTLS=The value of the \
+ ds-cfg-allow-start-tls attribute has been updated to %s in configuration \
+ entry %s
+INFO_LDAP_CONNHANDLER_DESCRIPTION_KEEP_STATS=Indicates whether the \
+ connection handler should keep statistics regarding LDAP client \
+ communication.  Maintaining this information can cause a slight decrease in \
+ performance, but can be useful for understanding client usage patterns. \
+ Changes to this configuration attribute will take effect immediately, but \
+ will only apply for new connections and will have the side effect of clearing \
+ any existing statistical data that might have been collected
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEEP_STATS=An unexpected \
+ error occurred while processing the ds-cfg-keep-stats attribute in \
+ configuration entry %s, which is used to indicate whether LDAP usage \
+ statistics should be enabled for this connection handler:  %s
+INFO_LDAP_CONNHANDLER_NEW_KEEP_STATS=The value of the ds-cfg-keep-stats \
+ attribute has been updated to %s in configuration entry %s
+MILD_ERR_ASN1_LONG_SET_VALUE_INVALID_LENGTH=Cannot decode the provided \
+ byte array as the value of an ASN.1 long element because the array did not \
+ have a length between 1 and 8 bytes (provided length was %d)
+MILD_ERR_ASN1_LONG_DECODE_ELEMENT_INVALID_LENGTH=Cannot decode the \
+ provided ASN.1 element as a long element because the length of the element \
+ value was not between one and eight bytes (actual length was %d)
+MILD_ERR_ASN1_LONG_DECODE_ARRAY_INVALID_LENGTH=Cannot decode the provided \
+ byte array as an ASN.1 long element because the decoded value length was not \
+ between 1 and 8 bytes (decoded length was %d)
+SEVERE_ERR_INTERNAL_CANNOT_DECODE_DN=An unexpected error occurred while \
+ trying to decode the DN %s used for internal operations as a root user:  %s
+INFO_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_PROTOCOLS=Names of the \
+ SSL protocols that will be allowed for use in SSL or StartTLS \
+ communication.  Changes to this configuration attribute will take effect \
+ immediately but will only impact new SSL/TLS-based sessions created after \
+ the change
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_PROTOCOLS=An unexpected \
+ error occurred while processing the ds-cfg-ssl-protocol attribute in \
+ configuration entry %s, which is used to specify the names of the SSL \
+ protocols to allow for SSL/TLS sessions:  %s
+INFO_LDAP_CONNHANDLER_DESCRIPTION_SSL_ENABLED_CIPHERS=Names \
+ of the SSL cipher suites that will be allowed for use in SSL or StartTLS \
+ communication.  Changes to this configuration attribute will take immediately \
+ but will only impact new SSL/TLS-based sessions created after the change
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_SSL_CIPHERS=An unexpected \
+ error occurred while processing the ds-cfg-ssl-protocol attribute in \
+ configuration entry %s, which is used to specify the names of the SSL cipher \
+ suites to allow for SSL/TLS sessions:  %s
+INFO_LDAP_CONNHANDLER_NEW_SSL_PROTOCOLS=The value of the \
+ ds-cfg-ssl-protocol attribute has been updated to %s in configuration entry \
+ %s
+INFO_LDAP_CONNHANDLER_NEW_SSL_CIPHERS=The value of the \
+ ds-cfg-ssl-cipher-suite attribute has been updated to %s in configuration \
+ entry %s
+MILD_ERR_LDAP_TLS_EXISTING_SECURITY_PROVIDER=The TLS connection security \
+ provider cannot be enabled on this client connection because it is already \
+ using the %s provider.  StartTLS can only be used on clear-text connections
+MILD_ERR_LDAP_TLS_STARTTLS_NOT_ALLOWED=StartTLS cannot be enabled on this \
+ LDAP client connection because the corresponding LDAP connection handler is \
+ configured to reject StartTLS requests.  The use of StartTLS can be enabled \
+ using the ds-cfg-allow-start-tls configuration attribute
+MILD_ERR_LDAP_TLS_CANNOT_CREATE_TLS_PROVIDER=An error occurred while \
+ attempting to create a TLS connection security provider for this client \
+ connection for use with StartTLS:  %s
+MILD_ERR_LDAP_TLS_NO_PROVIDER=StartTLS is not available on this client \
+ connection because the connection does not have access to a TLS connection \
+ security provider
+MILD_ERR_LDAP_TLS_CLOSURE_NOT_ALLOWED=The LDAP connection handler does \
+ not allow clients to close a StartTLS session on a client connection while \
+ leaving the underlying TCP connection active.  The TCP connection will be \
+ closed
+NOTICE_LDAP_CONNHANDLER_STARTED_LISTENING=Started listening for new \
+ connections on %s
+NOTICE_LDAP_CONNHANDLER_STOPPED_LISTENING=Stopped listening for new \
+ connections on %s
+MILD_ERR_LDAP_PAGED_RESULTS_DECODE_NULL=Cannot decode the provided ASN.1 \
+ element as an LDAP paged results control value because the element is null
+MILD_ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE=Cannot decode the provided \
+ ASN.1 element as an LDAP paged results control value because the element \
+ could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_PAGED_RESULTS_DECODE_INVALID_ELEMENT_COUNT=Cannot decode \
+ the provided ASN.1 element as an LDAP paged results control value because the \
+ request sequence has an invalid number of elements (expected 2, got %d)
+MILD_ERR_LDAP_PAGED_RESULTS_DECODE_SIZE=Cannot decode the provided ASN.1 \
+ element as an LDAP paged results control value because the size element could \
+ not be properly decoded:  %s
+MILD_ERR_LDAP_PAGED_RESULTS_DECODE_COOKIE=Cannot decode the provided \
+ ASN.1 element as an LDAP paged results control value because the cookie could \
+ not be properly decoded:  %s
+MILD_ERR_LDAPASSERT_NO_CONTROL_VALUE=Cannot decode the provided LDAP \
+ assertion control because the control does not have a value
+MILD_ERR_LDAPASSERT_INVALID_CONTROL_VALUE=Cannot decode the provided LDAP \
+ assertion control because the control value cannot be decoded as an ASN.1 \
+ element:  %s
+MILD_ERR_PREREADREQ_NO_CONTROL_VALUE=Cannot decode the provided LDAP \
+ pre-read request control because the control does not have a value
+MILD_ERR_PREREADREQ_CANNOT_DECODE_VALUE=Cannot decode the provided LDAP \
+ pre-read request control because an error occurred while trying to decode the \
+ control value:  %s
+MILD_ERR_POSTREADREQ_NO_CONTROL_VALUE=Cannot decode the provided LDAP \
+ post-read request control because the control does not have a value
+MILD_ERR_POSTREADREQ_CANNOT_DECODE_VALUE=Cannot decode the provided LDAP \
+ post-read request control because an error occurred while trying to decode \
+ the control value:  %s
+MILD_ERR_PREREADRESP_NO_CONTROL_VALUE=Cannot decode the provided LDAP \
+ pre-read response control because the control does not have a value
+MILD_ERR_PREREADRESP_CANNOT_DECODE_VALUE=Cannot decode the provided LDAP \
+ pre-read response control because an error occurred while trying to decode \
+ the control value:  %s
+MILD_ERR_POSTREADRESP_NO_CONTROL_VALUE=Cannot decode the provided LDAP \
+ post-read response control because the control does not have a value
+MILD_ERR_POSTREADRESP_CANNOT_DECODE_VALUE=Cannot decode the provided LDAP \
+ post-read response control because an error occurred while trying to decode \
+ the control value:  %s
+MILD_ERR_PROXYAUTH1_NO_CONTROL_VALUE=Cannot decode the provided proxied \
+ authorization V1 control because it does not have a value
+MILD_ERR_PROXYAUTH1_INVALID_ELEMENT_COUNT=Cannot decode the provided \
+ proxied authorization V1 control because the ASN.1 sequence in the control \
+ value has an invalid number of elements (expected 1, got %d)
+MILD_ERR_PROXYAUTH1_CANNOT_DECODE_VALUE=Cannot decode the provided \
+ proxied authorization V1 control because an error occurred while attempting \
+ to decode the control value:  %s
+MILD_ERR_PROXYAUTH1_NO_SUCH_USER=User %s specified in the proxied \
+ authorization V1 control does not exist in the Directory Server
+MILD_ERR_PROXYAUTH2_NO_CONTROL_VALUE=Cannot decode the provided proxied \
+ authorization V2 control because it does not have a value
+MILD_ERR_PROXYAUTH2_CANNOT_DECODE_VALUE=Cannot decode the provided \
+ proxied authorization V2 control because an error occurred while attempting \
+ to decode the control value:  %s
+MILD_ERR_PROXYAUTH2_NO_IDENTITY_MAPPER=Unable to process proxied \
+ authorization V2 control because it contains an authorization ID based on a \
+ username and no proxied authorization identity mapper is configured in the \
+ Directory Server
+MILD_ERR_PROXYAUTH2_INVALID_AUTHZID=The authorization ID "%s" contained \
+ in the proxied authorization V2 control is invalid because it does not start \
+ with "dn:" to indicate a user DN or "u:" to indicate a username
+MILD_ERR_PROXYAUTH2_NO_SUCH_USER=User %s specified in the proxied \
+ authorization V2 control does not exist in the Directory Server
+MILD_ERR_PSEARCH_CHANGETYPES_INVALID_TYPE=The provided integer value %d \
+ does not correspond to any persistent search change type
+MILD_ERR_PSEARCH_CHANGETYPES_NO_TYPES=The provided integer value \
+ indicated that there were no persistent search change types, which is not \
+ allowed
+MILD_ERR_PSEARCH_CHANGETYPES_INVALID_TYPES=The provided integer value %d \
+ was outside the range of acceptable values for an encoded change type set
+MILD_ERR_PSEARCH_NO_CONTROL_VALUE=Cannot decode the provided persistent \
+ search control because it does not have a value
+MILD_ERR_PSEARCH_INVALID_ELEMENT_COUNT=Cannot decode the provided \
+ persistent search control because the value sequence has an invalid number of \
+ elements (expected 3, got %d)
+MILD_ERR_PSEARCH_CANNOT_DECODE_VALUE=Cannot decode the provided \
+ persistent search control because an error occurred while attempting to \
+ decode the control value:  %s
+MILD_ERR_ECN_NO_CONTROL_VALUE=Cannot decode the provided entry change \
+ notification control because it does not have a value
+MILD_ERR_ECN_INVALID_ELEMENT_COUNT=Cannot decode the provided entry \
+ change notification control because the value sequence has an invalid number \
+ of elements (expected between 1 and 3, got %d)
+MILD_ERR_ECN_ILLEGAL_PREVIOUS_DN=Cannot decode the provided entry change \
+ notification control because it contains a previous DN element but had a \
+ change type of %s.  The previous DN element can only be provided with the \
+ modify DN change type
+MILD_ERR_ECN_INVALID_ELEMENT_TYPE=Cannot decode the provided entry change \
+ notification control because the second element in the value sequence has an \
+ invalid type of %s that is not appropriate for either a previous DN or a \
+ change number
+MILD_ERR_ECN_CANNOT_DECODE_VALUE=Cannot decode the provided entry change \
+ notification control because an error occurred while attempting to decode the \
+ control value:  %s
+MILD_ERR_AUTHZIDRESP_NO_CONTROL_VALUE=Cannot decode the provided \
+ authorization identity response control because it does not have a value
+MILD_ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_SEQUENCE=Cannot decode the \
+ provided ASN.1 element as an LDAP intermediate response protocol op because \
+ the element could not be decoded as a sequence:  %s
+MILD_ERR_LDAP_INTERMEDIATE_RESPONSE_DECODE_INVALID_ELEMENT_COUNT=Cannot \
+ decode the provided ASN.1 element as an LDAP intermediate response protocol \
+ op because the request sequence had an invalid number of elements (expected \
+ 0, 1, or 2, got %d)
+MILD_ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_OID=An error occurred \
+ while attempting to decode the intermediate response OID:  %s
+MILD_ERR_LDAP_INTERMEDIATE_RESPONSE_CANNOT_DECODE_VALUE=An error occurred \
+ while attempting to decode the intermediate response value:  %s
+MILD_ERR_LDAP_INTERMEDIATE_RESPONSE_INVALID_ELEMENT_TYPE=The intermediate \
+ response sequence element contained an invalid BER type %s that was not \
+ appropriate for either the OID or the value
+INFO_LDAP_CONNHANDLER_DESCRIPTION_BACKLOG=Accept queue \
+ size, which controls the number of new connection attempts that may be \
+ allowed to queue up in the backlog before being rejected.  This should only \
+ need to be changed if it is expected that the Directory Server will receive \
+ large numbers of new connection attempts at the same time.  Changes to this \
+ configuration attribute will not take effect until the connection handler is \
+ disabled and re-enabled, or until the Directory Server is restarted
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_BACKLOG=An unexpected error \
+ occurred while processing the ds-cfg-accept-backlog attribute in \
+ configuration entry %s, which is used to specify the accept backlog size:  %s
+SEVERE_ERR_MVFILTER_INVALID_LDAP_FILTER_TYPE=The provided LDAP filter \
+ "%s" cannot be used as a matched values filter because filters of type %s are \
+ not allowed for use in matched values filters
+SEVERE_ERR_MVFILTER_INVALID_DN_ATTRIBUTES_FLAG=The provided LDAP filter \
+ "%s" cannot be used as a matched values filter because it is an extensible \
+ match filter that contains the dnAttributes flag, which is not allowed for \
+ matched values filters
+SEVERE_ERR_MVFILTER_INVALID_AVA_SEQUENCE_SIZE=The provided matched values \
+ filter could not be decoded because there were an invalid number of elements \
+ in the attribute value assertion (expected 2, got %d)
+SEVERE_ERR_MVFILTER_CANNOT_DECODE_AVA=An error occurred while attempting \
+ to decode the attribute value assertion in the provided matched values \
+ filter:  %s
+SEVERE_ERR_MVFILTER_INVALID_SUBSTRING_SEQUENCE_SIZE=The provided matched \
+ values filter could not be decoded because there were an invalid number of \
+ elements in the substring sequence (expected 2, got %d)
+SEVERE_ERR_MVFILTER_NO_SUBSTRING_ELEMENTS=The provided matched values \
+ filter could not be decoded because there were no subInitial, subAny, or \
+ subFinal components in the substring filter
+SEVERE_ERR_MVFILTER_MULTIPLE_SUBINITIALS=The provided matched values \
+ filter could not be decoded because there were multiple subInitial components \
+ in the substring filter
+SEVERE_ERR_MVFILTER_MULTIPLE_SUBFINALS=The provided matched values filter \
+ could not be decoded because there were multiple subFinal components in the \
+ substring filter
+SEVERE_ERR_MVFILTER_INVALID_SUBSTRING_ELEMENT_TYPE=The provided matched \
+ values filter could not be decoded because there was an invalid element of \
+ type %s in the substring filter
+SEVERE_ERR_MVFILTER_CANNOT_DECODE_SUBSTRINGS=The provided matched values \
+ filter could not be decoded because an error occurred while decoding the \
+ substring filter component:  %s
+SEVERE_ERR_MVFILTER_CANNOT_DECODE_PRESENT_TYPE=The provided matched \
+ values filter could not be decoded because an error occurred while decoding \
+ the presence filter component:  %s
+SEVERE_ERR_MVFILTER_INVALID_EXTENSIBLE_SEQUENCE_SIZE=The provided matched \
+ values filter could not be decoded because there were an invalid number of \
+ elements in the extensible match sequence (expected 2 or 3, found %d)
+SEVERE_ERR_MVFILTER_MULTIPLE_MATCHING_RULE_IDS=The provided matched \
+ values filter could not be decoded because there were multiple matching rule \
+ ID elements found in the extensible match filter sequence
+SEVERE_ERR_MVFILTER_MULTIPLE_ATTRIBUTE_TYPES=The provided matched values \
+ filter could not be decoded because there were multiple attribute type \
+ elements found in the extensible match filter sequence
+SEVERE_ERR_MVFILTER_MULTIPLE_ASSERTION_VALUES=The provided matched values \
+ filter could not be decoded because there were multiple assertion value \
+ elements found in the extensible match filter sequence
+SEVERE_ERR_MVFILTER_INVALID_EXTENSIBLE_ELEMENT_TYPE=The provided matched \
+ values filter could not be decoded because there was an invalid element of \
+ type %s in the extensible match filter
+SEVERE_ERR_MVFILTER_CANNOT_DECODE_EXTENSIBLE_MATCH=The provided matched \
+ values filter could not be decoded because an error occurred while decoding \
+ the extensible match filter component:  %s
+SEVERE_ERR_MVFILTER_INVALID_ELEMENT_TYPE=The provided matched values \
+ filter could not be decoded because it had an invalid BER type of %s
+SEVERE_ERR_MATCHEDVALUES_NO_CONTROL_VALUE=Cannot decode the provided \
+ matched values control because it does not have a value
+SEVERE_ERR_MATCHEDVALUES_CANNOT_DECODE_VALUE_AS_SEQUENCE=Cannot decode \
+ the provided matched values control because an error occurred while \
+ attempting to decode the value as an ASN.1 sequence:  %s
+SEVERE_ERR_MATCHEDVALUES_NO_FILTERS=Cannot decode the provided matched \
+ values control because the control value does not specify any filters for use \
+ in matching attribute values
+SEVERE_ERR_PWEXPIRED_CONTROL_INVALID_VALUE=Cannot decode the provided \
+ control as a password expired control because the provided control had a \
+ value that could not be parsed as an integer
+SEVERE_ERR_PWEXPIRING_NO_CONTROL_VALUE=Cannot decode the provided \
+ password expiring control because it does not have a value
+SEVERE_ERR_PWEXPIRING_CANNOT_DECODE_SECONDS_UNTIL_EXPIRATION=Cannot \
+ decode the provided control as a password expiring control because an error \
+ occurred while attempting to decode the number of seconds until expiration: \
+ %s
+MILD_WARN_LDAP_CLIENT_DUPLICATE_MESSAGE_ID=The Directory Server is \
+ already processing another request on the same client connection with the \
+ same message ID of %d
+MILD_WARN_LDAP_CLIENT_CANNOT_ENQUEUE=The Directory Server encountered an \
+ unexpected error while attempting to add the client request to the work \
+ queue:  %s
+INFO_JMX_CONNHANDLER_DESCRIPTION_LISTEN_PORT=TCP port on \
+ which this connection handler may accept administrative connections.  Changes \
+ to this configuration attribute will not take effect until the connection \
+ handler is disabled and re-enabled, or until the Directory Server is \
+ restarted
+SEVERE_ERR_JMX_CONNHANDLER_NO_LISTEN_PORT=No listen port was defined \
+ using configuration ds-cfg-listen-port in configuration entry %s.  This is a \
+ required attribute
+SEVERE_ERR_JMX_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT=An unexpected \
+ error occurred while processing the ds-cfg-listen-port attribute in \
+ configuration entry %s, which is used to specify the port on which to listen \
+ for client connections:  %s
+INFO_JMX_CONNHANDLER_DESCRIPTION_USE_SSL=Indicates whether this \
+ connection handler should use SSL when accepting connections from clients. \
+ Changes to this configuration attribute will not take effect until the \
+ connection handler is disabled and re-enabled, or until the Directory Server \
+ is restarted
+SEVERE_ERR_JMX_CONNHANDLER_CANNOT_DETERMINE_USE_SSL=An unexpected error \
+ occurred while processing the ds-cfg-use-ssl attribute in configuration entry \
+ %s, which is used to indicate whether to use SSL when accepting client \
+ connections:  %s
+INFO_JMX_CONNHANDLER_DESCRIPTION_SSL_CERT_NICKNAME=Nickname \
+ of the certificate that the connection handler should use when accepting \
+ SSL-based connections or performing StartTLS negotiation.  Changes to this \
+ configuration attribute will not take effect until the connection handler is \
+ disabled and re-enabled, or until the Directory Server is restarted
+SEVERE_ERR_JMX_CONNHANDLER_CANNOT_DETERMINE_SSL_CERT_NICKNAME=An \
+ unexpected error occurred while processing the ds-cfg-ssl-cert-nickname \
+ attribute in configuration entry %s, which is used to specify the nickname of \
+ the certificate to use for accepting SSL/TLS connections:  %s
+SEVERE_ERR_PWPOLICYREQ_CONTROL_HAS_VALUE=Cannot decode the provided \
+ control as a password policy request control because the provided control had \
+ a value but the password policy request control should not have a value
+SEVERE_ERR_PWPOLICYRES_NO_CONTROL_VALUE=Cannot decode the provided \
+ password policy response control because it does not have a value
+SEVERE_ERR_PWPOLICYRES_INVALID_WARNING_TYPE=Cannot decode the provided \
+ password policy response control because the warning element has an invalid \
+ type of %s
+SEVERE_ERR_PWPOLICYRES_INVALID_ERROR_TYPE=Cannot decode the provided \
+ password policy response control because the error element has an invalid \
+ type of %d
+SEVERE_ERR_PWPOLICYRES_INVALID_ELEMENT_TYPE=Cannot decode the provided \
+ password policy response control because the value sequence has an element \
+ with an invalid type of %s
+SEVERE_ERR_PWPOLICYRES_DECODE_ERROR=Cannot decode the provided password \
+ policy response control:  %s
+INFO_PWPERRTYPE_DESCRIPTION_PASSWORD_EXPIRED=passwordExpired
+INFO_PWPERRTYPE_DESCRIPTION_ACCOUNT_LOCKED=accountLocked
+INFO_PWPERRTYPE_DESCRIPTION_CHANGE_AFTER_RESET=changeAfterReset
+INFO_PWPERRTYPE_DESCRIPTION_PASSWORD_MOD_NOT_ALLOWED=passwordModNotAllowed
+INFO_PWPERRTYPE_DESCRIPTION_MUST_SUPPLY_OLD_PASSWORD=mustSupplyOldPassword
+INFO_PWPERRTYPE_DESCRIPTION_INSUFFICIENT_PASSWORD_QUALITY=insufficientPasswordQuality
+INFO_PWPERRTYPE_DESCRIPTION_PASSWORD_TOO_SHORT=passwordTooShort
+INFO_PWPERRTYPE_DESCRIPTION_PASSWORD_TOO_YOUNG=passwordTooYoung
+INFO_PWPERRTYPE_DESCRIPTION_PASSWORD_IN_HISTORY=passwordInHistory
+INFO_PWPWARNTYPE_DESCRIPTION_TIME_BEFORE_EXPIRATION=timeBeforeExpiration
+INFO_PWPWARNTYPE_DESCRIPTION_GRACE_LOGINS_REMAINING=graceAuthNsRemaining
+MILD_ERR_PROXYAUTH1_CANNOT_LOCK_USER=Unable to obtain a lock on user \
+ entry %s for the proxied authorization V1 control validation
+MILD_ERR_PROXYAUTH1_UNUSABLE_ACCOUNT=Use of the proxied authorization V1 \
+ control for user %s is not allowed by the password policy configuration
+MILD_ERR_PROXYAUTH2_CANNOT_LOCK_USER=Unable to obtain a lock on user \
+ entry %s for the proxied authorization V2 control validation
+MILD_ERR_PROXYAUTH2_UNUSABLE_ACCOUNT=Use of the proxied authorization V2 \
+ control for user %s is not allowed by the password policy configuration
+SEVERE_ERR_ACCTUSABLEREQ_CONTROL_HAS_VALUE=Cannot decode the provided \
+ control as an account availability request control because the provided \
+ control had a value but the account availability request control should not \
+ have a value
+SEVERE_ERR_ACCTUSABLERES_NO_CONTROL_VALUE=Cannot decode the provided \
+ account availability response control because it does not have a value
+SEVERE_ERR_ACCTUSABLERES_UNKNOWN_UNAVAILABLE_TYPE=The account \
+ availability response control indicated that the account was unavailable but \
+ had an unknown unavailable element type of %s
+SEVERE_ERR_ACCTUSABLERES_UNKNOWN_VALUE_ELEMENT_TYPE=The account \
+ availability response control had an unknown ACCOUNT_USABLE_RESPONSE element \
+ type of %s
+SEVERE_ERR_ACCTUSABLERES_DECODE_ERROR=Cannot decode the provided account \
+ availability response control:  %s
+SEVERE_ERR_ADDRESSMASK_PREFIX_DECODE_ERROR=Cannot decode the provided \
+ address mask prefix because an invalid value was specified. The permitted \
+ values for IPv4are 0 to32 and for IPv6 0 to128
+SEVERE_ERR_ADDRESSMASK_WILDCARD_DECODE_ERROR=Cannot decode the provided \
+ address mask because an prefix mask was specified with an wild card "*" match \
+ character
+SEVERE_ERR_ADDRESSMASK_FORMAT_DECODE_ERROR=Cannot decode the provided \
+ address mask because the it has an invalid format
+MILD_ERR_LDAP_NO_CLEAR_SECURITY_PROVIDER=LDAP connection handler %s could \
+ not send a clear-text response to the client because it does not have a \
+ reference to a clear connection security provider
+MILD_ERR_LDAP_ATTRIBUTE_DUPLICATE_VALUES=The provided LDAP attribute %s \
+ contains duplicate values
+MILD_ERR_LDAP_FILTER_UNKNOWN_MATCHING_RULE=The provided LDAP search \
+ filter references unknown matching rule %s
+MILD_ERR_LDAP_FILTER_VALUE_WITH_NO_ATTR_OR_MR=The provided LDAP search \
+ filter has an assertion value but does not include either an attribute type \
+ or a matching rule ID
+FATAL_ERR_LDAP_REQHANDLER_DETECTED_JVM_ISSUE_CR6322825=Unable to call \
+ select() in the LDAP connection handler:  %s.  It appears that your JVM may \
+ be susceptible to the issue described at \
+ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6322825, and it is unable \
+ to handle LDAP requests in its current configuration.  Please upgrade to a \
+ newer JVM that does not exhibit this behavior (Java 5.0 Update 8 or higher) \
+ or set the number of available file descriptors to a value greater than or \
+ equal to 8193 (e.g., by issuing the command 'ulimit -n 8193') before starting \
+ the Directory Server
+MILD_ERR_PROXYAUTH1_CONTROL_NOT_CRITICAL=Unwilling to process the request \
+ because it contains a proxied authorization V1 control which is not marked \
+ critical.  The proxied authorization control must always have a criticality \
+ of "true"
+MILD_ERR_PROXYAUTH2_CONTROL_NOT_CRITICAL=Unwilling to process the request \
+ because it contains a proxied authorization V2 control which is not marked \
+ critical.  The proxied authorization control must always have a criticality \
+ of "true"
+INFO_LDAP_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN=DN of the \
+ configuration entry for the key manager provider that should be used with \
+ this LDAP connection handler.  Changes to this attribute will take effect \
+ immediately, but only for subsequent attempts to access the key manager \
+ provider for associated client connections
+SEVERE_ERR_LDAP_CONNHANDLER_INVALID_KEYMANAGER_DN=Configuration attribute \
+ ds-cfg-key-manager-provider of configuration entry %s has an invalid value \
+ %s which does not reference an enabled key manager provider
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN=An error \
+ occurred while processing the ds-cfg-key-manager-provider attribute in \
+ configuration entry %s, which is used to specify the key manager provider for \
+ use with the LDAP connection handler:  %s
+INFO_LDAP_CONNHANDLER_DESCRIPTION_TRUSTMANAGER_DN=DN of the \
+ configuration entry for the trust manager provider that should be used with \
+ this LDAP connection handler.  Changes to this attribute will take effect \
+ immediately, but only for subsequent attempts to access the trust manager \
+ provider for associated client connections
+SEVERE_ERR_LDAP_CONNHANDLER_INVALID_TRUSTMANAGER_DN=Configuration \
+ attribute ds-cfg-trust-manager-provider of configuration entry %s has an \
+ invalid value %s which does not reference an enabled trust manager provider
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_DETERMINE_TRUSTMANAGER_DN=An error \
+ occurred while processing the ds-cfg-trust-manager-provider attribute in \
+ configuration entry %s, which is used to specify the trust manager provider \
+ for use with the LDAP connection handler:  %s
+INFO_LDAP_CONNHANDLER_NEW_KEYMANAGER_DN=The value of the \
+ ds-cfg-key-manager-provider attribute has been updated to %s in \
+ configuration entry %s
+INFO_LDAP_CONNHANDLER_NEW_TRUSTMANAGER_DN=The value of the \
+ ds-cfg-trust-manager-provider attribute has been updated to %s in \
+ configuration entry %s
+INFO_JMX_CONNHANDLER_DESCRIPTION_KEYMANAGER_DN=DN of the \
+ key manager provider that the connection handler should use when accepting \
+ SSL-based connections or performing StartTLS negotiation.  Changes to this \
+ configuration attribute will take effect immediately
+SEVERE_ERR_JMX_CONNHANDLER_INVALID_KEYMANAGER_DN=An error occurred while \
+ processing the ds-cfg-key-manager-provider attribute in configuration \
+ entry %s, because the provided key manager DN %s does not refer to an enabled \
+ key manager provider
+SEVERE_ERR_JMX_CONNHANDLER_CANNOT_DETERMINE_KEYMANAGER_DN=An unexpected \
+ error occurred while processing the ds-cfg-key-manager-provider attribute \
+ in configuration entry %s, which is used to specify the DN of the key manager \
+ provider to use for accepting SSL/TLS connections:  %s
+MILD_ERR_LDAP_CONNHANDLER_CANNOT_SET_SECURITY_PROVIDER=An error occurred \
+ while attempting to configure the connection security provider for the client \
+ connection:  %s
+SEVERE_ERR_LDAP_CONNHANDLER_NO_KEYMANAGER_DN=The LDAP connection handler \
+ defined in configuration entry %s is configured to use either SSL or \
+ StartTLS, but does not specify which key manager provider should be used
+SEVERE_ERR_LDAP_CONNHANDLER_NO_TRUSTMANAGER_DN=The LDAP connection \
+ handler defined in configuration entry %s is configured to use either SSL or \
+ StartTLS, but does not specify which trust manager provider should be used
+INFO_LDAPS_CONNHANDLER_DESCRIPTION_ENABLE=Specifies whether to enable the \
+ LDAPS connection handler
+MILD_ERR_LDAP_FILTER_NOT_EXACTLY_ONE=The provided search filter "%s" \
+ could not be decoded because the NOT filter between positions %d and %d did \
+ not contain exactly one filter component
+INFO_SORTREQ_CONTROL_NO_VALUE=Unable to decode the provided control as a \
+ server-side sort request control because it does not include a control value
+INFO_SORTREQ_CONTROL_UNDEFINED_ATTR=Unable to process the provided \
+ server-side sort request control because it references attribute type %s \
+ which is not defined in the server schema
+INFO_SORTREQ_CONTROL_UNDEFINED_ORDERING_RULE=Unable to process the \
+ provided server-side sort request control because it references undefined \
+ ordering matching rule %s
+INFO_SORTREQ_CONTROL_INVALID_SEQ_ELEMENT_TYPE=Unable to process the \
+ provided server-side sort request control because the value sequence contains \
+ an element with an unsupported type of %s
+INFO_SORTREQ_CONTROL_CANNOT_DECODE_VALUE=Unable to process the provided \
+ server-side sort request control because an error occurred while attempting \
+ to decode the control value:  %s
+INFO_SORTRES_CONTROL_NO_VALUE=Unable to decode the provided control as a \
+ server-side sort response control because it does not include a control value
+INFO_SORTRES_CONTROL_CANNOT_DECODE_VALUE=Unable to process the provided \
+ server-side sort response control because an error occurred while attempting \
+ to decode the control value:  %s
+INFO_SORTREQ_CONTROL_NO_ATTR_NAME=Unable to process the provided \
+ server-side sort request control because the sort order string "%s" included \
+ a sort key with no attribute name
+INFO_SORTREQ_CONTROL_NO_MATCHING_RULE=Unable to process the provided \
+ server-side sort request control because the sort order string "%s" included \
+ a sort key with a colon but no matching rule name
+INFO_SORTREQ_CONTROL_NO_SORT_KEYS=Unable to process the provided \
+ server-side sort request control because it did not contain any sort keys
+INFO_SORTREQ_CONTROL_NO_ORDERING_RULE_FOR_ATTR=Unable to process the \
+ provided server-side sort request control because it included attribute %s \
+ which does not have a default ordering matching rule and no ordering rule was \
+ specified in the sort key
+INFO_VLVREQ_CONTROL_NO_VALUE=Unable to decode the provided control as a \
+ VLV request control because it does not include a control value
+INFO_VLVREQ_CONTROL_INVALID_ELEMENT_COUNT=Unable to decode the provided \
+ control as a VLV request control because it contains an invalid number of \
+ elements:  %d
+INFO_VLVREQ_CONTROL_INVALID_TARGET_TYPE=Unable to decode the provided \
+ control as a VLV request control because the target element type %s is \
+ invalid
+INFO_VLVREQ_CONTROL_CANNOT_DECODE_VALUE=Unable to process the provided \
+ VLV request control because an error occurred while attempting to decode the \
+ control value:  %s
+INFO_VLVRES_CONTROL_NO_VALUE=Unable to decode the provided control as a \
+ VLV response control because it does not include a control value
+INFO_VLVRES_CONTROL_INVALID_ELEMENT_COUNT=Unable to decode the provided \
+ control as a VLV response control because it contains an invalid number of \
+ elements:  %d
+INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE=Unable to process the provided \
+ VLV response control because an error occurred while attempting to decode the \
+ control value:  %s
+INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID=The authorization ID "%s" \
+ contained in the geteffectiverights control is invalid because it does not \
+ start with "dn:" to indicate a user DN
+INFO_GETEFFECTIVERIGHTS_DECODE_ERROR=Cannot decode the provided \
+ geteffectiverights request control:  %s
+INFO_CANNOT_DECODE_GETEFFECTIVERIGHTS_AUTHZID_DN=Unable to decode authzid \
+ DN string "%s" as a valid distinguished name:  %s
+MILD_ERR_LDAP_FILTER_ENCLOSED_IN_APOSTROPHES=An LDAP filter enclosed in \
+ apostrophes is invalid:  %s
+INFO_JMX_CONNHANDLER_DESCRIPTION_ENABLE=Specifies whether to enable the \
+ JMX connection handler
+MILD_ERR_LDAP_FILTER_INVALID_CHAR_IN_ATTR_TYPE=The provided search filter \
+ contains an invalid attribute type '%s' with invalid character '%s' at \
+ position %d
+MILD_ERR_LDAP_FILTER_EXTENSIBLE_MATCH_NO_AD_OR_MR=The provided search \
+ filter "%s" could not be decoded because the extensible match component \
+ starting at position %d did not include either an attribute description or a \
+ matching rule ID.  At least one of them must be provided
+MILD_ERR_LDAPV2_CONTROLS_NOT_ALLOWED=LDAPv2 clients are not allowed to \
+ use request controls
+SEVERE_ERR_LDAP_CONNHANDLER_CANNOT_BIND=The LDAP connection handler \
+ defined in configuration entry %s was unable to bind to %s:%d:  %s
+SEVERE_ERR_JMX_CONNHANDLER_CANNOT_BIND=The JMX connection handler defined \
+ in configuration entry %s was unable to bind to port %d:  %s
+MILD_ERR_JMX_ADD_INSUFFICIENT_PRIVILEGES=You do not have sufficient \
+ privileges to perform add operations through JMX
+MILD_ERR_JMX_DELETE_INSUFFICIENT_PRIVILEGES=You do not have sufficient \
+ privileges to perform delete operations through JMX
+MILD_ERR_JMX_MODIFY_INSUFFICIENT_PRIVILEGES=You do not have sufficient \
+ privileges to perform modify operations through JMX
+MILD_ERR_JMX_MODDN_INSUFFICIENT_PRIVILEGES=You do not have sufficient \
+ privileges to perform modify DN operations through JMX
+MILD_ERR_JMX_SEARCH_INSUFFICIENT_PRIVILEGES=You do not have sufficient \
+ privileges to perform search operations through JMX
+MILD_ERR_JMX_INSUFFICIENT_PRIVILEGES=You do not have sufficient \
+ privileges to establish the connection through JMX. At least JMX_READ \
+ privilege is required
+MILD_ERR_INTERNALCONN_NO_SUCH_USER=User %s does not exist in the directory
+MILD_ERR_INTERNALOS_CLOSED=This output stream has been closed
+MILD_ERR_INTERNALOS_INVALID_REQUEST=The provided LDAP message had an \
+ invalid operation type (%s) for a request
+MILD_ERR_INTERNALOS_SASL_BIND_NOT_SUPPORTED=SASL bind operations are not \
+ supported over internal LDAP sockets
+MILD_ERR_INTERNALOS_STARTTLS_NOT_SUPPORTED=StartTLS operations are not \
+ supported over internal LDAP sockets
+SEVERE_WARN_LDIF_CONNHANDLER_LDIF_DIRECTORY_NOT_DIRECTORY=The value %s \
+ specified as the LDIF directory path for the LDIF connection handler defined \
+ in configuration entry %s exists but is not a directory.  The specified path \
+ must be a directory.  The LDIF connection handler will start, but will not \
+ be able to proces any changes until this path is changed to a directory
+MILD_WARN_LDIF_CONNHANDLER_LDIF_DIRECTORY_MISSING=The directory %s \
+ referenced by the LDIF connection handler defined in configuration entry %s \
+ does not exist.  The LDIF connection handler will start, but will not be \
+ able to process any changes until this directory is created
+MILD_ERR_LDIF_CONNHANDLER_CANNOT_READ_CHANGE_RECORD_NONFATAL=An error \
+ occurred while trying to read a change record from the LDIF file:  %s.  This \
+ change will be skipped but processing on the LDIF file will continue
+MILD_ERR_LDIF_CONNHANDLER_CANNOT_READ_CHANGE_RECORD_FATAL=An error \
+ occurred while trying to read a change record from the LDIF file:  %s.  No \
+ further processing on this LDIF file can be performed
+INFO_LDIF_CONNHANDLER_UNKNOWN_CHANGETYPE=Unsupported change type %s
+INFO_LDIF_CONNHANDLER_RESULT_CODE=Result Code:  %d (%s)
+INFO_LDIF_CONNHANDLER_ERROR_MESSAGE=Additional Info:  %s
+INFO_LDIF_CONNHANDLER_MATCHED_DN=Matched DN:  %s
+INFO_LDIF_CONNHANDLER_REFERRAL_URL=Referral URL:  %s
+SEVERE_ERR_LDIF_CONNHANDLER_IO_ERROR=An I/O error occurred while the LDIF \
+ connection handler was processing LDIF file %s:  %s
+SEVERE_ERR_LDIF_CONNHANDLER_CANNOT_RENAME=An error occurred while the \
+ LDIF connection handler was attempting to rename partially-processed file \
+ from %s to %s:  %s
+SEVERE_ERR_LDIF_CONNHANDLER_CANNOT_DELETE=An error occurred while the \
+ LDIF connection handler was attempting to delete processed file %s:  %s
+SEVERE_ERR_CONNHANDLER_ADDRESS_INUSE=Address already in use
+INFO_SNMP_CONNHANDLER_DESCRIPTION_LISTEN_PORT=SNMP port on \
+ which this connection handler accepts SNMP requests.  Changes \
+ to this configuration attribute will not take effect until the connection \
+ handler is disabled and re-enabled, or until the Directory Server is \
+ restarted
+SEVERE_ERR_SNMP_CONNHANDLER_NO_LISTEN_PORT=No listen port was defined \
+ using configuration ds-cfg-listen-port in configuration entry %s.  This is a \
+ required attribute
+SEVERE_ERR_SNMP_CONNHANDLER_CANNOT_DETERMINE_LISTEN_PORT=An unexpected \
+ error occurred while processing the ds-cfg-listen-port attribute in \
+ configuration entry %s, which is used to specify the port on which to listen \
+ for client connections:  %s
+SEVERE_ERR_SNMP_CONNHANDLER_CANNOT_BE_STARTED=An unexpected \
+ error occurred when this connection handler started
+SEVERE_ERR_SNMP_CONNHANDLER_NO_CONFIGURATION=No Configuration was defined \
+ for this connection handler. The configuration parameters ds-cfg-listen-port \
+ and ds-cfg-trap-port are required by the connection handler to start
+SEVERE_ERR_SNMP_CONNHANDLER_TRAPS_DESTINATION=Traps Destination %s is \
+ an unknown host. Traps will not be sent to this destination
+SEVERE_ERR_SNMP_CONNHANDLER_NO_OPENDMK_JARFILES=You do not have the \
+ appropriate OpenDMK jar files to enable the SNMP Connection Handler. \
+ Please go under http://opendmk.dev.java.net and set the \
+ opendmk-jarfile configuration parameter to set the full path \
+ of the required jdmkrt.jar file. The SNMP connection Handler didn't started
+SEVERE_ERR_SNMP_CONNHANDLER_BAD_CONFIGURATION=Cannot initialize the \
+ SNMP Connection Handler. Please check the configuration attributes
+SEVERE_ERR_SNMP_CONNHANDLER_NO_VALID_TRAP_DESTINATIONS=No valid trap \
+ destinations has been found. No trap will be sent
+SEVERE_ERR_ASN1_READ_ERROR=An error occured while accessing the \
+ underlying data source: %s
+SEVERE_ERR_ASN1_EOF_ERROR=An unexpected end of file reached while trying \
+ to read %d bytes from the underlying data source
+SEVERE_ERR_ASN1_INVALID_STATE=Invalid reader state: %d
+SEVERE_ERR_SUBTREE_DELETE_INVALID_CONTROL_VALUE=Cannot decode the provided \
+ subtree delete control because it contains a value
+ SEVERE_ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE=An error occurred \
+ while attempting to initialize the SSL context for use in the LDAP \
+ Connection Handler:  %s
+MILD_ERR_LDAP_UNSUPPORTED_PROTOCOL_VERSION=The Directory Server does not \
+ support LDAP protocol version %d.  This connection will be closed
+SEVERE_ERR_SNMP_CONNHANDLER_OPENDMK_JARFILES_DOES_NOT_EXIST=The specified \
+ OpenDMK jar file '%s' could not be found.  Verify that the value set in the \
+ opendmk-jarfile configuration parameter of the SNMP connection handler is the \
+ valid path to the jdmkrt.jar file and that the file is accessible
+SEVERE_ERR_SNMP_CONNHANDLER_OPENDMK_JARFILES_NOT_OPERATIONAL=The required \
+ classes could not be loaded using jar file '%s'.  Verify that the jar file \
+ is not corrupted
+MILD_ERR_ASN1_UNEXPECTED_TAG=Encountered unexpected tag while reading \
+ ASN.1 element (expected=%d, got=%d)
+SEVERE_ERR_AUTHZIDREQ_CONTROL_HAS_VALUE=Cannot decode the provided \
+ control as an authorization identity request control because the provided \
+ control had a value but the authorization identity request control should not \
+ have a value
+MILD_ERR_LDAP_FILTER_BAD_SUBSTRING=The search filter "%s" cannot be \
+ parsed because it contains a malformed substring filter component "%s"
+MILD_ERR_MVFILTER_BAD_FILTER_AND=The provided filter \
+ "%s" cannot be used as a matched values filter because "and" filters are \
+ not allowed
+MILD_ERR_MVFILTER_BAD_FILTER_OR=The provided filter \
+ "%s" cannot be used as a matched values filter because "or" filters are \
+ not allowed
+MILD_ERR_MVFILTER_BAD_FILTER_NOT=The provided filter \
+ "%s" cannot be used as a matched values filter because "not" filters are \
+ not allowed
+MILD_ERR_MVFILTER_BAD_FILTER_EXT=The provided filter \
+ "%s" cannot be used as a matched values filter because extensible match \
+ filters requesting DN attributes are not allowed
+MILD_ERR_MVFILTER_BAD_FILTER_UNRECOGNIZED=The provided filter \
+ "%s" cannot be used as a matched values filter because filters of type %d are \
+ not allowed
+MILD_ERR_CANNOT_DECODE_CONTROL_VALUE=Cannot decode the provided \
+ control %s because an error occurred while attempting to \
+ decode the control value:  %s
+MILD_ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED=Cannot encode the end of the ASN.1 \
+ sequence or set because the start of the sequence was not written
+MILD_ERR_NO_SEARCH_RESULT_ENTRIES=The search request succeeded \
+ but did not return any search result entries when one was expected
+MILD_ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES=The search request succeeded \
+ but returned %d search result entry when only one was expected
+MILD_ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES=The search request succeeded \
+ but returned a search result reference containing the following URI: %s
+#
+# Utility messages
+#
+MILD_ERR_BASE64_DECODE_INVALID_LENGTH=The value %s cannot be base64-decoded \
+ because it does not have a length that is a multiple of four bytes
+MILD_ERR_BASE64_DECODE_INVALID_CHARACTER=The value %s cannot be \
+ base64-decoded because it contains an illegal character %c that is not \
+ allowed in base64-encoded values
+MILD_ERR_HEX_DECODE_INVALID_LENGTH=The value %s cannot be decoded as a \
+ hexadecimal string because it does not have a length that is a multiple of \
+ two bytes
+MILD_ERR_HEX_DECODE_INVALID_CHARACTER=The value %s cannot be decoded as a \
+ hexadecimal string because it contains an illegal character %c that is not a \
+ valid hexadecimal digit
+MILD_ERR_LDIF_INVALID_LEADING_SPACE=Unable to parse line %d ("%s") from the \
+ LDIF source because the line started with a space but there were no previous \
+ lines in the entry to which this line could be appended
+MILD_ERR_LDIF_NO_ATTR_NAME=Unable to parse LDIF entry starting at line %d \
+ because the line "%s" does not include an attribute name
+MILD_ERR_LDIF_NO_DN=Unable to parse LDIF entry starting at line %d because \
+ the first line does not contain a DN (the first line was "%s"
+MILD_ERR_LDIF_INVALID_DN_SEPARATOR=Unable to parse LDIF entry starting at \
+ line %d because line "%s" contained an invalid separator between the "dn" \
+ prefix and the actual distinguished name
+MILD_ERR_LDIF_INVALID_DN=Unable to parse LDIF entry starting at line %d \
+ because an error occurred while trying to parse the value of line "%s" as a \
+ distinguished name:  %s
+MILD_ERR_LDIF_INVALID_ATTR_SEPARATOR=Unable to parse LDIF entry %s \
+ starting at line %d because line "%s" contained an invalid separator between \
+ the attribute name and value
+MILD_ERR_LDIF_COULD_NOT_BASE64_DECODE_DN=Unable to parse LDIF entry \
+ starting at line %d because it was not possible to base64-decode the DN on \
+ line "%s":  %s
+MILD_ERR_LDIF_COULD_NOT_BASE64_DECODE_ATTR=Unable to parse LDIF entry %s \
+ starting at line %d because it was not possible to base64-decode the \
+ attribute on line "%s":  %s
+MILD_WARN_LDIF_DUPLICATE_OBJECTCLASS=Entry %s read from LDIF starting at \
+ line %d includes a duplicate objectclass value %s.  The second occurrence of \
+ that objectclass has been skipped
+MILD_WARN_LDIF_DUPLICATE_ATTR=Entry %s read from LDIF starting at line %d \
+ includes a duplicate attribute %s with value %s.  The second occurrence of \
+ that attribute value has been skipped
+MILD_ERR_LDIF_MULTIPLE_VALUES_FOR_SINGLE_VALUED_ATTR=Entry %s starting at \
+ line %d includes multiple values for single-valued attribute %s
+MILD_ERR_LDIF_INVALID_ATTR_SYNTAX=Unable to parse LDIF entry %s starting \
+ at line %d because it has an invalid value "%s" for attribute %s:  %s
+MILD_ERR_LDIF_SCHEMA_VIOLATION=Entry %s read from LDIF starting at line %d \
+ is not valid because it violates the server's schema configuration:  %s
+SEVERE_ERR_LDIF_FILE_EXISTS=The specified LDIF file %s already exists and \
+ the export configuration indicates that no attempt should be made to append \
+ to or replace the file
+MILD_ERR_LDIF_INVALID_URL=Unable to parse LDIF entry %s starting at line \
+ %d because the value of attribute %s was to be read from a URL but the URL \
+ was invalid:  %s
+MILD_ERR_LDIF_URL_IO_ERROR=Unable to parse LDIF entry %s starting at line \
+ %d because the value of attribute %s was to be read from URL %s but an error \
+ occurred while trying to read that content:  %s
+SEVERE_ERR_REJECT_FILE_EXISTS=The specified reject file %s already exists \
+ and the import configuration indicates that no attempt should be made to \
+ append to or replace the file
+SEVERE_ERR_LDIF_COULD_NOT_EVALUATE_FILTERS_FOR_IMPORT=An error occurred \
+ while attempting to determine whether LDIF entry "%s" starting at line %d \
+ should be imported as a result of the include and exclude filter \
+ configuration:  %s
+SEVERE_ERR_LDIF_COULD_NOT_EVALUATE_FILTERS_FOR_EXPORT=An error occurred \
+ while attempting to determine whether LDIF entry "%s" should be exported as a \
+ result of the include and exclude filter configuration:  %s
+SEVERE_ERR_LDIF_INVALID_DELETE_ATTRIBUTES=Error in the LDIF change record \
+ entry. Invalid attributes specified for the delete operation
+SEVERE_ERR_LDIF_NO_MOD_DN_ATTRIBUTES=Error in the LDIF change record \
+ entry. No attributes specified for the mod DN operation
+SEVERE_ERR_LDIF_NO_DELETE_OLDRDN_ATTRIBUTE=Error in the LDIF change record \
+ entry. No delete old RDN attribute specified for the mod DN operation
+SEVERE_ERR_LDIF_INVALID_DELETE_OLDRDN_ATTRIBUTE=Error in the LDIF change \
+ record entry. Invalid value "%s" for the delete old RDN attribute specified \
+ for the mod DN operation
+SEVERE_ERR_LDIF_INVALID_CHANGERECORD_ATTRIBUTE=Error in the LDIF change \
+ record entry. Invalid attribute "%s" specified. Expecting attribute "%s"
+SEVERE_ERR_LDIF_INVALID_MODIFY_ATTRIBUTE=Error in the LDIF change record \
+ entry. Invalid attribute "%s" specified. Expecting one of the following \
+ attributes "%s"
+SEVERE_ERR_LDIF_INVALID_CHANGETYPE_ATTRIBUTE=Error in the LDIF change \
+ record entry. Invalid value "%s" for the changetype specified. Expecting one \
+ of the following values "%s"
+SEVERE_ERR_LDIF_INVALID_MODIFY_ATTRIBUTE_VAL=Error in the LDIF change \
+ record entry. Invalid value for the "%s" attribute specified
+SEVERE_ERR_SCHEMANAME_EMPTY_VALUE=The provided value could not be parsed \
+ to determine whether it contained a valid schema element name or OID because \
+ it was null or empty
+SEVERE_ERR_SCHEMANAME_ILLEGAL_CHAR=The provided value "%s" does not \
+ contain a valid schema element name or OID because it contains an illegal \
+ character %c at position %d
+SEVERE_ERR_SCHEMANAME_CONSECUTIVE_PERIODS=The provided value "%s" does not \
+ contain a valid schema element name or OID because the numeric OID contains \
+ two consecutive periods at position %d
+SEVERE_ERR_ARG_NO_IDENTIFIER=The %s argument does not have either a \
+ single-character or a long identifier that may be used to specify it.  At \
+ least one of these must be specified for each argument
+SEVERE_ERR_ARG_NO_VALUE_PLACEHOLDER=The %s argument is configured to take \
+ a value but no value placeholder has been defined for it
+SEVERE_ERR_ARG_NO_INT_VALUE=The %s argument does not have any value that \
+ may be retrieved as an integer
+SEVERE_ERR_ARG_CANNOT_DECODE_AS_INT=The provided value "%s" for the %s \
+ argument cannot be decoded as an integer
+SEVERE_ERR_ARG_INT_MULTIPLE_VALUES=The %s argument has multiple values and \
+ therefore cannot be decoded as a single integer value
+SEVERE_ERR_ARG_NO_BOOLEAN_VALUE=The %s argument does not have any value \
+ that may be retrieved as a Boolean
+SEVERE_ERR_ARG_CANNOT_DECODE_AS_BOOLEAN=The provided value "%s" for the %s \
+ argument cannot be decoded as a Boolean
+SEVERE_ERR_ARG_BOOLEAN_MULTIPLE_VALUES=The %s argument has multiple values \
+ and therefore cannot be decoded as a single Boolean value
+SEVERE_ERR_INTARG_LOWER_BOUND_ABOVE_UPPER_BOUND=The %s argument \
+ configuration is invalid because the lower bound of %d is greater than the \
+ upper bound of %d
+SEVERE_ERR_INTARG_VALUE_BELOW_LOWER_BOUND=The provided %s value %d is \
+ unacceptable because it is below the lower bound of %d
+SEVERE_ERR_INTARG_VALUE_ABOVE_UPPER_BOUND=The provided %s value %d is \
+ unacceptable because it is above the upper bound of %d
+SEVERE_ERR_BOOLEANARG_NO_VALUE_ALLOWED=The provided %s value is \
+ unacceptable because Boolean arguments are never allowed to have values
+SEVERE_ERR_MCARG_VALUE_NOT_ALLOWED=The provided %s value %s is \
+ unacceptable because it is not included in the set of allowed values for that \
+ argument
+SEVERE_ERR_FILEARG_NO_SUCH_FILE=The file %s specified for argument %s does \
+ not exist
+SEVERE_ERR_FILEARG_CANNOT_VERIFY_FILE_EXISTENCE=An error occurred while \
+ trying to verify the existence of file %s specified for argument %s:  %s
+SEVERE_ERR_FILEARG_CANNOT_OPEN_FILE=An error occurred while trying to open \
+ file %s specified for argument %s for reading:  %s
+SEVERE_ERR_FILEARG_CANNOT_READ_FILE=An error occurred while trying to read \
+ from file %s specified for argument %s:  %s
+SEVERE_ERR_FILEARG_EMPTY_FILE=The file %s specified for argument %s exists \
+ but is empty
+SEVERE_ERR_ARGPARSER_DUPLICATE_SHORT_ID=Cannot add argument %s to the \
+ argument list because its short identifier -%s conflicts with the %s argument \
+ that has already been defined
+SEVERE_ERR_ARGPARSER_DUPLICATE_LONG_ID=Cannot add argument %s to the \
+ argument list because its long identifier --%s conflicts with the %s argument \
+ that has already been defined
+SEVERE_ERR_ARGPARSER_CANNOT_READ_PROPERTIES_FILE=An error occurred while \
+ attempting to read the contents of the argument properties file %s:  %s
+SEVERE_ERR_ARGPARSER_TOO_MANY_TRAILING_ARGS=The provided set of \
+ command-line arguments contained too many unnamed trailing arguments.  The \
+ maximum number of allowed trailing arguments is %d
+SEVERE_ERR_ARGPARSER_LONG_ARG_WITHOUT_NAME=The provided argument "%s" is \
+ invalid because it does not include the argument name
+SEVERE_ERR_ARGPARSER_NO_ARGUMENT_WITH_LONG_ID=Argument --%s is not allowed \
+ for use with this program
+SEVERE_ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_LONG_ID=Argument --%s \
+ requires a value but none was provided
+SEVERE_ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_LONG_ID=The provided value \
+ "%s" for argument --%s is not acceptable:  %s
+SEVERE_ERR_ARGPARSER_NOT_MULTIVALUED_FOR_LONG_ID=The argument --%s was \
+ included multiple times in the provided set of arguments but it does not \
+ allow multiple values
+SEVERE_ERR_ARGPARSER_ARG_FOR_LONG_ID_DOESNT_TAKE_VALUE=A value was \
+ provided for argument --%s but that argument does not take a value
+SEVERE_ERR_ARGPARSER_INVALID_DASH_AS_ARGUMENT=The dash character by itself \
+ is invalid for use as an argument name
+SEVERE_ERR_ARGPARSER_NO_ARGUMENT_WITH_SHORT_ID=Argument -%s is not allowed \
+ for use with this program
+SEVERE_ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_SHORT_ID=Argument -%s \
+ requires a value but none was provided
+SEVERE_ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_SHORT_ID=The provided value \
+ "%s" for argument -%s is not acceptable:  %s
+SEVERE_ERR_ARGPARSER_NOT_MULTIVALUED_FOR_SHORT_ID=The argument -%s was \
+ included multiple times in the provided set of arguments but it does not \
+ allow multiple values
+SEVERE_ERR_ARGPARSER_CANT_MIX_ARGS_WITH_VALUES=The provided argument block \
+ '-%s%s' is illegal because the '%s' argument requires a value but is in the \
+ same block as at least one other argument that doesn't require a value
+SEVERE_ERR_ARGPARSER_DISALLOWED_TRAILING_ARGUMENT=Argument "%s" does not \
+ start with one or two dashes and unnamed trailing arguments are not allowed
+SEVERE_ERR_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS=At least %d unnamed \
+ trailing arguments are required in the argument list, but too few were \
+ provided
+SEVERE_ERR_ARGPARSER_NO_VALUE_FOR_REQUIRED_ARG=The argument %s is required \
+ to have a value but none was provided in the argument list and no default \
+ value is available
+SEVERE_ERR_MOVEFILE_NO_SUCH_FILE=The file to move %s does not exist
+SEVERE_ERR_MOVEFILE_NOT_FILE=The file to move %s exists but is not a file
+SEVERE_ERR_MOVEFILE_NO_SUCH_DIRECTORY=The target directory %s does not \
+ exist
+SEVERE_ERR_MOVEFILE_NOT_DIRECTORY=The target directory %s exists but is \
+ not a directory
+SEVERE_ERR_EMAILMSG_INVALID_SENDER_ADDRESS=The provided sender address %s \
+ is invalid:  %s
+SEVERE_ERR_EMAILMSG_INVALID_RECIPIENT_ADDRESS=The provided recipient \
+ address %s is invalid:  %s
+SEVERE_ERR_EMAILMSG_CANNOT_SEND=The specified e-mail message could not be \
+ sent using any of the configured mail servers
+SEVERE_ERR_ARG_SUBCOMMAND_DUPLICATE_SUBCOMMAND=The argument parser already \
+ has a %s subcommand
+SEVERE_ERR_ARG_SUBCOMMAND_DUPLICATE_ARGUMENT_NAME=There are multiple \
+ arguments for subcommand %s with name %s
+SEVERE_ERR_ARG_SUBCOMMAND_ARGUMENT_GLOBAL_CONFLICT=Argument %s for \
+ subcommand %s conflicts with a global argument with the same name
+SEVERE_ERR_ARG_SUBCOMMAND_DUPLICATE_SHORT_ID=Argument %s for subcommand %s \
+ has a short identifier -%s that conflicts with that of argument %s
+SEVERE_ERR_ARG_SUBCOMMAND_ARGUMENT_SHORT_ID_GLOBAL_CONFLICT=Argument %s \
+ for subcommand %s has a short ID -%s that conflicts with that of global \
+ argument %s
+SEVERE_ERR_ARG_SUBCOMMAND_DUPLICATE_LONG_ID=Argument %s for subcommand %s \
+ has a long identifier --%s that conflicts with that of argument %s
+SEVERE_ERR_ARG_SUBCOMMAND_ARGUMENT_LONG_ID_GLOBAL_CONFLICT=Argument %s for \
+ subcommand %s has a long ID --%s that conflicts with that of global argument \
+ %s
+SEVERE_ERR_SUBCMDPARSER_DUPLICATE_GLOBAL_ARG_NAME=There is already another \
+ global argument named "%s"
+SEVERE_ERR_SUBCMDPARSER_GLOBAL_ARG_NAME_SUBCMD_CONFLICT=The argument name \
+ %s conflicts with the name of another argument associated with the %s \
+ subcommand
+SEVERE_ERR_SUBCMDPARSER_DUPLICATE_GLOBAL_ARG_SHORT_ID=Short ID -%s for \
+ global argument %s conflicts with the short ID of another global argument %s
+SEVERE_ERR_SUBCMDPARSER_GLOBAL_ARG_SHORT_ID_CONFLICT=Short ID -%s for \
+ global argument %s conflicts with the short ID for the %s argument associated \
+ with subcommand %s
+SEVERE_ERR_SUBCMDPARSER_DUPLICATE_GLOBAL_ARG_LONG_ID=Long ID --%s for \
+ global argument %s conflicts with the long ID of another global argument %s
+SEVERE_ERR_SUBCMDPARSER_GLOBAL_ARG_LONG_ID_CONFLICT=Long ID --%s for \
+ global argument %s conflicts with the long ID for the %s argument associated \
+ with subcommand %s
+SEVERE_ERR_SUBCMDPARSER_CANNOT_READ_PROPERTIES_FILE=An error occurred \
+ while attempting to read the contents of the argument properties file %s:  %s
+SEVERE_ERR_SUBCMDPARSER_LONG_ARG_WITHOUT_NAME=The provided command-line \
+ argument %s does not contain an argument name
+SEVERE_ERR_SUBCMDPARSER_NO_GLOBAL_ARGUMENT_FOR_LONG_ID=The provided \
+ argument --%s is not a valid global argument identifier
+SEVERE_ERR_SUBCMDPARSER_NO_ARGUMENT_FOR_LONG_ID=The provided argument --%s \
+ is not a valid global or subcommand argument identifier
+SEVERE_ERR_SUBCMDPARSER_NO_VALUE_FOR_ARGUMENT_WITH_LONG_ID=Command-line \
+ argument --%s requires a value but none was given
+SEVERE_ERR_SUBCMDPARSER_VALUE_UNACCEPTABLE_FOR_LONG_ID=The provided value \
+ "%s" for argument --%s is not acceptable:  %s
+SEVERE_ERR_SUBCMDPARSER_NOT_MULTIVALUED_FOR_LONG_ID=The argument --%s was \
+ included multiple times in the provided set of arguments but it does not \
+ allow multiple values
+SEVERE_ERR_SUBCMDPARSER_ARG_FOR_LONG_ID_DOESNT_TAKE_VALUE=A value was \
+ provided for argument --%s but that argument does not take a value
+SEVERE_ERR_SUBCMDPARSER_INVALID_DASH_AS_ARGUMENT=The dash character by \
+ itself is invalid for use as an argument name
+SEVERE_ERR_SUBCMDPARSER_NO_GLOBAL_ARGUMENT_FOR_SHORT_ID=The provided \
+ argument -%s is not a valid global argument identifier
+SEVERE_ERR_SUBCMDPARSER_NO_ARGUMENT_FOR_SHORT_ID=The provided argument \
+ -%s is not a valid global or subcommand argument identifier
+SEVERE_ERR_SUBCMDPARSER_NO_VALUE_FOR_ARGUMENT_WITH_SHORT_ID=Argument -%s \
+ requires a value but none was provided
+SEVERE_ERR_SUBCMDPARSER_VALUE_UNACCEPTABLE_FOR_SHORT_ID=The provided \
+ value "%s" for argument -%s is not acceptable:  %s
+SEVERE_ERR_SUBCMDPARSER_NOT_MULTIVALUED_FOR_SHORT_ID=The argument -%s was \
+ included multiple times in the provided set of arguments but it does not \
+ allow multiple values
+SEVERE_ERR_SUBCMDPARSER_CANT_MIX_ARGS_WITH_VALUES=The provided argument \
+ block '-%s%s' is illegal because the '%s' argument requires a value but is in \
+ the same block as at least one other argument that doesn't require a value
+SEVERE_ERR_SUBCMDPARSER_INVALID_ARGUMENT=The provided argument "%s" is \
+ not recognized
+SEVERE_ERR_SUBCMDPARSER_MULTIPLE_SUBCOMMANDS=The provided argument %s \
+ specifies a valid subcommand, but another subcommand %s was also given.  Only \
+ a single subcommand may be provided
+SEVERE_ERR_SUBCMDPARSER_NO_VALUE_FOR_REQUIRED_ARG=The argument %s is \
+ required to have a value but none was provided in the argument list and no \
+ default value is available
+SEVERE_ERR_LDAPURL_NO_COLON_SLASH_SLASH=The provided string "%s" cannot \
+ be decoded as an LDAP URL because it does not contain the necessary :// \
+ component to separate the scheme from the rest of the URL
+SEVERE_ERR_LDAPURL_NO_SCHEME=The provided string "%s" cannot be decoded \
+ as an LDAP URL because it does not contain a protocol scheme
+SEVERE_ERR_LDAPURL_BAD_SCHEME=The provided string "%s" cannot be decoded \
+ as an LDAP URL because the protocol scheme "%s" is invalid. It should be
+ either "ldap" or "ldaps"
+SEVERE_ERR_LDAPURL_NO_HOST=The provided string "%s" cannot be decoded as \
+ an LDAP URL because it does not contain a host before the colon to specify \
+ the port number
+SEVERE_ERR_LDAPURL_NO_PORT=The provided string "%s" cannot be decoded as \
+ an LDAP URL because it does not contain a port number after the colon \
+ following the host
+SEVERE_ERR_LDAPURL_CANNOT_DECODE_PORT=The provided string "%s" cannot be \
+ decoded as an LDAP URL because the port number portion %s cannot be decoded \
+ as an integer
+SEVERE_ERR_LDAPURL_INVALID_PORT=The provided string "%s" cannot be \
+ decoded as an LDAP URL because the provided port number %d is not within the \
+ valid range between 1 and 65535
+SEVERE_ERR_LDAPURL_BAD_PORT=The provided port number %d is not within the \
+ valid range between 1 and 65535
+SEVERE_ERR_LDAPURL_INVALID_DN=The provided string "%s" cannot be \
+ decoded as an LDAP URL because the provided distinguished name could \
+ not be parsed: %s
+SEVERE_ERR_LDAPURL_INVALID_FILTER=The provided string "%s" cannot be \
+ decoded as an LDAP URL because the provided filter could \
+ not be parsed: %s
+SEVERE_ERR_LDAPURL_INVALID_SCOPE_STRING=The provided string "%s" cannot \
+ be decoded as an LDAP URL because the scope string %s was not one of the \
+ allowed values of base, one, sub, or subordinate
+SEVERE_ERR_LDAPURL_PERCENT_TOO_CLOSE_TO_END=The provided URL component \
+ "%s" could not be decoded because the percent character at byte %d was not \
+ followed by two hexadecimal digits
+SEVERE_ERR_LDAPURL_INVALID_HEX_BYTE=The provided URL component "%s" could \
+ not be decoded because the character at byte %d was not a valid hexadecimal \
+ digit
+SEVERE_ERR_LDAPURL_CANNOT_CREATE_UTF8_STRING=An error occurred while \
+ attempting to represent a byte array as a UTF-8 string during the course of \
+ decoding a portion of an LDAP URL:  %s
+MILD_ERR_CHARSET_NO_COLON=Cannot decode value "%s" as a named character \
+ set because it does not contain a colon to separate the name from the set of \
+ characters
+MILD_ERR_CHARSET_CONSTRUCTOR_NO_NAME=The named character set is invalid \
+ because it does not contain a name
+MILD_ERR_CHARSET_CONSTRUCTOR_INVALID_NAME_CHAR=The named character set is \
+ invalid because the provide name "%s" has an invalid character at position \
+ %d.  Only ASCII alphabetic characters are allowed in the name
+MILD_ERR_CHARSET_NO_NAME=Cannot decode value "%s" as a named character \
+ set because it does not contain a name to use for the character set
+MILD_ERR_CHARSET_NO_CHARS=Cannot decode value "%s" as a named character \
+ set because there are no characters to include in the set
+INFO_TIME_IN_SECONDS=%d seconds
+INFO_TIME_IN_MINUTES_SECONDS=%d minutes, %d seconds
+INFO_TIME_IN_HOURS_MINUTES_SECONDS=%d hours, %d minutes, %d seconds
+INFO_TIME_IN_DAYS_HOURS_MINUTES_SECONDS=%d days, %d hours, %d minutes, %d \
+ seconds
+INFO_ACCTNOTTYPE_ACCOUNT_TEMPORARILY_LOCKED=account-temporarily-locked
+INFO_ACCTNOTTYPE_ACCOUNT_PERMANENTLY_LOCKED=account-permanently-locked
+INFO_ACCTNOTTYPE_ACCOUNT_UNLOCKED=account-unlocked
+INFO_ACCTNOTTYPE_ACCOUNT_IDLE_LOCKED=account-idle-locked
+INFO_ACCTNOTTYPE_ACCOUNT_RESET_LOCKED=account-reset-locked
+INFO_ACCTNOTTYPE_ACCOUNT_DISABLED=account-disabled
+INFO_ACCTNOTTYPE_ACCOUNT_ENABLED=account-enabled
+INFO_ACCTNOTTYPE_ACCOUNT_EXPIRED=account-expired
+INFO_ACCTNOTTYPE_PASSWORD_EXPIRED=password-expired
+INFO_ACCTNOTTYPE_PASSWORD_EXPIRING=password-expiring
+INFO_ACCTNOTTYPE_PASSWORD_RESET=password-reset
+INFO_ACCTNOTTYPE_PASSWORD_CHANGED=password-changed
+MILD_ERR_FILEPERM_SET_NO_SUCH_FILE=Unable to set permissions for file %s \
+ because it does not exist
+MILD_ERR_FILEPERM_CANNOT_EXEC_CHMOD=Unable to execute the chmod command \
+ to set file permissions on %s:  %s
+SEVERE_ERR_FILEPERM_SET_JAVA_EXCEPTION=One or more exceptions were thrown \
+ in the process of updating the file permissions for %s.  Some of the \
+ permissions for the file may have been altered
+SEVERE_ERR_FILEPERM_SET_JAVA_FAILED_ALTERED=One or more updates to the \
+ file permissions for %s failed, but at least one update was successful.  Some \
+ of the permissions for the file may have been altered
+SEVERE_ERR_FILEPERM_SET_JAVA_FAILED_UNALTERED=All of the attempts to \
+ update the file permissions for %s failed.  The file should be left with its \
+ original permissions
+MILD_ERR_FILEPERM_INVALID_UNIX_MODE_STRING=The provided string %s does \
+ not represent a valid UNIX file mode.  UNIX file modes must be a \
+ three-character string in which each character is a numeric digit between \
+ zero and seven
+MILD_ERR_EXEC_DISABLED=The %s command will not be allowed because the \
+ Directory Server has been configured to refuse the use of the exec method
+SEVERE_ERR_VALIDATOR_PRECONDITION_NOT_MET=A precondition of the invoked \
+ method was not met.  This This usually means there is a defect somewhere in \
+ the call stack.  Details: %s
+INFO_GLOBAL_OPTIONS=Global Options:
+INFO_GLOBAL_OPTIONS_REFERENCE=See "%s --help"
+INFO_SUBCMD_OPTIONS=SubCommand Options:
+INFO_ARGPARSER_USAGE=Usage:
+INFO_SUBCMDPARSER_SUBCMD_HEADING=Available subcommands:
+INFO_SUBCMDPARSER_SUBCMD_REFERENCE=See "%s --help-{category}"
+INFO_SUBCMDPARSER_GLOBAL_HEADING=The global options are:
+INFO_GLOBAL_HELP_REFERENCE=See "%s --help" to get more usage help
+SEVERE_ERR_RENAMEFILE_CANNOT_RENAME=Failed to rename file %s to %s
+SEVERE_ERR_RENAMEFILE_CANNOT_DELETE_TARGET=Failed to delete target file \
+ %s.  Make sure the file is not currently in use by this or another \
+ application
+SEVERE_ERR_EXPCHECK_TRUSTMGR_CLIENT_CERT_EXPIRED=Refusing to trust client \
+ or issuer certificate '%s' because it expired on %s
+SEVERE_ERR_EXPCHECK_TRUSTMGR_CLIENT_CERT_NOT_YET_VALID=Refusing to trust \
+ client or issuer certificate '%s' because it is not valid until %s
+SEVERE_ERR_EXPCHECK_TRUSTMGR_SERVER_CERT_EXPIRED=Refusing to trust server \
+ or issuer certificate '%s' because it expired on %s
+SEVERE_ERR_EXPCHECK_TRUSTMGR_SERVER_CERT_NOT_YET_VALID=Refusing to trust \
+ server or issuer certificate '%s' because it is not valid until %s
+MILD_WARN_LDIF_VALUE_VIOLATES_SYNTAX=Entry %s read from LDIF starting at \
+ line %d includes value "%s" for attribute %s that is invalid according to the \
+ associated syntax:  %s
+SEVERE_ERR_SKIP_FILE_EXISTS=The specified skip file %s already exists and \
+ the import configuration indicates that no attempt should be made to append \
+ to or replace the file
+MILD_ERR_LDIF_SKIP=Skipping entry %s because the DN is not one that \
+ should be included based on the include and exclude branches
+INFO_SUBCMDPARSER_SUBCMD_HELP_HEADING=To get the list of subcommands use:
+SEVERE_ERR_EMBEDUTILS_SERVER_ALREADY_RUNNING=The Directory Server cannot \
+ be started because it is already running
+INFO_SUBCMDPARSER_OPTIONS={options}
+INFO_SUBCMDPARSER_SUBCMD_AND_OPTIONS={subcommand} {options}
+INFO_SUBCMDPARSER_WHERE_OPTIONS_INCLUDE=Where {options} include:
+INFO_EMAIL_TOOL_DESCRIPTION=Send an e-mail message via SMTP
+INFO_EMAIL_HOST_DESCRIPTION=The address of the SMTP server to use to send \
+ the message
+INFO_EMAIL_FROM_DESCRIPTION=The address to use for the message sender
+INFO_EMAIL_TO_DESCRIPTION=The address to use for the message recipient
+INFO_EMAIL_SUBJECT_DESCRIPTION=The subject to use for the e-mail message
+INFO_EMAIL_BODY_DESCRIPTION=The path to the file containing the text for \
+ the message body
+INFO_EMAIL_ATTACH_DESCRIPTION=The path to a file to attach to the e-mail \
+ message
+INFO_EMAIL_HELP_DESCRIPTION=Display this usage information
+SEVERE_ERR_EMAIL_NO_SUCH_BODY_FILE=The file %s specified as the body file \
+ for the e-mail message does not exist
+SEVERE_ERR_EMAIL_CANNOT_PROCESS_BODY_FILE=An error occurred while \
+ attempting to process message body file %s:  %s
+SEVERE_ERR_EMAIL_NO_SUCH_ATTACHMENT_FILE=The attachment file %s does not \
+ exist
+SEVERE_ERR_EMAIL_CANNOT_ATTACH_FILE=An error occurred while trying to \
+ attach file %s:  %s
+SEVERE_ERR_EMAIL_CANNOT_SEND_MESSAGE=An error occurred while trying to \
+ send the e-mail message:  %s
+INFO_BASE64_TOOL_DESCRIPTION=This utility can be used to encode and \
+ decode information using base64
+INFO_BASE64_HELP_DESCRIPTION=Display this usage information
+INFO_BASE64_DECODE_DESCRIPTION=Decode base64-encoded information into \
+ raw data
+INFO_BASE64_ENCODE_DESCRIPTION=Encode raw data using base64
+INFO_BASE64_ENCODED_DATA_DESCRIPTION=The base64-encoded data to be decoded
+INFO_BASE64_ENCODED_FILE_DESCRIPTION=The path to a file containing the \
+ base64-encoded data to be decoded
+INFO_BASE64_RAW_DATA_DESCRIPTION=The raw data to be base64 encoded
+INFO_BASE64_RAW_FILE_DESCRIPTION=The path to a file containing the raw \
+ data to be base64 encoded
+INFO_BASE64_TO_ENCODED_FILE_DESCRIPTION=The path to a file to which the \
+ base64-encoded data should be written
+INFO_BASE64_TO_RAW_FILE_DESCRIPTION=The path to a file to which the raw \
+ base64-decoded data should be written
+SEVERE_ERR_BASE64_CANNOT_READ_RAW_DATA=An error occurred while attempting \
+ to read the raw data to encode:  %s
+SEVERE_ERR_BASE64_CANNOT_WRITE_ENCODED_DATA=An error occurred while \
+ attempting to write the encoded data:  %s
+SEVERE_ERR_BASE64_CANNOT_READ_ENCODED_DATA=An error occurred while \
+ attempting to read the base64-encoded data:  %s
+SEVERE_ERR_BASE64_CANNOT_WRITE_RAW_DATA=An error occurred while \
+ attempting to write the decoded data:  %s
+SEVERE_ERR_BASE64_UNKNOWN_SUBCOMMAND=Unknown subcommand %s
+INFO_GENERAL_NO=no
+INFO_GENERAL_YES=yes
+SEVERE_ERR_CONSOLE_APP_CONFIRM=Invalid response. Please enter \
+ "%s" or "%s"
+INFO_MENU_OPTION_HELP=help
+INFO_MENU_OPTION_HELP_KEY=?
+INFO_MENU_OPTION_CANCEL=cancel
+INFO_MENU_OPTION_CANCEL_KEY=c
+INFO_MENU_OPTION_QUIT=quit
+INFO_MENU_OPTION_QUIT_KEY=q
+INFO_MENU_NUMERIC_OPTION=%d)
+INFO_MENU_CHAR_OPTION=%c)
+SEVERE_ERR_MENU_BAD_CHOICE_MULTI=Invalid response. Please enter one or \
+more valid menu options
+SEVERE_ERR_MENU_BAD_CHOICE_SINGLE=Invalid response. Please enter a valid \
+menu option
+SEVERE_ERR_MENU_BAD_CHOICE_MULTI_DUPE=The option "%s" was specified \
+more than once. Please enter one or more valid menu options
+INFO_MENU_PROMPT_SINGLE=Enter choice:
+INFO_MENU_PROMPT_SINGLE_DEFAULT=Enter choice [%s]:
+INFO_MENU_PROMPT_MULTI=Enter one or more choices separated by commas:
+INFO_MENU_PROMPT_MULTI_DEFAULT=Enter one or more choices separated by commas [%s]:
+INFO_MENU_PROMPT_RETURN_TO_CONTINUE=Press RETURN to continue
+INFO_MENU_PROMPT_CONFIRM=%s (%s / %s) [%s]:
+SEVERE_ERR_CONSOLE_INPUT_ERROR=The response could not be read from the console due to the following error: %s
+INFO_MENU_OPTION_BACK=back
+INFO_MENU_OPTION_BACK_KEY=b
+SEVERE_ERR_LDIF_REJECTED_BY_PLUGIN_NOMESSAGE=Rejecting entry %s because \
+ it was rejected by a plugin
+SEVERE_ERR_LDIF_REJECTED_BY_PLUGIN=Rejecting entry %s because it was \
+ rejected by a plugin:  %s
+INFO_LDAP_CONN_PROMPT_SECURITY_LDAP=LDAP
+INFO_LDAP_CONN_PROMPT_SECURITY_USE_SSL=LDAP with SSL
+INFO_LDAP_CONN_PROMPT_SECURITY_USE_START_TLS=LDAP with StartTLS
+INFO_LDAP_CONN_PROMPT_SECURITY_USE_TRUST_ALL=Automatically \
+  trust
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PATH=Truststore path:
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PASSWORD=Password for \
+  truststore '%s':
+INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_NEEDED=Do you want to perform \
+  secure authentication (client side authentication)?
+INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PATH=Keystore path:
+INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PASSWORD=Password for keystore \
+  '%s':
+INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_NAME=Certificate nickname:
+INFO_LDAP_CONN_HEADING_CONNECTION_PARAMETERS=>>>> Specify OpenDS LDAP \
+  connection parameters
+SEVERE_ERR_LDAP_CONN_BAD_HOST_NAME=The hostname "%s" could not be \
+  resolved. Please check you have provided the correct address
+SEVERE_ERR_LDAP_CONN_BAD_PORT_NUMBER=Invalid port number "%s". Please \
+  enter a valid port number between 1 and 65535
+INFO_LDAP_CONN_PROMPT_HOST_NAME=Directory server hostname or IP address \
+  [%s]:
+INFO_LDAP_CONN_PROMPT_PORT_NUMBER=Directory server port number [%d]:
+INFO_LDAP_CONN_PROMPT_BIND_DN=Administrator user bind DN [%s]:
+INFO_LDAP_CONN_PROMPT_SECURITY_USE_SECURE_CTX=How do you want to connect?
+INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE=%d
+SEVERE_ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH=The provided path \
+  is not valid
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_METHOD=How do you want to trust the server certificate?
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE=Use a truststore
+INFO_LDAP_CONN_PROMPT_SECURITY_MANUAL_CHECK=Manually validate
+INFO_LDAP_CONN_PROMPT_SECURITY_SERVER_CERTIFICATE=Server Certificate:
+INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE=%s
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION=Do you trust this server certificate?
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_NO=No
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_SESSION=Yes, for this session only
+INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_ALWAYS=Yes, also add it to a truststore
+INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_DETAILS=View certificate details
+INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_USER_DN=User DN  : %s
+INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_VALIDITY=Validity : From '%s'%n             To '%s'
+INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_ISSUER=Issuer   : %s
+INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_ALIASES=Which certificate do you want to use?
+INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_ALIAS=%s (%s)
+INFO_SUBCMDPARSER_GLOBAL_HEADING_PREFIX=Global %s
+INFO_PROMPT_SINGLE_DEFAULT=%s [%s]:
+INFO_LDAP_CONN_PROMPT_ADMINISTRATOR_UID=Global Administrator User ID [%s]:
+INFO_LDAP_CONN_GLOBAL_ADMINISTRATOR_OR_BINDDN_PROMPT=Global Administrator \
+ User ID, or bind DN if no Global Administrator is defined [%s]:
+INFO_ARGPARSER_USAGE_JAVA_CLASSNAME=Usage:  java %s  {options}
+INFO_ARGPARSER_USAGE_JAVA_SCRIPTNAME=Usage:  %s  {options}
+INFO_ARGPARSER_USAGE_TRAILINGARGS={trailing-arguments}
+MILD_ERR_CONFIRMATION_TRIES_LIMIT_REACHED=Confirmation tries limit reached \
+ (%d)
+SEVERE_ERR_UNEXPECTED=Unexpected error.  Details: %s
+MILD_ERR_TRIES_LIMIT_REACHED=Input tries limit reached (%d)
+INFO_ADMIN_CONN_PROMPT_PORT_NUMBER=Directory server administration port number [%d]:
+MILD_ERR_LDIF_INVALID_ATTR_OPTION=Unable to parse LDIF entry %s starting \
+ at line %d because it has an invalid binary option for attribute %s
+SEVERE_ERR_CERTMGR_INVALID_PKCS11_PATH=Invalid key store path for PKCS11 \
+keystore, it must be %s
+SEVERE_ERR_CERTMGR_INVALID_KEYSTORE_PATH=Key store path %s exists but is \
+not a file
+SEVERE_ERR_CERTMGR_INVALID_PARENT=Parent directory for key store path \
+ %s does not exist or is not a directory
+SEVERE_ERR_CERTMGR_INVALID_STORETYPE=Invalid key store type, it must \
+be one of the following: %s, %s, %s or %s
+SEVERE_ERR_CERTMGR_KEYSTORE_NONEXISTANT=Keystore does not exist, \
+it must exist to retrieve an alias, delete an alias or generate a \
+certificate request
+SEVERE_ERR_CERTMGR_VALIDITY=Validity value %d is invalid, it must \
+be a positive integer
+SEVERE_ERR_CERTMGR_ALIAS_ALREADY_EXISTS= A certificate with the alias \
+%s already exists in the key store
+SEVERE_ERR_CERTMGR_ADD_CERT=The following error occured when \
+adding a certificate with alias %s to the keystore: %s
+SEVERE_ERR_CERTMGR_ALIAS_INVALID=The alias %s is cannot be added to the \
+keystore for one of the following reasons: it already exists in the \
+keystore, or, it is not an instance of a trusted certificate class
+SEVERE_ERR_CERTMGR_CERT_REPLIES_INVALID=The alias %s is an instance of \
+a private key entry, which is not supported being added to the keystore \
+at this time
+SEVERE_ERR_CERTMGR_DELETE_ALIAS=The following error occured when \
+deleting a certificate with alias %s from the keystore: %s
+SEVERE_ERR_CERTMGR_CERT_REQUEST=The following error occured when \
+generating a certificate request with alias %s: %s
+SEVERE_ERR_CERTMGR_GEN_SELF_SIGNED_CERT=The following error occured when \
+generating a self-signed certificate using the alias %s: %s
+SEVERE_ERR_CERTMGR_INVALID_CERT_FILE=The certificate file %s is \
+invalid because it does not exists, or exists, but is not a file
+SEVERE_ERR_CERTMGR_ALIAS_CAN_NOT_DELETE=The alias %s cannot be \
+deleted from the keystore because it does not exist
+SEVERE_ERR_CERTMGR_ALIAS_DOES_NOT_EXIST=The alias %s does not exist \
+in the keystore so its key information cannot be retrieved
+SEVERE_ERR_CERTMGR_ALIAS_INVALID_ENTRY_TYPE=The alias %s is not a \
+valid keystore entry type, so its key information cannot be retrieved
+SEVERE_ERR_CERTMGR_GET_KEY=The key information for alias %s \
+cannot be retrieved because of the following reason: %s
+SEVERE_ERR_CERTMGR_PRIVATE_KEY=The private key for alias %s \
+could not be retrieved because it was not a key related entry
+SEVERE_ERR_CERTMGR_ALIAS_NO_CERTIFICATE=The alias %s does not \
+does not have a certificate associated with it
+SEVERE_ERR_CERTMGR_TRUSTED_CERT=The trusted certificate associated \
+with alias %s could not be added to keystore because of the following \
+reason: %s
+SEVERE_ERR_CERTMGR_FILE_NAME_INVALID=The %s is invalid because it is \
+null
+SEVERE_ERR_CERTMGR_VALUE_INVALID=The argument %s is invalid because it \
+is either null, or has zero length
+SEVERE_ERR_CERTMGR_CLASS_NOT_FOUND=A security class cannot be found \
+in this JVM because of the following reason: %s
+SEVERE_ERR_CERTMGR_SECURITY=The security classes could not be \
+initialized because of the following reason: %s
+SEVERE_ERR_CERTMGR_NO_METHOD=A method needed in the security classes \
+could not be located because of the following reason: %s
+SEVERE_ERR_CERTMGR_CERT_SIGN_REQ_NOT_SUPPORTED=Certificate signing \
+request generation is not supported on JVM supplied by this vendor: %s
+INFO_ARGPARSER_USAGE_DEFAULT_VALUE=Default value: %s
+SEVERE_WARN_EXPORT_LDIF_SET_PERMISSION_FAILED=An error occurred while \
+ setting file permissions for the LDIF file %s: %s
+MILD_ERR_INVALID_ESCAPE_CHAR=The value %s cannot be decoded because %c \
+ is not a valid escape character
+SEVERE_WARN_READ_LDIF_RECORD_NO_CHANGE_RECORD_FOUND=The provided LDIF \
+ content did not contain any LDIF change records
+SEVERE_WARN_READ_LDIF_RECORD_MULTIPLE_CHANGE_RECORDS_FOUND=The provided LDIF \
+ content contained multiple LDIF change records, when only one was expected
+SEVERE_WARN_READ_LDIF_RECORD_CHANGE_RECORD_WRONG_TYPE=The provided LDIF \
+ content did not contain an "%s" change record
+SEVERE_WARN_READ_LDIF_RECORD_UNEXPECTED_IO_ERROR=An unexpected IO error \
+ occurred while reading the provided LDIF content: %s
+#
+# Extension messages
+#
+SEVERE_ERR_PWPSTATE_EXTOP_UNKNOWN_OP_TYPE=The password policy state \
+ extended request included an operation with an invalid or unsupported \
+ operation type of %s
+SEVERE_ERR_PWPSTATE_EXTOP_NO_REQUEST_VALUE=The provided password policy \
+ state extended request did not include a request value
+SEVERE_ERR_PWPSTATE_EXTOP_DECODE_FAILURE=An unexpected error occurred \
+ while attempting to decode password policy state extended request value:  %s
+MILD_ERR_EXTOP_CANCEL_NO_REQUEST_VALUE=Unable to process the cancel \
+ request because the extended operation did not include a request value
+MILD_ERR_EXTOP_CANCEL_CANNOT_DECODE_REQUEST_VALUE=An error occurred while \
+ attempting to decode the value of the cancel extended request:  %s
+MILD_ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST=An unexpected error occurred \
+ while attempting to decode the password modify extended request sequence:  %s
+MILD_ERR_GET_SYMMETRIC_KEY_ASN1_DECODE_EXCEPTION=Cannot decode the \
+ provided symmetric key extended request: %s
+MILD_ERR_GET_SYMMETRIC_KEY_NO_VALUE=Cannot decode the provided \
+ symmetric key extended operation because it does not have a value
+INFO_SASL_UNSUPPORTED_CALLBACK=An unsupported or unexpected callback was \
+ provided to the SASL server for use during %s authentication:  %s
+SEVERE_ERR_SASL_CONTEXT_CREATE_ERROR=An unexpected error occurred while \
+ trying to create an %s context: %s
+SEVERE_ERR_SASL_PROTOCOL_ERROR=SASL %s protocol error: %s
+#
+# Tools messages
+#
+SEVERE_ERR_TOOLS_CANNOT_CREATE_SSL_CONNECTION=Unable to create an SSL \
+ connection to the server: %s
+SEVERE_ERR_TOOLS_SSL_CONNECTION_NOT_INITIALIZED=Unable to create an SSL \
+ connection to the server because the connection factory has not been \
+ initialized
+SEVERE_ERR_TOOLS_CANNOT_LOAD_KEYSTORE_FILE=Cannot load the key store file: \
+ %s
+SEVERE_ERR_TOOLS_CANNOT_INIT_KEYMANAGER=Cannot initialize the key manager \
+ for the key store:%s
+SEVERE_ERR_TOOLS_CANNOT_LOAD_TRUSTSTORE_FILE=Cannot load the key store \
+ file: %s
+SEVERE_ERR_TOOLS_CANNOT_INIT_TRUSTMANAGER=Cannot initialize the key manager \
+ for the key store:%s
+INFO_ENCPW_DESCRIPTION_LISTSCHEMES=List available password storage schemes
+INFO_ENCPW_DESCRIPTION_CLEAR_PW=Clear-text password to encode or to compare \
+ against an encoded password
+INFO_ENCPW_DESCRIPTION_CLEAR_PW_FILE=Clear-text password file
+INFO_ENCPW_DESCRIPTION_ENCODED_PW=Encoded password to compare against the \
+ clear-text password
+INFO_ENCPW_DESCRIPTION_ENCODED_PW_FILE=Encoded password file
+INFO_DESCRIPTION_CONFIG_CLASS=The fully-qualified name of the Java class \
+ to use as the Directory Server configuration handler.  If this is not \
+ provided, then a default of org.opends.server.extensions.ConfigFileHandler \
+ will be used
+INFO_DESCRIPTION_CONFIG_FILE=Path to the Directory Server \
+ configuration file
+INFO_ENCPW_DESCRIPTION_SCHEME=Scheme to use for the encoded password
+INFO_DESCRIPTION_USAGE=Displays this usage information
+SEVERE_ERR_CANNOT_INITIALIZE_ARGS=An unexpected error occurred while \
+ attempting to initialize the command-line arguments:  %s
+SEVERE_ERR_ERROR_PARSING_ARGS=An error occurred while parsing the \
+ command-line arguments:  %s
+SEVERE_ERR_ENCPW_NO_CLEAR_PW=No clear-text password was specified.  Use \
+ --%s or --%s to specify the password to encode
+SEVERE_ERR_ENCPW_NO_SCHEME=No password storage scheme was specified.  Use \
+ the --%s argument to specify the storage scheme
+SEVERE_ERR_SERVER_BOOTSTRAP_ERROR=An unexpected error occurred while \
+ attempting to bootstrap the Directory Server client-side code:  %s
+SEVERE_ERR_CANNOT_LOAD_CONFIG=An error occurred while trying to load the \
+ Directory Server configuration:  %s
+SEVERE_ERR_CANNOT_LOAD_SCHEMA=An error occurred while trying to load the \
+ Directory Server schema:  %s
+SEVERE_ERR_CANNOT_INITIALIZE_CORE_CONFIG=An error occurred while trying to \
+ initialize the core Directory Server configuration:  %s
+SEVERE_ERR_ENCPW_CANNOT_INITIALIZE_STORAGE_SCHEMES=An error occurred while \
+ trying to initialize the Directory Server password storage schemes:  %s
+SEVERE_ERR_ENCPW_NO_STORAGE_SCHEMES=No password storage schemes have been \
+ configured for use in the Directory Server
+SEVERE_ERR_ENCPW_NO_SUCH_SCHEME=Password storage scheme "%s" is not \
+ configured for use in the Directory Server
+INFO_ENCPW_PASSWORDS_MATCH=The provided clear-text and encoded passwords \
+ match
+INFO_ENCPW_PASSWORDS_DO_NOT_MATCH=The provided clear-text and encoded \
+ passwords do not match
+SEVERE_ERR_ENCPW_ENCODED_PASSWORD=Encoded Password:  "%s"
+SEVERE_ERR_ENCPW_CANNOT_ENCODE=An error occurred while attempting to \
+ encode the clear-text password:  %s
+INFO_LDIFEXPORT_DESCRIPTION_LDIF_FILE=Path to the LDIF file to be written
+INFO_LDIFEXPORT_DESCRIPTION_APPEND_TO_LDIF=Append an existing LDIF file \
+ rather than overwriting it
+INFO_LDIFEXPORT_DESCRIPTION_BACKEND_ID=Backend ID for the backend to \
+ export
+INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_BRANCH=Base DN of a branch to exclude \
+ from the LDIF export
+INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_ATTRIBUTE=Attribute to include in the \
+ LDIF export
+INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_ATTRIBUTE=Attribute to exclude from \
+ the LDIF export
+INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_FILTER=Filter to identify entries to \
+ include in the LDIF export
+INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_FILTER=Filter to identify entries to \
+ exclude from the LDIF export
+INFO_LDIFEXPORT_DESCRIPTION_WRAP_COLUMN=Column at which to wrap long lines \
+ (0 for no wrapping)
+INFO_LDIFEXPORT_DESCRIPTION_COMPRESS_LDIF=Compress the LDIF data as it is \
+ exported
+INFO_LDIFEXPORT_DESCRIPTION_ENCRYPT_LDIF=Encrypt the LDIF data as it is \
+ exported
+INFO_LDIFEXPORT_DESCRIPTION_SIGN_HASH=Generate a signed hash of the export \
+ data
+SEVERE_ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER=Unable to decode exclude \
+ filter string "%s" as a valid search filter:  %s
+SEVERE_ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER=Unable to decode include \
+ filter string "%s" as a valid search filter:  %s
+SEVERE_ERR_CANNOT_DECODE_BASE_DN=Unable to decode base DN string "%s" as a \
+ valid distinguished name:  %s
+SEVERE_ERR_LDIFEXPORT_MULTIPLE_BACKENDS_FOR_ID=Multiple Directory Server \
+ backends are configured with the requested backend ID "%s"
+SEVERE_ERR_LDIFEXPORT_NO_BACKENDS_FOR_ID=None of the Directory Server \
+ backends are configured with the requested backend ID "%s"
+SEVERE_ERR_LDIFEXPORT_CANNOT_DECODE_EXCLUDE_BASE=Unable to decode exclude \
+ branch string "%s" as a valid distinguished name:  %s
+SEVERE_ERR_LDIFEXPORT_CANNOT_DECODE_WRAP_COLUMN_AS_INTEGER=Unable to \
+ decode wrap column value "%s" as an integer
+SEVERE_ERR_LDIFEXPORT_ERROR_DURING_EXPORT=An error occurred while \
+ attempting to process the LDIF export:  %s
+SEVERE_ERR_CANNOT_DECODE_BACKEND_BASE_DN=Unable to decode the backend \
+ configuration base DN string "%s" as a valid DN:  %s
+SEVERE_ERR_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY=Unable to retrieve the \
+ backend configuration base entry "%s" from the server configuration:  %s
+SEVERE_ERR_CANNOT_DETERMINE_BACKEND_CLASS=Cannot determine the name of the \
+ Java class providing the logic for the backend defined in configuration entry \
+ %s:  %s
+SEVERE_ERR_CANNOT_LOAD_BACKEND_CLASS=Unable to load class %s referenced in \
+ configuration entry %s for use as a Directory Server backend:  %s
+SEVERE_ERR_CANNOT_INSTANTIATE_BACKEND_CLASS=Unable to create an instance \
+ of class %s referenced in configuration entry %s as a Directory Server \
+ backend:  %s
+SEVERE_ERR_NO_BASES_FOR_BACKEND=No base DNs have been defined in backend \
+ configuration entry %s.  This backend will not be evaluated
+SEVERE_ERR_CANNOT_DETERMINE_BASES_FOR_BACKEND=Unable to determine the set \
+ of base DNs defined in backend configuration entry %s:  %s
+INFO_LDIFIMPORT_DESCRIPTION_LDIF_FILE=Path to the LDIF file to be imported
+INFO_LDIFIMPORT_DESCRIPTION_APPEND=Append to an existing database rather \
+ than overwriting it
+INFO_LDIFIMPORT_DESCRIPTION_REPLACE_EXISTING=Replace existing entries when \
+ appending to the database
+INFO_LDIFIMPORT_DESCRIPTION_BACKEND_ID=Backend ID for the backend to \
+ import
+INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_BRANCH=Base DN of a branch to exclude \
+ from the LDIF import
+INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_ATTRIBUTE=Attribute to include in the \
+ LDIF import
+INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_ATTRIBUTE=Attribute to exclude from \
+ the LDIF import
+INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_FILTER=Filter to identify entries to \
+ include in the LDIF import
+INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_FILTER=Filter to identify entries to \
+ exclude from the LDIF import
+INFO_LDIFIMPORT_DESCRIPTION_REJECT_FILE=Write rejected entries to the \
+ specified file
+INFO_LDIFIMPORT_DESCRIPTION_OVERWRITE=Overwrite an existing rejects and/or \
+ skip file rather than appending to it
+INFO_LDIFIMPORT_DESCRIPTION_IS_COMPRESSED=LDIF file is compressed
+INFO_LDIFIMPORT_DESCRIPTION_IS_ENCRYPTED=LDIF file is encrypted
+SEVERE_ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER=Unable to decode exclude \
+ filter string "%s" as a valid search filter:  %s
+SEVERE_ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER=Unable to decode include \
+ filter string "%s" as a valid search filter:  %s
+SEVERE_ERR_LDIFIMPORT_MULTIPLE_BACKENDS_FOR_ID=Imported branches or \
+ backend IDs can not span across multiple Directory Server backends
+SEVERE_ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID=None of the Directory Server \
+ backends are configured with the requested backend ID or base DNs that \
+ include the specified branches
+SEVERE_ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE=Unable to decode exclude \
+ branch string "%s" as a valid distinguished name:  %s
+SEVERE_ERR_LDIFIMPORT_CANNOT_OPEN_REJECTS_FILE=An error occurred while \
+ trying to open the rejects file %s for writing:  %s
+SEVERE_ERR_LDIFIMPORT_ERROR_DURING_IMPORT=An error occurred while \
+ attempting to process the LDIF import:  %s
+INFO_PROCESSING_OPERATION=Processing %s request for %s
+INFO_OPERATION_FAILED=%s operation failed
+INFO_OPERATION_SUCCESSFUL=%s operation successful for DN %s
+INFO_PROCESSING_COMPARE_OPERATION=Comparing type %s with value %s in \
+ entry %s
+INFO_COMPARE_OPERATION_RESULT_FALSE=Compare operation returned false for \
+ entry %s
+INFO_COMPARE_OPERATION_RESULT_TRUE=Compare operation returned true for \
+ entry %s
+INFO_SEARCH_OPERATION_INVALID_PROTOCOL=Invalid operation type returned in \
+ search result %s
+INFO_DESCRIPTION_TRUSTALL=Trust all server SSL certificates
+INFO_DESCRIPTION_BINDDN=DN to use to bind to the server
+INFO_DESCRIPTION_BINDPASSWORD=Password to use to bind to \
+ the server
+INFO_DESCRIPTION_BINDPASSWORDFILE=Bind password file
+INFO_DESCRIPTION_ENCODING=Use the specified character set for \
+ command-line input
+INFO_DESCRIPTION_VERBOSE=Use verbose mode
+INFO_DESCRIPTION_KEYSTOREPATH=Certificate key store path
+INFO_DESCRIPTION_TRUSTSTOREPATH=Certificate trust store path
+INFO_DESCRIPTION_KEYSTOREPASSWORD=Certificate key store PIN
+INFO_DESCRIPTION_HOST=Directory server hostname or IP address
+INFO_DESCRIPTION_PORT=Directory server port number
+INFO_DESCRIPTION_SHOWUSAGE=Display this usage information
+INFO_DESCRIPTION_CONTROLS=Use a request control with the provided \
+ information
+INFO_DESCRIPTION_CONTINUE_ON_ERROR=Continue processing even if there are \
+ errors
+INFO_DESCRIPTION_USE_SSL=Use SSL for secure communication with the server
+INFO_DESCRIPTION_START_TLS=Use StartTLS to secure communication with the \
+ server
+INFO_DESCRIPTION_USE_SASL_EXTERNAL=Use the SASL EXTERNAL authentication \
+ mechanism
+INFO_DELETE_DESCRIPTION_FILENAME=File containing the DNs of the entries \
+ to delete
+INFO_DELETE_DESCRIPTION_DELETE_SUBTREE=Delete the specified entry and all \
+ entries below it
+INFO_MODIFY_DESCRIPTION_DEFAULT_ADD=Treat records with no changetype as \
+ add operations
+INFO_SEARCH_DESCRIPTION_BASEDN=Search base DN
+INFO_SEARCH_DESCRIPTION_SIZE_LIMIT=Maximum number of entries to return \
+ from the search
+INFO_SEARCH_DESCRIPTION_TIME_LIMIT=Maximum length of time in seconds to \
+ allow for the search
+INFO_SEARCH_DESCRIPTION_SEARCH_SCOPE=Search scope ('base', 'one', 'sub', \
+ or 'subordinate')
+INFO_SEARCH_DESCRIPTION_DEREFERENCE_POLICY=Alias dereference policy \
+ ('never', 'always', 'search', or 'find')
+SEVERE_ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND=Cannot send the simple bind \
+ request:  %s
+SEVERE_ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE=Cannot read the bind \
+ response from the server. The port you are using may require a secured \
+communication (--useSSL). %s
+SEVERE_ERR_LDAPAUTH_SERVER_DISCONNECT=The Directory Server indicated that \
+ it was closing the connection to the client (result code %d, message "%s"
+SEVERE_ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE=The Directory Server \
+ sent an unexpected extended response message to the client:  %s
+SEVERE_ERR_LDAPAUTH_UNEXPECTED_RESPONSE=The Directory Server sent an \
+ unexpected response message to the client:  %s
+MILD_ERR_LDAPAUTH_SIMPLE_BIND_FAILED=The simple bind attempt failed
+SEVERE_ERR_LDAPAUTH_NO_SASL_MECHANISM=A SASL bind was requested but no \
+ SASL mechanism was specified
+MILD_ERR_LDAPAUTH_UNSUPPORTED_SASL_MECHANISM=The requested SASL mechanism \
+ "%s" is not supported by this client
+MILD_ERR_LDAPAUTH_TRACE_SINGLE_VALUED=The trace SASL property may only be \
+ given a single value
+MILD_ERR_LDAPAUTH_INVALID_SASL_PROPERTY=Property "%s" is not allowed for \
+ the %s SASL mechanism
+SEVERE_ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND=Cannot send the SASL %S bind \
+ request:  %s
+MILD_ERR_LDAPAUTH_SASL_BIND_FAILED=The SASL %s bind attempt failed
+MILD_ERR_LDAPAUTH_NO_SASL_PROPERTIES=No SASL properties were provided for \
+ use with the %s mechanism
+MILD_ERR_LDAPAUTH_AUTHID_SINGLE_VALUED=The "authid" SASL property only \
+ accepts a single value
+MILD_ERR_LDAPAUTH_SASL_AUTHID_REQUIRED=The "authid" SASL property is \
+ required for use with the %s mechanism
+MILD_ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND=Cannot send the initial \
+ bind request in the multi-stage %s bind to the server:  %s
+MILD_ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE=Cannot read the \
+ initial %s bind response from the server:  %s
+MILD_ERR_LDAPAUTH_UNEXPECTED_INITIAL_BIND_RESPONSE=The client received an \
+ unexpected intermediate bind response.  The "SASL bind in progress" result \
+ was expected for the first response in the multi-stage %s bind process, but \
+ the bind response had a result code of %d (%s) and an error message of "%s"
+MILD_ERR_LDAPAUTH_NO_CRAMMD5_SERVER_CREDENTIALS=The initial bind response \
+ from the server did not include any server SASL credentials containing the \
+ challenge information needed to complete the CRAM-MD5 authentication
+MILD_ERR_LDAPAUTH_CANNOT_INITIALIZE_MD5_DIGEST=An unexpected error \
+ occurred while trying to initialize the MD5 digest generator:  %s
+MILD_ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND=Cannot send the second \
+ bind request in the multi-stage %s bind to the server:  %s
+MILD_ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE=Cannot read the second \
+ %s bind response from the server:  %s
+MILD_ERR_LDAPAUTH_NO_ALLOWED_SASL_PROPERTIES=One or more SASL properties \
+ were provided, but the %s mechanism does not take any SASL properties
+MILD_ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED=The "authzid" SASL property only \
+ accepts a single value
+MILD_ERR_LDAPAUTH_REALM_SINGLE_VALUED=The "realm" SASL property only \
+ accepts a single value
+MILD_ERR_LDAPAUTH_QOP_SINGLE_VALUED=The "qop" SASL property only accepts \
+ a single value
+MILD_ERR_LDAPAUTH_DIGESTMD5_QOP_NOT_SUPPORTED=The "%s" QoP mode is not \
+ supported by this client.  Only the "auth" mode is currently available for \
+ use
+MILD_ERR_LDAPAUTH_DIGESTMD5_INVALID_QOP=The specified DIGEST-MD5 quality \
+ of protection mode "%s" is not valid.  The only QoP mode currently supported \
+ is "auth"
+MILD_ERR_LDAPAUTH_DIGEST_URI_SINGLE_VALUED=The "digest-uri" SASL property \
+ only accepts a single value
+MILD_ERR_LDAPAUTH_NO_DIGESTMD5_SERVER_CREDENTIALS=The initial bind \
+ response from the server did not include any server SASL credentials \
+ containing the challenge information needed to complete the DIGEST-MD5 \
+ authentication
+MILD_ERR_LDAPAUTH_DIGESTMD5_INVALID_TOKEN_IN_CREDENTIALS=The DIGEST-MD5 \
+ credentials provided by the server contained an invalid token of "%s" \
+ starting at position %d
+MILD_ERR_LDAPAUTH_DIGESTMD5_INVALID_CHARSET=The DIGEST-MD5 credentials \
+ provided by the server specified the use of the "%s" character set.  The \
+ character set that may be specified in the DIGEST-MD5 credentials is "utf-8"
+MILD_ERR_LDAPAUTH_REQUESTED_QOP_NOT_SUPPORTED_BY_SERVER=The requested QoP \
+ mode of "%s" is not listed as supported by the Directory Server.  The \
+ Directory Server's list of supported QoP modes is:  "%s"
+MILD_ERR_LDAPAUTH_DIGESTMD5_NO_NONCE=The server SASL credentials provided \
+ in response to the initial DIGEST-MD5 bind request did not include the nonce \
+ to use to generate the authentication digests
+MILD_ERR_LDAPAUTH_DIGESTMD5_CANNOT_CREATE_RESPONSE_DIGEST=An error \
+ occurred while attempting to generate the response digest for the DIGEST-MD5 \
+ bind request:  %s
+MILD_ERR_LDAPAUTH_DIGESTMD5_NO_RSPAUTH_CREDS=The DIGEST-MD5 bind response \
+ from the server did not include the "rspauth" element to provide a digest of \
+ the response authentication information
+MILD_ERR_LDAPAUTH_DIGESTMD5_COULD_NOT_DECODE_RSPAUTH=An error occurred \
+ while trying to decode the rspauth element of the DIGEST-MD5 bind response \
+ from the server as a hexadecimal string:  %s
+MILD_ERR_LDAPAUTH_DIGESTMD5_COULD_NOT_CALCULATE_RSPAUTH=An error occurred \
+ while trying to calculate the expected rspauth element to compare against the \
+ value included in the DIGEST-MD5 response from the server:  %s
+MILD_ERR_LDAPAUTH_DIGESTMD5_RSPAUTH_MISMATCH=The rpsauth element included \
+ in the DIGEST-MD5 bind response from the Directory Server was different from \
+ the expected value calculated by the client
+MILD_ERR_LDAPAUTH_DIGESTMD5_INVALID_CLOSING_QUOTE_POS=The DIGEST-MD5 \
+ response challenge could not be parsed because it had an invalid quotation \
+ mark at position %d
+INFO_LDAPAUTH_PROPERTY_DESCRIPTION_TRACE=Text string that may be written \
+ to the Directory Server error log as trace information for the bind
+INFO_LDAPAUTH_PROPERTY_DESCRIPTION_AUTHID=Authentication ID for the bind
+INFO_LDAPAUTH_PROPERTY_DESCRIPTION_REALM=Realm into which \
+ the authentication is to be performed
+INFO_LDAPAUTH_PROPERTY_DESCRIPTION_QOP=Quality of \
+ protection to use for the bind
+INFO_LDAPAUTH_PROPERTY_DESCRIPTION_DIGEST_URI=Digest URI to \
+ use for the bind
+INFO_LDAPAUTH_PROPERTY_DESCRIPTION_AUTHZID=Authorization ID \
+ to use for the bind
+INFO_DESCRIPTION_SASL_PROPERTIES=SASL bind options
+INFO_LDAPAUTH_PROPERTY_DESCRIPTION_KDC=KDC to use for the \
+ Kerberos authentication
+MILD_ERR_LDAPAUTH_KDC_SINGLE_VALUED=The "kdc" SASL property only accepts \
+ a single value
+MILD_ERR_LDAPAUTH_GSSAPI_INVALID_QOP=The specified GSSAPI quality of \
+ protection mode "%s" is not valid.  The only QoP mode currently supported is \
+ "auth"
+SEVERE_ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_JAAS_CONFIG=An error occurred \
+ while trying to create the temporary JAAS configuration for GSSAPI \
+ authentication:  %s
+MILD_ERR_LDAPAUTH_GSSAPI_LOCAL_AUTHENTICATION_FAILED=An error occurred \
+ while attempting to perform local authentication to the Kerberos realm:  %s
+MILD_ERR_LDAPAUTH_GSSAPI_REMOTE_AUTHENTICATION_FAILED=An error occurred \
+ while attempting to perform GSSAPI authentication to the Directory Server: \
+ %s
+SEVERE_ERR_LDAPAUTH_NONSASL_RUN_INVOCATION=The \
+ LDAPAuthenticationHandler.run() method was called for a non-SASL bind.  The \
+ backtrace for this call is %s
+SEVERE_ERR_LDAPAUTH_UNEXPECTED_RUN_INVOCATION=The \
+ LDAPAuthenticationHandler.run() method was called for a SASL bind with an \
+ unexpected mechanism of "%s".  The backtrace for this call is %s
+SEVERE_ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_SASL_CLIENT=An error occurred \
+ while attempting to create a SASL client to process the GSSAPI \
+ authentication:  %s
+SEVERE_ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_INITIAL_CHALLENGE=An error \
+ occurred while attempting to create the initial challenge for GSSAPI \
+ authentication:  %s
+MILD_ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS=An error occurred \
+ while trying to validate the SASL credentials provided by the Directory \
+ Server in the GSSAPI bind response:  %s
+MILD_ERR_LDAPAUTH_GSSAPI_UNEXPECTED_SUCCESS_RESPONSE=The Directory Server \
+ unexpectedly returned a success response to the client even though the client \
+ does not believe that the GSSAPI negotiation is complete
+MILD_ERR_LDAPAUTH_GSSAPI_BIND_FAILED=The GSSAPI bind attempt failed
+SEVERE_ERR_LDAPAUTH_NONSASL_CALLBACK_INVOCATION=The \
+ LDAPAuthenticationHandler.handle() method was called for a non-SASL bind. \
+ The backtrace for this call is %s
+SEVERE_ERR_LDAPAUTH_UNEXPECTED_GSSAPI_CALLBACK=The \
+ LDAPAuthenticationHandler.handle() method was called during a GSSAPI bind \
+ attempt with an unexpected callback type of %s
+SEVERE_ERR_LDAPAUTH_UNEXPECTED_CALLBACK_INVOCATION=The \
+ LDAPAuthenticationHandler.handle() method was called for an unexpected SASL \
+ mechanism of %s.  The backtrace for this call is %s
+INFO_LDAPAUTH_PASSWORD_PROMPT=Password for user '%s':
+INFO_DESCRIPTION_VERSION=LDAP protocol version number
+MILD_ERR_DESCRIPTION_INVALID_VERSION=Invalid LDAP version number '%s'. \
+ Allowed values are 2 and 3
+SEVERE_ERR_LDAPAUTH_CANNOT_SEND_WHOAMI_REQUEST=Cannot send the 'Who Am \
+ I?' request to the Directory Server:  %s
+SEVERE_ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE=Cannot read the 'Who Am \
+ I?' response from the Directory Server:  %s
+MILD_ERR_LDAPAUTH_WHOAMI_FAILED=The 'Who Am I?' request was rejected by \
+ the Directory Server
+SEVERE_ERR_SEARCH_INVALID_SEARCH_SCOPE=Invalid scope '%s' specified for \
+ the search request
+SEVERE_ERR_SEARCH_NO_FILTERS=No filters specified for the search request
+INFO_VERIFYINDEX_DESCRIPTION_BASE_DN=Base DN of a backend \
+ supporting indexing. Verification is performed on indexes within the scope of \
+ the given base DN
+INFO_VERIFYINDEX_DESCRIPTION_INDEX_NAME=Name of an index to \
+ be verified. For an attribute index this is simply an attribute name. \
+ Multiple indexes may be verified for completeness, or all indexes if no \
+ indexes are specified.  An index is complete if each index value references \
+ all entries containing that value
+INFO_VERIFYINDEX_DESCRIPTION_VERIFY_CLEAN=Specifies that a single index \
+ should be verified to ensure it is clean.  An index is clean if each index \
+ value references only entries containing that value.  Only one index at a \
+ time may be verified in this way
+SEVERE_ERR_VERIFYINDEX_ERROR_DURING_VERIFY=An error occurred while \
+ attempting to perform index verification:  %s
+SEVERE_ERR_VERIFYINDEX_VERIFY_CLEAN_REQUIRES_SINGLE_INDEX=Only one index \
+ at a time may be verified for cleanliness
+SEVERE_ERR_BACKEND_NO_INDEXING_SUPPORT=The backend does not support \
+ indexing
+SEVERE_ERR_LDIFEXPORT_CANNOT_EXPORT_BACKEND=The Directory Server backend \
+ with backend ID "%s" does not provide a mechanism for performing LDIF exports
+SEVERE_ERR_LDIFIMPORT_CANNOT_IMPORT=The Directory Server backend with \
+ backend ID %s does not provide a mechanism for performing LDIF imports
+INFO_DESCRIPTION_DONT_WRAP=Do not wrap long lines
+INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_BRANCH=Base DN of a branch to include \
+ in the LDIF import
+SEVERE_ERR_CANNOT_DETERMINE_BACKEND_ID=Cannot determine the backend ID \
+ for the backend defined in configuration entry %s:  %s
+SEVERE_ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE=Unable to decode include \
+ branch string "%s" as a valid distinguished name:  %s
+SEVERE_ERR_LDIFIMPORT_INVALID_INCLUDE_BASE=Provided include base DN "%s" \
+ is not handled by the backend with backend ID %s
+SEVERE_ERR_MULTIPLE_BACKENDS_FOR_BASE=Multiple Directory Server backends \
+ are configured to support base DN "%s"
+SEVERE_ERR_NO_BACKENDS_FOR_BASE=None of the Directory Server backends are \
+ configured to support the requested base DN "%s"
+INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_BRANCH=Base DN of a branch to include \
+ in the LDIF export
+SEVERE_ERR_LDIFEXPORT_CANNOT_DECODE_INCLUDE_BASE=Unable to decode include \
+ branch string "%s" as a valid distinguished name:  %s
+SEVERE_ERR_LDIFEXPORT_INVALID_INCLUDE_BASE=Provided include base DN "%s" \
+ is not handled by the backend with backend ID %s
+INFO_BACKUPDB_DESCRIPTION_BACKEND_ID=Backend ID for the backend to \
+ archive
+INFO_BACKUPDB_DESCRIPTION_BACKUP_ID=Use the provided identifier for the \
+ backup
+INFO_BACKUPDB_DESCRIPTION_BACKUP_DIR=Path to the target directory for the \
+ backup file(s)
+INFO_BACKUPDB_DESCRIPTION_INCREMENTAL=Perform an incremental backup \
+ rather than a full backup
+INFO_BACKUPDB_DESCRIPTION_COMPRESS=Compress the backup contents
+INFO_BACKUPDB_DESCRIPTION_ENCRYPT=Encrypt the backup contents
+INFO_BACKUPDB_DESCRIPTION_HASH=Generate a hash of the backup contents
+INFO_BACKUPDB_DESCRIPTION_SIGN_HASH=Sign the hash of the backup contents
+SEVERE_ERR_BACKUPDB_MULTIPLE_BACKENDS_FOR_ID=Multiple Directory Server \
+ backends are configured with the requested backend ID "%s"
+SEVERE_ERR_BACKUPDB_NO_BACKENDS_FOR_ID=None of the Directory Server \
+ backends are configured with the requested backend ID "%s"
+SEVERE_ERR_BACKUPDB_CONFIG_ENTRY_MISMATCH=The configuration for the \
+ backend with backend ID %s is held in entry "%s", but other backups in the \
+ target backup directory %s were generated from a backend whose configuration \
+ was held in configuration entry "%s"
+SEVERE_ERR_BACKUPDB_INVALID_BACKUP_DIR=An error occurred while attempting \
+ to use the specified path "%s" as the target directory for the backup:  %s
+SEVERE_ERR_BACKUPDB_CANNOT_BACKUP=The target backend %s cannot be backed \
+ up using the requested configuration:  %s
+SEVERE_ERR_BACKUPDB_ERROR_DURING_BACKUP=An error occurred while \
+ attempting to back up backend %s with the requested configuration:  %s
+INFO_BACKUPDB_DESCRIPTION_BACKUP_ALL=Back up all backends in the server
+SEVERE_ERR_BACKUPDB_CANNOT_MIX_BACKUP_ALL_AND_BACKEND_ID=The %s and %s \
+ arguments may not be used together.  Exactly one of them must be provided
+SEVERE_ERR_BACKUPDB_NEED_BACKUP_ALL_OR_BACKEND_ID=Neither the %s argument \
+ nor the %s argument was provided.  Exactly one of them is required
+SEVERE_ERR_BACKUPDB_CANNOT_CREATE_BACKUP_DIR=An error occurred while \
+ attempting to create the backup directory %s:  %s
+SEVERE_WARN_BACKUPDB_BACKUP_NOT_SUPPORTED=Backend ID %s was included in \
+ the set of backends to archive, but this backend does not provide support for \
+ a backup mechanism.  It will be skipped
+SEVERE_WARN_BACKUPDB_NO_BACKENDS_TO_ARCHIVE=None of the target backends \
+ provide a backup mechanism.  The backup operation has been aborted
+NOTICE_BACKUPDB_STARTING_BACKUP=Starting backup for backend %s
+SEVERE_ERR_BACKUPDB_CANNOT_PARSE_BACKUP_DESCRIPTOR=An error occurred \
+ while attempting to parse the backup descriptor file %s:  %s
+NOTICE_BACKUPDB_COMPLETED_WITH_ERRORS=The backup process completed with \
+ one or more errors
+NOTICE_BACKUPDB_COMPLETED_SUCCESSFULLY=The backup process completed \
+ successfully
+SEVERE_ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER=An error occurred while \
+ attempting to initialize the crypto manager:  %s
+INFO_BACKUPDB_DESCRIPTION_INCREMENTAL_BASE_ID=Backup ID of the source \
+ archive for an incremental backup
+SEVERE_ERR_BACKUPDB_INCREMENTAL_BASE_REQUIRES_INCREMENTAL=The use of the \
+ %s argument requires that the %s argument is also provided
+INFO_RESTOREDB_DESCRIPTION_BACKEND_ID=Backend ID for the backend to \
+ restore
+INFO_RESTOREDB_DESCRIPTION_BACKUP_ID=Backup ID of the backup to restore
+INFO_RESTOREDB_DESCRIPTION_BACKUP_DIR=Path to the directory containing \
+ the backup file(s)
+INFO_RESTOREDB_DESCRIPTION_LIST_BACKUPS=List available backups in the \
+ backup directory
+INFO_RESTOREDB_DESCRIPTION_VERIFY_ONLY=Verify the contents of the backup \
+ but do not restore it
+SEVERE_ERR_RESTOREDB_CANNOT_READ_BACKUP_DIRECTORY=An error occurred while \
+ attempting to examine the set of backups contained in backup directory %s: \
+ %s
+INFO_RESTOREDB_LIST_BACKUP_ID=Backup ID:          %s
+INFO_RESTOREDB_LIST_BACKUP_DATE=Backup Date:        %s
+INFO_RESTOREDB_LIST_INCREMENTAL=Is Incremental:     %s
+INFO_RESTOREDB_LIST_COMPRESSED=Is Compressed:      %s
+INFO_RESTOREDB_LIST_ENCRYPTED=Is Encrypted:       %s
+INFO_RESTOREDB_LIST_HASHED=Has Unsigned Hash:  %s
+INFO_RESTOREDB_LIST_SIGNED=Has Signed Hash:    %s
+INFO_RESTOREDB_LIST_DEPENDENCIES=Dependent Upon:     %s
+SEVERE_ERR_RESTOREDB_INVALID_BACKUP_ID=The requested backup ID %s does \
+ not exist in %s
+SEVERE_ERR_RESTOREDB_NO_BACKUPS_IN_DIRECTORY=There are no Directory \
+ Server backups contained in %s
+SEVERE_ERR_RESTOREDB_NO_BACKENDS_FOR_DN=The backups contained in \
+ directory %s were taken from a Directory Server backend defined in \
+ configuration entry %s but no such backend is available
+SEVERE_ERR_RESTOREDB_CANNOT_RESTORE=The Directory Server backend \
+ configured with backend ID %s does not provide a mechanism for restoring \
+ backups
+SEVERE_ERR_RESTOREDB_ERROR_DURING_BACKUP=An unexpected error occurred \
+ while attempting to restore backup %s from %s:  %s
+SEVERE_ERR_RESTOREDB_ENCRYPT_OR_SIGN_REQUIRES_ONLINE=Restoring an \
+ encrypted or signed backup requires a connection to an online server
+SEVERE_ERR_BACKUPDB_ENCRYPT_OR_SIGN_REQUIRES_ONLINE=The use of the \
+ %s argument or the %s argument requires a connection to an online server \
+ instance
+SEVERE_ERR_BACKUPDB_SIGN_REQUIRES_HASH=The use of the %s argument \
+ requires that the %s argument is also provided
+INFO_DESCRIPTION_NOOP=Show what would be done but do not perform any \
+ operation
+SEVERE_ERR_BACKUPDB_CANNOT_LOCK_BACKEND=An error occurred while \
+ attempting to acquire a shared lock for backend %s:  %s.  This generally \
+ means that some other process has exclusive access to this backend (e.g., a \
+ restore or an LDIF import).  This backend will not be archived
+SEVERE_WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND=An error occurred while \
+ attempting to release the shared lock for backend %s:  %s.  This lock should \
+ automatically be cleared when the backup process exits, so no further action \
+ should be required
+SEVERE_ERR_RESTOREDB_CANNOT_LOCK_BACKEND=An error occurred while \
+ attempting to acquire an exclusive lock for backend %s:  %s.  This generally \
+ means some other process is still using this backend (e.g., it is in use by \
+ the Directory Server or a backup or LDIF export is in progress).  The restore \
+ cannot continue
+SEVERE_WARN_RESTOREDB_CANNOT_UNLOCK_BACKEND=An error occurred while \
+ attempting to release the exclusive lock for backend %s:  %s.  This lock \
+ should automatically be cleared when the restore process exits, so no further \
+ action should be required
+SEVERE_ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND=An error occurred while \
+ attempting to acquire an exclusive lock for backend %s:  %s.  This generally \
+ means some other process is still using this backend (e.g., it is in use by \
+ the Directory Server or a backup or LDIF export is in progress).  The LDIF \
+ import cannot continue
+SEVERE_WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND=An error occurred while \
+ attempting to release the exclusive lock for backend %s:  %s.  This lock \
+ should automatically be cleared when the import process exits, so no further \
+ action should be required
+SEVERE_ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND=An error occurred while \
+ attempting to acquire a shared lock for backend %s:  %s.  This generally \
+ means that some other process has an exclusive lock on this backend (e.g., an \
+ LDIF import or a restore).  The LDIF export cannot continue
+SEVERE_WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND=An error occurred while \
+ attempting to release the shared lock for backend %s:  %s.  This lock should \
+ automatically be cleared when the export process exits, so no further action \
+ should be required
+SEVERE_ERR_VERIFYINDEX_CANNOT_LOCK_BACKEND=An error occurred while \
+ attempting to acquire a shared lock for backend %s:  %s.  This generally \
+ means that some other process has an exclusive lock on this backend (e.g., an \
+ LDIF import or a restore).  The index verification cannot continue
+SEVERE_WARN_VERIFYINDEX_CANNOT_UNLOCK_BACKEND=An error occurred while \
+ attempting to release the shared lock for backend %s:  %s.  This lock should \
+ automatically be cleared when the verification process exits, so no further \
+ action should be required
+INFO_DESCRIPTION_TYPES_ONLY=Only retrieve attribute names but not their \
+ values
+INFO_LDIFIMPORT_DESCRIPTION_SKIP_SCHEMA_VALIDATION=Skip schema validation \
+ during the LDIF import
+SEVERE_ERR_LDIFEXPORT_CANNOT_INITIALIZE_PLUGINS=An error occurred while \
+ attempting to initialize the LDIF export plugins:  %s
+SEVERE_ERR_LDIFIMPORT_CANNOT_INITIALIZE_PLUGINS=An error occurred while \
+ attempting to initialize the LDIF import plugins:  %s
+INFO_DESCRIPTION_ASSERTION_FILTER=Use the LDAP assertion control with the \
+ provided filter
+MILD_ERR_LDAP_ASSERTION_INVALID_FILTER=The search filter provided for the \
+ LDAP assertion control was invalid:  %s
+INFO_DESCRIPTION_PREREAD_ATTRS=Use the LDAP ReadEntry pre-read control
+INFO_DESCRIPTION_POSTREAD_ATTRS=Use the LDAP ReadEntry post-read control
+MILD_ERR_LDAPMODIFY_PREREAD_NO_VALUE=The pre-read response control did \
+ not include a value
+MILD_ERR_LDAPMODIFY_PREREAD_CANNOT_DECODE_VALUE=An error occurred while \
+ trying to decode the entry contained in the value of the pre-read response \
+ control:  %s
+INFO_LDAPMODIFY_PREREAD_ENTRY=Target entry before the operation:
+MILD_ERR_LDAPMODIFY_POSTREAD_NO_VALUE=The post-read response control did \
+ not include a value
+MILD_ERR_LDAPMODIFY_POSTREAD_CANNOT_DECODE_VALUE=An error occurred while \
+ trying to decode the entry contained in the value of the post-read response \
+ control:  %s
+INFO_LDAPMODIFY_POSTREAD_ENTRY=Target entry after the operation:
+INFO_DESCRIPTION_PROXY_AUTHZID=Use the proxied authorization control with \
+ the given authorization ID
+INFO_DESCRIPTION_PSEARCH_INFO=Use the persistent search control
+MILD_ERR_PSEARCH_MISSING_DESCRIPTOR=The request to use the persistent \
+ search control did not include a descriptor that indicates the options to use \
+ with that control
+MILD_ERR_PSEARCH_DOESNT_START_WITH_PS=The persistent search descriptor %s \
+ did not start with the required 'ps' string
+MILD_ERR_PSEARCH_INVALID_CHANGE_TYPE=The provided change type value %s is \
+ invalid.  The recognized change types are add, delete, modify, modifydn, and \
+ any
+MILD_ERR_PSEARCH_INVALID_CHANGESONLY=The provided changesOnly value %s is \
+ invalid.  Allowed values are 1 to only return matching entries that have \
+ changed since the beginning of the search, or 0 to also include existing \
+ entries that match the search criteria
+MILD_ERR_PSEARCH_INVALID_RETURN_ECS=The provided returnECs value %s is \
+ invalid.  Allowed values are 1 to request that the entry change notification \
+ control be included in updated entries, or 0 to exclude the control from \
+ matching entries
+INFO_DESCRIPTION_REPORT_AUTHZID=Use the authorization identity control
+INFO_BIND_AUTHZID_RETURNED=# Bound with authorization ID %s
+INFO_SEARCH_DESCRIPTION_FILENAME=File containing a list of search filter \
+ strings
+INFO_DESCRIPTION_MATCHED_VALUES_FILTER=Use the LDAP matched values \
+ control with the provided filter
+MILD_ERR_LDAP_MATCHEDVALUES_INVALID_FILTER=The provided matched values \
+ filter was invalid:  %s
+FATAL_ERR_LDIF_FILE_CANNOT_OPEN_FOR_READ=An error occurred while \
+ attempting to open the LDIF file %s for reading:  %s
+FATAL_ERR_LDIF_FILE_READ_ERROR=An error occurred while attempting to read \
+ the contents of LDIF file %s:  %s
+SEVERE_ERR_LDIF_FILE_INVALID_LDIF_ENTRY=Error at or near line %d in LDIF \
+ file %s:  %s
+INFO_ENCPW_DESCRIPTION_AUTHPW=Use the authentication password syntax \
+ rather than the user password syntax
+SEVERE_ERR_ENCPW_NO_AUTH_STORAGE_SCHEMES=No authentication password \
+ storage schemes have been configured for use in the Directory Server
+SEVERE_ERR_ENCPW_NO_SUCH_AUTH_SCHEME=Authentication password storage \
+ scheme "%s" is not configured for use in the Directory Server
+SEVERE_ERR_ENCPW_INVALID_ENCODED_AUTHPW=The provided password is not a \
+ valid encoded authentication password value:  %s
+SEVERE_ERR_LDIFIMPORT_CANNOT_INITIALIZE_PWPOLICY=An error occurred while \
+ attempting to initialize the password policy components:  %s
+INFO_STOPDS_DESCRIPTION_HOST=Directory server hostname or IP address
+INFO_STOPDS_DESCRIPTION_PORT=Directory server administration port number
+INFO_STOPDS_DESCRIPTION_USESSL=Use SSL for secure communication with the \
+ server
+INFO_STOPDS_DESCRIPTION_USESTARTTLS=Use StartTLS for secure communication \
+ with the server
+INFO_STOPDS_DESCRIPTION_BINDDN=DN to use to bind to the server
+INFO_STOPDS_DESCRIPTION_BINDPW=Password to use to bind to the server
+INFO_STOPDS_DESCRIPTION_BINDPWFILE=Bind password file
+INFO_STOPDS_DESCRIPTION_SASLOPTIONS=SASL bind options
+INFO_STOPDS_DESCRIPTION_PROXYAUTHZID=Use the proxied authorization \
+ control with the given authorization ID
+INFO_STOPDS_DESCRIPTION_STOP_REASON=Reason the server is being stopped or \
+ restarted
+INFO_STOPDS_DESCRIPTION_STOP_TIME=Indicates the date/time at which the \
+ shutdown operation will begin as a server task expressed in format \
+ 'YYYYMMDDhhmmss'.  A value of '0' will cause the shutdown to be scheduled for \
+ immediate execution.  When this option is specified the operation will be \
+ scheduled to start at the specified time after which this utility will exit \
+ immediately
+INFO_STOPDS_DESCRIPTION_TRUST_ALL=Trust all server SSL certificates
+INFO_STOPDS_DESCRIPTION_KSFILE=Certificate key store path
+INFO_STOPDS_DESCRIPTION_KSPW=Certificate key store PIN
+INFO_STOPDS_DESCRIPTION_KSPWFILE=Certificate key store PIN file
+INFO_STOPDS_DESCRIPTION_TSFILE=Certificate trust store path
+INFO_STOPDS_DESCRIPTION_TSPW=Certificate trust store PIN
+INFO_STOPDS_DESCRIPTION_TSPWFILE=Certificate trust store PIN file
+INFO_STOPDS_DESCRIPTION_SHOWUSAGE=Display this usage information
+SEVERE_ERR_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS=ERROR:  You may not \
+ provide both the %s and the %s arguments
+SEVERE_ERR_STOPDS_CANNOT_DECODE_STOP_TIME=ERROR:  Unable to decode the \
+ provided stop time.  It should be in the form YYYYMMDDhhmmssZ for UTC time or \
+ YYYYMMDDhhmmss for local time
+SEVERE_ERR_STOPDS_CANNOT_INITIALIZE_SSL=ERROR:  Unable to perform SSL \
+ initialization:  %s
+SEVERE_ERR_STOPDS_CANNOT_PARSE_SASL_OPTION=ERROR:  The provided SASL \
+ option string "%s" could not be parsed in the form "name=value"
+SEVERE_ERR_STOPDS_NO_SASL_MECHANISM=ERROR:  One or more SASL options were \
+ provided, but none of them were the "mech" option to specify which SASL \
+ mechanism should be used
+SEVERE_ERR_STOPDS_CANNOT_DETERMINE_PORT=ERROR:  Cannot parse the value of \
+ the %s argument as an integer value between 1 and 65535:  %s
+SEVERE_ERR_STOPDS_CANNOT_CONNECT=ERROR:  Cannot establish a connection to \
+ the Directory Server %s.  Verify that the server is running and that \
+ the provided credentials are valid.  Details:  %s
+SEVERE_ERR_STOPDS_UNEXPECTED_CONNECTION_CLOSURE=NOTICE:  The connection \
+ to the Directory Server was closed while waiting for a response to the \
+ shutdown request.  This likely means that the server has started the shutdown \
+ process
+SEVERE_ERR_STOPDS_IO_ERROR=ERROR:  An I/O error occurred while attempting \
+ to communicate with the Directory Server:  %s
+SEVERE_ERR_STOPDS_DECODE_ERROR=ERROR:  An error occurred while trying to \
+ decode the response from the server:  %s
+SEVERE_ERR_STOPDS_INVALID_RESPONSE_TYPE=ERROR:  Expected an add response \
+ message but got a %s message instead
+INFO_BIND_PASSWORD_EXPIRED=# Your password has expired
+INFO_BIND_PASSWORD_EXPIRING=# Your password will expire in %s
+INFO_BIND_ACCOUNT_LOCKED=# Your account has been locked
+INFO_BIND_MUST_CHANGE_PASSWORD=# You must change your password before any \
+ other operations will be allowed
+INFO_BIND_GRACE_LOGINS_REMAINING=# You have %d grace logins remaining
+INFO_DESCRIPTION_USE_PWP_CONTROL=Use the password policy request control
+INFO_STOPDS_DESCRIPTION_RESTART=Attempt to automatically restart the \
+ server once it has stopped
+INFO_COMPARE_DESCRIPTION_FILENAME=File containing the DNs of the entries \
+ to compare
+INFO_LDIFSEARCH_DESCRIPTION_LDIF_FILE=LDIF file containing \
+ the data to search.  Multiple files may be specified by providing the option \
+ multiple times.  If no files are provided, the data will be read from \
+ standard input
+INFO_LDIFSEARCH_DESCRIPTION_BASEDN=The base DN for the search.  Multiple \
+ base DNs may be specified by providing the option multiple times.  If no base \
+ DN is provided, then the root DSE will be used
+INFO_LDIFSEARCH_DESCRIPTION_SCOPE=The scope for the search.  It must be \
+ one of 'base', 'one', 'sub', or 'subordinate'.  If it is not provided, then \
+ 'sub' will be used
+INFO_LDIFSEARCH_DESCRIPTION_FILTER_FILE=The path to the file containing \
+ the search filter(s) to use.  If this is not provided, then the filter must \
+ be provided on the command line after all configuration options
+INFO_LDIFSEARCH_DESCRIPTION_OUTPUT_FILE=The path to the output file to \
+ which the matching entries should be written.  If this is not provided, then \
+ the data will be written to standard output
+INFO_LDIFSEARCH_DESCRIPTION_OVERWRITE_EXISTING=Any existing output \
+ file should be overwritten rather than appending to it
+INFO_LDIFSEARCH_DESCRIPTION_DONT_WRAP=Long lines should \
+ not be wrapped
+INFO_LDIFSEARCH_DESCRIPTION_SIZE_LIMIT=Maximum number of \
+ matching entries to return
+INFO_LDIFSEARCH_DESCRIPTION_TIME_LIMIT=Maximum length of \
+ time (in seconds) to spend processing
+SEVERE_ERR_LDIFSEARCH_NO_FILTER=No search filter was specified.  Either a \
+ filter file or an individual search filter must be provided
+SEVERE_ERR_LDIFSEARCH_CANNOT_INITIALIZE_CONFIG=An error occurred while \
+ attempting to process the Directory Server configuration file %s:  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_INITIALIZE_SCHEMA=An error occurred while \
+ attempting to initialize the Directory Server schema based on the information \
+ in configuration file %s:  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_PARSE_FILTER=An error occurred while \
+ attempting to parse search filter '%s':  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_PARSE_BASE_DN=An error occurred while \
+ attempting to parse base DN '%s':  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_PARSE_TIME_LIMIT=An error occurred while \
+ attempting to parse the time limit as an integer:  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_PARSE_SIZE_LIMIT=An error occurred while \
+ attempting to parse the size limit as an integer:  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_CREATE_READER=An error occurred while \
+ attempting to create the LDIF reader:  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_CREATE_WRITER=An error occurred while \
+ attempting to create the LDIF writer used to return matching entries:  %s
+MILD_WARN_LDIFSEARCH_TIME_LIMIT_EXCEEDED=The specified time limit has \
+ been exceeded during search processing
+MILD_WARN_LDIFSEARCH_SIZE_LIMIT_EXCEEDED=The specified size limit has \
+ been exceeded during search processing
+SEVERE_ERR_LDIFSEARCH_CANNOT_READ_ENTRY_RECOVERABLE=An error occurred \
+ while attempting to read an entry from the LDIF content:  %s.  Skipping this \
+ entry and continuing processing
+SEVERE_ERR_LDIFSEARCH_CANNOT_READ_ENTRY_FATAL=An error occurred while \
+ attempting to read an entry from the LDIF content:  %s.  Unable to continue \
+ processing
+SEVERE_ERR_LDIFSEARCH_ERROR_DURING_PROCESSING=An unexpected error \
+ occurred during search processing:  %s
+SEVERE_ERR_LDIFSEARCH_CANNOT_INITIALIZE_JMX=An error occurred while \
+ attempting to initialize the Directory Server JMX subsystem based on the \
+ information in configuration file %s:  %s
+INFO_LDIFDIFF_DESCRIPTION_SOURCE_LDIF=LDIF file to use as \
+ the source data
+INFO_LDIFDIFF_DESCRIPTION_TARGET_LDIF=LDIF file to use as \
+ the target data
+INFO_LDIFDIFF_DESCRIPTION_OUTPUT_LDIF=File to which the \
+ output should be written
+INFO_LDIFDIFF_DESCRIPTION_OVERWRITE_EXISTING=Any existing \
+ output file should be overwritten rather than appending to it
+SEVERE_ERR_LDIFDIFF_CANNOT_INITIALIZE_JMX=An error occurred while \
+ attempting to initialize the Directory Server JMX subsystem based on the \
+ information in configuration file %s:  %s
+SEVERE_ERR_LDIFDIFF_CANNOT_INITIALIZE_CONFIG=An error occurred while \
+ attempting to process the Directory Server configuration file %s:  %s
+SEVERE_ERR_LDIFDIFF_CANNOT_INITIALIZE_SCHEMA=An error occurred while \
+ attempting to initialize the Directory Server schema based on the information \
+ in configuration file %s:  %s
+SEVERE_ERR_LDIFDIFF_CANNOT_OPEN_SOURCE_LDIF=An error occurred while \
+ attempting to open source LDIF %s:  %s
+SEVERE_ERR_LDIFDIFF_ERROR_READING_SOURCE_LDIF=An error occurred while \
+ reading the contents of source LDIF %s:  %s
+SEVERE_ERR_LDIFDIFF_CANNOT_OPEN_TARGET_LDIF=An error occurred while \
+ attempting to open target LDIF %s:  %s
+SEVERE_ERR_LDIFDIFF_ERROR_READING_TARGET_LDIF=An error occurred while \
+ reading the contents of target LDIF %s:  %s
+SEVERE_ERR_LDIFDIFF_CANNOT_OPEN_OUTPUT=An error occurred while attempting \
+ to open the LDIF writer for the diff output:  %s
+INFO_LDIFDIFF_NO_DIFFERENCES=No differences were detected between the \
+ source and target LDIF files
+SEVERE_ERR_LDIFDIFF_ERROR_WRITING_OUTPUT=An error occurred while \
+ attempting to write the diff output:  %s
+INFO_CONFIGDS_DESCRIPTION_LDAP_PORT=Port on which the \
+ Directory Server should listen for LDAP communication
+INFO_CONFIGDS_DESCRIPTION_BASE_DN=Base DN for user \
+ information in the Directory Server.  Multiple base DNs may be provided by \
+ using this option multiple times
+INFO_CONFIGDS_DESCRIPTION_ROOT_DN=DN for the initial root \
+ user for the Directory Server
+INFO_CONFIGDS_DESCRIPTION_ROOT_PW=Password for the initial \
+ root user for the Directory Server
+INFO_CONFIGDS_DESCRIPTION_ROOT_PW_FILE=Path to a file \
+ containing the password for the initial root user for the Directory Server
+SEVERE_ERR_CONFIGDS_CANNOT_ACQUIRE_SERVER_LOCK=An error occurred while \
+ attempting to acquire the server-wide lock file %s:  %s.  This generally \
+ means that the Directory Server is running, or another tool that requires \
+ exclusive access to the server is in use
+SEVERE_ERR_CONFIGDS_CANNOT_INITIALIZE_JMX=An error occurred while \
+ attempting to initialize the Directory Server JMX subsystem based on the \
+ information in configuration file %s:  %s
+SEVERE_ERR_CONFIGDS_CANNOT_INITIALIZE_CONFIG=An error occurred while \
+ attempting to process the Directory Server configuration file %s:  %s
+SEVERE_ERR_CONFIGDS_CANNOT_INITIALIZE_SCHEMA=An error occurred while \
+ attempting to initialize the Directory Server schema based on the information \
+ in configuration file %s:  %s
+SEVERE_ERR_CONFIGDS_CANNOT_PARSE_BASE_DN=An error occurred while \
+ attempting to parse base DN value "%s" as a DN:  %s
+SEVERE_ERR_CONFIGDS_CANNOT_PARSE_ROOT_DN=An error occurred while \
+ attempting to parse root DN value "%s" as a DN:  %s
+SEVERE_ERR_CONFIGDS_NO_ROOT_PW=The DN for the initial root user was \
+ provided, but no corresponding password was given.  If the root DN is \
+ specified then the password must also be provided
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_BASE_DN=An error occurred while \
+ attempting to update the base DN(s) for user data in the Directory Server: \
+ %s
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_LDAP_PORT=An error occurred while \
+ attempting to update the port on which to listen for LDAP communication:  %s
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_ROOT_USER=An error occurred while \
+ attempting to update the entry for the initial Directory Server root user: \
+ %s
+SEVERE_ERR_CONFIGDS_CANNOT_WRITE_UPDATED_CONFIG=An error occurred while \
+ writing the updated Directory Server configuration:  %s
+SEVERE_ERR_CONFIGDS_NO_CONFIG_CHANGES=ERROR:  No configuration changes \
+ were specified
+INFO_CONFIGDS_WROTE_UPDATED_CONFIG=Successfully wrote the updated \
+ Directory Server configuration
+INFO_INSTALLDS_DESCRIPTION_TESTONLY=Just verify that the JVM can be \
+ started properly
+INFO_INSTALLDS_DESCRIPTION_PROGNAME=The setup command used to invoke this \
+ program
+INFO_INSTALLDS_DESCRIPTION_SILENT=Run setup in quiet mode.  Quiet mode \
+ will not output progress information to standard output
+INFO_INSTALLDS_DESCRIPTION_BASEDN=Base DN for user \
+ information in the Directory Server.  Multiple base DNs may be provided by \
+ using this option multiple times
+INFO_INSTALLDS_DESCRIPTION_ADDBASE=Indicates whether to create the base \
+ entry in the Directory Server database
+INFO_INSTALLDS_DESCRIPTION_IMPORTLDIF=Path to an LDIF file \
+ containing data that should be added to the Directory Server database. \
+ Multiple LDIF files may be provided by using this option multiple times
+INFO_INSTALLDS_DESCRIPTION_LDAPPORT=Port on which the \
+ Directory Server should listen for LDAP communication
+INFO_INSTALLDS_DESCRIPTION_SKIPPORT=Skip the check to determine whether \
+ the specified ports are usable
+INFO_INSTALLDS_DESCRIPTION_ROOTDN=DN for the initial root \
+ user for the Directory Server
+INFO_INSTALLDS_DESCRIPTION_ROOTPW=Password for the initial \
+ root user for the Directory Server
+INFO_INSTALLDS_DESCRIPTION_ROOTPWFILE=Path to a file \
+ containing the password for the initial root user for the Directory Server
+INFO_INSTALLDS_DESCRIPTION_HELP=Display this usage information
+SEVERE_ERR_INSTALLDS_NO_CONFIG_FILE=ERROR:  No configuration file path \
+ was provided (use the %s argument)
+SEVERE_ERR_INSTALLDS_CANNOT_INITIALIZE_JMX=An error occurred while \
+ attempting to initialize the Directory Server JMX subsystem based on the \
+ information in configuration file %s:  %s
+SEVERE_ERR_INSTALLDS_CANNOT_INITIALIZE_CONFIG=An error occurred while \
+ attempting to process the Directory Server configuration file %s:  %s
+SEVERE_ERR_INSTALLDS_CANNOT_INITIALIZE_SCHEMA=An error occurred while \
+ attempting to initialize the Directory Server schema based on the information \
+ in configuration file %s:  %s
+SEVERE_ERR_INSTALLDS_CANNOT_PARSE_DN=An error occurred while attempting \
+ to parse the string "%s" as a valid DN:  %s
+INFO_INSTALLDS_PROMPT_BASEDN=What do you wish to use as the base DN for \
+ the directory data?
+INFO_INSTALLDS_PROMPT_IMPORT=Do you wish to populate the directory \
+ database with information from an existing LDIF file?
+INFO_INSTALLDS_PROMPT_IMPORT_FILE=Please specify the path to the LDIF \
+ file containing the data to import:
+SEVERE_ERR_INSTALLDS_TWO_CONFLICTING_ARGUMENTS=ERROR:  You may not \
+ provide both the %s and the %s arguments at the same time
+INFO_INSTALLDS_PROMPT_ADDBASE=Would you like to have the base %s entry \
+ automatically created in the directory database?
+INFO_INSTALLDS_PROMPT_LDAPPORT=On which port would you like the Directory \
+ Server to accept connections from LDAP clients?
+SEVERE_ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT=ERROR:  Unable to \
+ bind to port %d.  This port may already be in use, or you may not have \
+ permission to bind to it.  On UNIX-based operating systems, non-root users \
+ may not be allowed to bind to ports 1 through 1024
+SEVERE_ERR_INSTALLDS_CANNOT_BIND_TO_PORT=ERROR:  Unable to bind to port \
+ %d.  This port may already be in use, or you may not have permission to bind \
+ to it
+INFO_INSTALLDS_PROMPT_ROOT_DN=What would you like to use as the initial \
+ root user DN for the Directory Server?
+SEVERE_ERR_INSTALLDS_NO_ROOT_PASSWORD=ERROR:  No password was provided \
+ for the initial root user.  When performing a non-interactive installation, \
+ this must be provided using either the %s or the %s argument
+INFO_INSTALLDS_PROMPT_ROOT_PASSWORD=Please provide the password to use \
+ for the initial root user:
+INFO_INSTALLDS_PROMPT_CONFIRM_ROOT_PASSWORD=Please re-enter the password \
+ for confirmation:
+INFO_INSTALLDS_STATUS_CONFIGURING_DS=Applying the requested configuration \
+ to the Directory Server...
+INFO_INSTALLDS_STATUS_CREATING_BASE_LDIF=Creating a temporary LDIF file \
+ with the initial base entry contents...
+SEVERE_ERR_INSTALLDS_CANNOT_CREATE_BASE_ENTRY_LDIF=An error occurred \
+ while attempting to create the base LDIF file:  %s
+INFO_INSTALLDS_STATUS_IMPORTING_LDIF=Importing the LDIF data into the \
+ Directory Server database...
+INFO_INSTALLDS_STATUS_SUCCESS=The server setup process has completed \
+ successfully
+INFO_INSTALLDS_PROMPT_VALUE_YES=yes
+INFO_INSTALLDS_PROMPT_VALUE_NO=no
+MILD_ERR_INSTALLDS_INVALID_YESNO_RESPONSE=ERROR:  The provided value \
+ could not be interpreted as a yes or no response.  Please enter a response of \
+ either "yes" or "no"
+MILD_ERR_INSTALLDS_INVALID_INTEGER_RESPONSE=ERROR:  The provided response \
+ could not be interpreted as an integer.  Please provide the response as an \
+ integer value
+MILD_ERR_INSTALLDS_INTEGER_BELOW_LOWER_BOUND=ERROR:  The provided value \
+ is less than the lowest allowed value of %d
+MILD_ERR_INSTALLDS_INTEGER_ABOVE_UPPER_BOUND=ERROR:  The provided value \
+ is greater than the largest allowed value of %d
+MILD_ERR_INSTALLDS_INVALID_DN_RESPONSE=ERROR:  The provided response \
+ could not be interpreted as an LDAP DN
+MILD_ERR_INSTALLDS_INVALID_STRING_RESPONSE=ERROR:  The response value may \
+ not be an empty string
+MILD_ERR_INSTALLDS_INVALID_PASSWORD_RESPONSE=ERROR:  The password value \
+ may not be an empty string
+MILD_ERR_INSTALLDS_PASSWORDS_DONT_MATCH=ERROR:  The provided password \
+ values do not match
+MILD_ERR_INSTALLDS_ERROR_READING_FROM_STDIN=ERROR:  Unexpected failure \
+ while reading from standard input:  %s
+INFO_LDIFIMPORT_DESCRIPTION_QUIET=Use quiet mode (no output)
+INFO_INSTALLDS_IMPORT_SUCCESSFUL=Import complete
+INFO_INSTALLDS_INITIALIZING=Please wait while the setup program \
+ initializes...
+MILD_ERR_MAKELDIF_TAG_INVALID_ARGUMENT_COUNT=Invalid number of arguments \
+ provided for tag %s on line number %d of the template file:  expected %d, got \
+ %d
+MILD_ERR_MAKELDIF_TAG_INVALID_ARGUMENT_RANGE_COUNT=Invalid number of \
+ arguments provided for tag %s on line number %d of the template file: \
+ expected between %d and %d, got %d
+MILD_ERR_MAKELDIF_TAG_UNDEFINED_ATTRIBUTE=Undefined attribute %s \
+ referenced on line %d of the template file
+MILD_ERR_MAKELDIF_TAG_INTEGER_BELOW_LOWER_BOUND=Value %d is below the \
+ lowest allowed value of %d for tag %s on line %d of the template file
+MILD_ERR_MAKELDIF_TAG_CANNOT_PARSE_AS_INTEGER=Cannot parse value "%s" as \
+ an integer for tag %s on line %d of the template file
+MILD_ERR_MAKELDIF_TAG_INTEGER_ABOVE_UPPER_BOUND=Value %d is above the \
+ largest allowed value of %d for tag %s on line %d of the template file
+MILD_ERR_MAKELDIF_TAG_INVALID_EMPTY_STRING_ARGUMENT=Argument %d for tag \
+ %s on line number %d may not be an empty string
+MILD_ERR_MAKELDIF_TAG_CANNOT_PARSE_AS_BOOLEAN=Cannot parse value "%s" as \
+ a Boolean value for tag %s on line %d of the template file.  The value must \
+ be either 'true' or 'false'
+MILD_ERR_MAKELDIF_UNDEFINED_BRANCH_SUBORDINATE=The branch with entry DN \
+ '%s' references a subordinate template named '%s' which is not defined in the \
+ template file
+MILD_ERR_MAKELDIF_CANNOT_LOAD_TAG_CLASS=Unable to load class %s for use \
+ as a MakeLDIF tag
+MILD_ERR_MAKELDIF_CANNOT_INSTANTIATE_TAG=Cannot instantiate class %s as a \
+ MakeLDIF tag
+MILD_ERR_MAKELDIF_CONFLICTING_TAG_NAME=Cannot register the tag defined in \
+ class %s because the tag name %s conflicts with the name of another tag that \
+ has already been registered
+MILD_WARN_MAKELDIF_WARNING_UNDEFINED_CONSTANT=Possible reference to an \
+ undefined constant %s on line %d
+MILD_ERR_MAKELDIF_DEFINE_MISSING_EQUALS=The constant definition on line \
+ %d is missing an equal sign to delimit the constant name from the value
+MILD_ERR_MAKELDIF_DEFINE_NAME_EMPTY=The constant definition on line %d \
+ does not include a name for the constant
+MILD_ERR_MAKELDIF_CONFLICTING_CONSTANT_NAME=The definition for constant \
+ %s on line %d conflicts with an earlier constant definition included in the \
+ template
+MILD_ERR_MAKELDIF_WARNING_DEFINE_VALUE_EMPTY=Constant %s defined on line \
+ %d has not been assigned a value
+MILD_ERR_MAKELDIF_CONFLICTING_BRANCH_DN=The branch definition %s starting \
+ on line %d conflicts with an earlier branch definition contained in the \
+ template file
+MILD_ERR_MAKELDIF_CONFLICTING_TEMPLATE_NAME=The template definition %s \
+ starting on line %d conflicts with an earlier template definition contained \
+ in the template file
+MILD_ERR_MAKELDIF_UNEXPECTED_TEMPLATE_FILE_LINE=Unexpected template line \
+ "%s" encountered on line %d of the template file
+MILD_ERR_MAKELDIF_UNDEFINED_TEMPLATE_SUBORDINATE=The template named %s \
+ references a subordinate template named %s which is not defined in the \
+ template file
+MILD_ERR_MAKELDIF_CANNOT_DECODE_BRANCH_DN=Unable to decode branch DN "%s" \
+ on line %d of the template file
+MILD_ERR_MAKELDIF_BRANCH_SUBORDINATE_TEMPLATE_NO_COLON=Subordinate \
+ template definition on line %d for branch %s is missing a colon to separate \
+ the template name from the number of entries
+MILD_ERR_MAKELDIF_BRANCH_SUBORDINATE_INVALID_NUM_ENTRIES=Subordinate \
+ template definition on line %d for branch %s specified invalid number of \
+ entries %d for template %s
+MILD_WARN_MAKELDIF_BRANCH_SUBORDINATE_ZERO_ENTRIES=Subordinate template \
+ definition on line %d for branch %s specifies that zero entries of type %s \
+ should be generated
+MILD_ERR_MAKELDIF_BRANCH_SUBORDINATE_CANT_PARSE_NUMENTRIES=Unable to \
+ parse the number of entries for template %s as an integer for the subordinate \
+ template definition on line %d for branch %s
+MILD_ERR_MAKELDIF_TEMPLATE_SUBORDINATE_TEMPLATE_NO_COLON=Subordinate \
+ template definition on line %d for template %s is missing a colon to separate \
+ the template name from the number of entries
+MILD_ERR_MAKELDIF_TEMPLATE_SUBORDINATE_INVALID_NUM_ENTRIES=Subordinate \
+ template definition on line %d for template %s specified invalid number of \
+ entries %d for subordinate template %s
+MILD_WARN_MAKELDIF_TEMPLATE_SUBORDINATE_ZERO_ENTRIES=Subordinate template \
+ definition on line %d for template %s specifies that zero entries of type %s \
+ should be generated
+MILD_ERR_MAKELDIF_TEMPLATE_SUBORDINATE_CANT_PARSE_NUMENTRIES=Unable to \
+ parse the number of entries for template %s as an integer for the subordinate \
+ template definition on line %d for template %s
+MILD_ERR_MAKELDIF_TEMPLATE_MISSING_RDN_ATTR=The template named %s \
+ includes RDN attribute %s that is not assigned a value in that template
+MILD_ERR_MAKELDIF_NO_COLON_IN_BRANCH_EXTRA_LINE=There is no colon to \
+ separate the attribute name from the value pattern on line %d of the template \
+ file in the definition for branch %s
+MILD_ERR_MAKELDIF_NO_ATTR_IN_BRANCH_EXTRA_LINE=There is no attribute name \
+ before the colon on line %d of the template file in the definition for branch \
+ %s
+MILD_WARN_MAKELDIF_NO_VALUE_IN_BRANCH_EXTRA_LINE=The value pattern for \
+ line %d of the template file in the definition for branch %s is empty
+MILD_ERR_MAKELDIF_NO_COLON_IN_TEMPLATE_LINE=There is no colon to separate \
+ the attribute name from the value pattern on line %d of the template file in \
+ the definition for template %s
+MILD_ERR_MAKELDIF_NO_ATTR_IN_TEMPLATE_LINE=There is no attribute name \
+ before the colon on line %d of the template file in the definition for \
+ template %s
+MILD_WARN_MAKELDIF_NO_VALUE_IN_TEMPLATE_LINE=The value pattern for line \
+ %d of the template file in the definition for template %s is empty
+MILD_ERR_MAKELDIF_NO_SUCH_TAG=An undefined tag %s is referenced on line \
+ %d of the template file
+MILD_ERR_MAKELDIF_CANNOT_INSTANTIATE_NEW_TAG=An unexpected error occurred \
+ while trying to create a new instance of tag %s referenced on line %d of the \
+ template file:  %s
+INFO_MAKELDIF_DESCRIPTION_TEMPLATE=The path to the template file with \
+ information about the LDIF data to generate
+INFO_MAKELDIF_DESCRIPTION_LDIF=The path to the LDIF file to be written
+INFO_MAKELDIF_DESCRIPTION_SEED=The seed to use to initialize the random \
+ number generator
+INFO_MAKELDIF_DESCRIPTION_HELP=Show this usage information
+SEVERE_ERR_MAKELDIF_CANNOT_INITIALIZE_JMX=An error occurred while \
+ attempting to initialize the Directory Server JMX subsystem based on the \
+ information in configuration file %s:  %s
+SEVERE_ERR_MAKELDIF_CANNOT_INITIALIZE_CONFIG=An error occurred while \
+ attempting to process the Directory Server configuration file %s:  %s
+SEVERE_ERR_MAKELDIF_CANNOT_INITIALIZE_SCHEMA=An error occurred while \
+ attempting to initialize the Directory Server schema based on the information \
+ in configuration file %s:  %s
+SEVERE_ERR_MAKELDIF_IOEXCEPTION_DURING_PARSE=An error occurred while \
+ attempting to read the template file:  %s
+SEVERE_ERR_MAKELDIF_EXCEPTION_DURING_PARSE=An error occurred while \
+ attempting to parse the template file:  %s
+MILD_ERR_MAKELDIF_TAG_INVALID_FORMAT_STRING=Cannot parse value "%s" as an \
+ valid format string for tag %s on line %d of the template file
+MILD_ERR_MAKELDIF_TAG_NO_RANDOM_TYPE_ARGUMENT=The random tag on line %d \
+ of the template file does not include an argument to specify the type of \
+ random value that should be generated
+MILD_WARN_MAKELDIF_TAG_WARNING_EMPTY_VALUE=The value generated from the \
+ random tag on line %d of the template file will always be an empty string
+MILD_ERR_MAKELDIF_TAG_UNKNOWN_RANDOM_TYPE=The random tag on line %d of \
+ the template file references an unknown random type of %s
+INFO_MAKELDIF_DESCRIPTION_RESOURCE_PATH=Path to look for \
+ MakeLDIF resources (e.g., data files) not found in the current working \
+ directory or template directory path
+MILD_ERR_MAKELDIF_COULD_NOT_FIND_TEMPLATE_FILE=Could not find template \
+ file %s
+MILD_ERR_MAKELDIF_NO_SUCH_RESOURCE_DIRECTORY=The specified resource \
+ directory %s could not be found
+MILD_ERR_MAKELDIF_RESOURCE_DIRECTORY_NOT_DIRECTORY=The specified resource \
+ directory %s exists but is not a directory
+MILD_ERR_MAKELDIF_TAG_CANNOT_FIND_FILE=Cannot find file %s referenced by \
+ tag %s on line %d of the template file
+MILD_ERR_MAKELDIF_TAG_INVALID_FILE_ACCESS_MODE=Invalid file access mode \
+ %s for tag %s on line %d of the template file.  It must be either \
+ "sequential" or "random"
+MILD_ERR_MAKELDIF_TAG_CANNOT_READ_FILE=An error occurred while trying to \
+ read file %s referenced by tag %s on line %d of the template file:  %s
+MILD_ERR_MAKELDIF_UNABLE_TO_CREATE_LDIF=An error occurred while \
+ attempting to open LDIF file %s for writing:  %s
+MILD_ERR_MAKELDIF_ERROR_WRITING_LDIF=An error occurred while writing data \
+ to LDIF file %s:  %s
+INFO_MAKELDIF_PROCESSED_N_ENTRIES=Processed %d entries
+MILD_ERR_MAKELDIF_CANNOT_WRITE_ENTRY=An error occurred while attempting \
+ to write entry %s to LDIF:  %s
+INFO_MAKELDIF_PROCESSING_COMPLETE=LDIF processing complete.  %d entries \
+ written
+INFO_LDIFIMPORT_DESCRIPTION_TEMPLATE_FILE=Path to a MakeLDIF template to \
+ use to generate the import data
+SEVERE_ERR_LDIFIMPORT_CONFLICTING_OPTIONS=The %s and %s arguments are \
+ incompatible and may not be used together
+SEVERE_ERR_LDIFIMPORT_MISSING_REQUIRED_ARGUMENT=Neither the %s or the %s \
+ argument was provided.  One of these arguments must be given to specify the \
+ source for the LDIF data to be imported
+SEVERE_ERR_LDIFIMPORT_CANNOT_PARSE_TEMPLATE_FILE=Unable to parse the \
+ specified file %s as a MakeLDIF template file:  %s
+MILD_ERR_MAKELDIF_INCOMPLETE_TAG=Line %d of the template file contains an \
+ incomplete tag that starts with either '<' or '{' but does get closed
+MILD_ERR_MAKELDIF_TAG_NOT_ALLOWED_IN_BRANCH=Tag %s referenced on line %d \
+ of the template file is not allowed for use in branch definitions
+INFO_LDIFIMPORT_DESCRIPTION_RANDOM_SEED=Seed for the MakeLDIF random \
+ number generator
+MILD_ERR_LDIFMODIFY_CANNOT_ADD_ENTRY_TWICE=Entry %s is added twice in the \
+ set of changes to apply, which is not supported by the LDIF modify tool
+MILD_ERR_LDIFMODIFY_CANNOT_DELETE_AFTER_ADD=Entry %s cannot be deleted \
+ because it was previously added in the set of changes.  This is not supported \
+ by the LDIF modify tool
+MILD_ERR_LDIFMODIFY_CANNOT_MODIFY_ADDED_OR_DELETED=Cannot modify entry %s \
+ because it was previously added or deleted in the set of changes.  This is \
+ not supported by the LDIF modify tool
+MILD_ERR_LDIFMODIFY_MODDN_NOT_SUPPORTED=The modify DN operation targeted \
+ at entry %s cannot be processed because modify DN operations are not \
+ supported by the LDIF modify tool
+MILD_ERR_LDIFMODIFY_UNKNOWN_CHANGETYPE=Entry %s has an unknown changetype \
+ of %s
+MILD_ERR_LDIFMODIFY_ADD_ALREADY_EXISTS=Unable to add entry %s because it \
+ already exists in the data set
+MILD_ERR_LDIFMODIFY_DELETE_NO_SUCH_ENTRY=Unable to delete entry %s \
+ because it does not exist in the data set
+MILD_ERR_LDIFMODIFY_MODIFY_NO_SUCH_ENTRY=Unable to modify entry %s \
+ because it does not exist in the data set
+INFO_LDIFMODIFY_DESCRIPTION_SOURCE=LDIF file containing the \
+ data to be updated
+INFO_LDIFMODIFY_DESCRIPTION_CHANGES=LDIF file containing \
+ the changes to apply
+INFO_LDIFMODIFY_DESCRIPTION_TARGET=File to which the \
+ updated data should be written
+INFO_LDIFMODIFY_DESCRIPTION_HELP=Displays this usage information
+SEVERE_ERR_LDIFMODIFY_CANNOT_INITIALIZE_JMX=An error occurred while \
+ attempting to initialize the Directory Server JMX subsystem based on the \
+ information in configuration file %s:  %s
+SEVERE_ERR_LDIFMODIFY_CANNOT_INITIALIZE_CONFIG=An error occurred while \
+ attempting to process the Directory Server configuration file %s:  %s
+SEVERE_ERR_LDIFMODIFY_CANNOT_INITIALIZE_SCHEMA=An error occurred while \
+ attempting to initialize the Directory Server schema based on the information \
+ in configuration file %s:  %s
+SEVERE_ERR_LDIFMODIFY_SOURCE_DOES_NOT_EXIST=The source LDIF file %s does \
+ not exist
+SEVERE_ERR_LDIFMODIFY_CANNOT_OPEN_SOURCE=Unable to open the source LDIF \
+ file %s:  %s
+SEVERE_ERR_LDIFMODIFY_CHANGES_DOES_NOT_EXIST=The changes LDIF file %s \
+ does not exist
+SEVERE_ERR_LDIFMODIFY_CANNOT_OPEN_CHANGES=Unable to open the changes LDIF \
+ file %s:  %s
+SEVERE_ERR_LDIFMODIFY_CANNOT_OPEN_TARGET=Unable to open the target LDIF \
+ file %s for writing:  %s
+SEVERE_ERR_LDIFMODIFY_ERROR_PROCESSING_LDIF=An error occurred while \
+ processing the requested changes:  %s
+INFO_LDAPPWMOD_DESCRIPTION_HOST=Address of the Directory \
+ Server system
+INFO_LDAPPWMOD_DESCRIPTION_PORT=Port on which the Directory \
+ Server listens for LDAP client connections
+INFO_LDAPPWMOD_DESCRIPTION_BIND_DN=DN to use to bind to the server
+INFO_LDAPPWMOD_DESCRIPTION_BIND_PW=Password to use to bind to the server
+INFO_LDAPPWMOD_DESCRIPTION_BIND_PW_FILE=Path to a file \
+ containing the password to use to bind to the server
+INFO_LDAPPWMOD_DESCRIPTION_AUTHZID=Authorization ID for the \
+ user entry whose password should be changed
+INFO_LDAPPWMOD_DESCRIPTION_PROVIDE_DN_FOR_AUTHZID=Use the bind \
+ DN as the authorization ID for the password modify operation
+INFO_LDAPPWMOD_DESCRIPTION_NEWPW=New password to provide \
+ for the target user
+INFO_LDAPPWMOD_DESCRIPTION_NEWPWFILE=Path to a file \
+ containing the new password to provide for the target user
+INFO_LDAPPWMOD_DESCRIPTION_CURRENTPW=Current password for \
+ the target user
+INFO_LDAPPWMOD_DESCRIPTION_CURRENTPWFILE=Path to a file \
+ containing the current password for the target user
+INFO_LDAPPWMOD_DESCRIPTION_USE_SSL=Use SSL to secure the communication \
+ with the Directory Server
+INFO_LDAPPWMOD_DESCRIPTION_USE_STARTTLS=Use StartTLS to secure the \
+ communication with the Directory Server
+INFO_LDAPPWMOD_DESCRIPTION_BLIND_TRUST=Blindly trust any SSL certificate \
+ presented by the server
+INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE=Path to the key store to use when \
+ establishing SSL/TLS communication with the server
+INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE_PINFILE=Path to a file containing \
+ the PIN needed to access the contents of the key store
+INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE=Path to the trust store to use \
+ when establishing SSL/TLS communication with the server
+INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE_PINFILE=Path to a file \
+ containing the PIN needed to access the contents of the trust store
+SEVERE_ERR_LDAPPWMOD_CONFLICTING_ARGS=The %s and %s arguments may not be \
+ provided together
+SEVERE_ERR_LDAPPWMOD_BIND_DN_AND_PW_MUST_BE_TOGETHER=If either a bind DN \
+ or bind password is provided, then the other must be given as well
+SEVERE_ERR_LDAPPWMOD_ANON_REQUIRES_AUTHZID_AND_CURRENTPW=If a bind DN and \
+ password are not provided, then an authorization ID and current password must \
+ be given
+SEVERE_ERR_LDAPPWMOD_DEPENDENT_ARGS=If the %s argument is provided, then \
+ the  %s argument must also be given
+SEVERE_ERR_LDAPPWMOD_ERROR_INITIALIZING_SSL=Unable to initialize SSL/TLS \
+ support:  %s
+SEVERE_ERR_LDAPPWMOD_CANNOT_CONNECT=An error occurred while attempting to \
+ connect to the Directory Server:  %s
+SEVERE_ERR_LDAPPWMOD_CANNOT_SEND_PWMOD_REQUEST=Unable to send the LDAP \
+ password modify request:  %s
+SEVERE_ERR_LDAPPWMOD_CANNOT_READ_PWMOD_RESPONSE=Unable to read the LDAP \
+ password modify response:  %s
+SEVERE_ERR_LDAPPWMOD_FAILED=The LDAP password modify operation failed: \
+ %d (%s)
+SEVERE_ERR_LDAPPWMOD_FAILURE_ERROR_MESSAGE=Error Message:  %s
+SEVERE_ERR_LDAPPWMOD_FAILURE_MATCHED_DN=Matched DN:  %s
+INFO_LDAPPWMOD_SUCCESSFUL=The LDAP password modify operation was \
+ successful
+INFO_LDAPPWMOD_ADDITIONAL_INFO=Additional Info:  %s
+INFO_LDAPPWMOD_GENERATED_PASSWORD=Generated Password:  %s
+SEVERE_ERR_LDAPPWMOD_UNRECOGNIZED_VALUE_TYPE=Unable to decode the \
+ password modify response value because it contained an invalid element type \
+ of %s
+SEVERE_ERR_LDAPPWMOD_COULD_NOT_DECODE_RESPONSE_VALUE=Unable to decode the \
+ password modify response value:  %s
+SEVERE_ERR_INSTALLDS_IMPORT_UNSUCCESSFUL=Import failed
+INFO_COMPARE_CANNOT_BASE64_DECODE_ASSERTION_VALUE=The assertion value was \
+ indicated to be base64-encoded, but an error occurred while trying to decode \
+ the value
+INFO_COMPARE_CANNOT_READ_ASSERTION_VALUE_FROM_FILE=Unable to read the \
+ assertion value from the specified file:  %s
+INFO_WAIT4DEL_DESCRIPTION_TARGET_FILE=Path to the file to \
+ watch for deletion
+INFO_WAIT4DEL_DESCRIPTION_LOG_FILE=Path to a file \
+ containing log output to monitor
+INFO_WAIT4DEL_DESCRIPTION_TIMEOUT=Maximum length of time in seconds \
+ to wait for the target file to be deleted before exiting
+INFO_WAIT4DEL_DESCRIPTION_HELP=Displays this usage information
+SEVERE_WARN_WAIT4DEL_CANNOT_OPEN_LOG_FILE=WARNING:  Unable to open log \
+ file %s for reading:  %s
+SEVERE_ERR_LDAPCOMPARE_NO_DNS=No entry DNs provided for the compare \
+ operation
+INFO_BACKUPDB_TOOL_DESCRIPTION=This utility can be used to back up one or \
+ more Directory Server backends
+INFO_CONFIGDS_TOOL_DESCRIPTION=This utility can be used to define a base \
+ configuration for the Directory Server
+INFO_ENCPW_TOOL_DESCRIPTION=This utility can be used to encode user \
+ passwords with a specified storage scheme, or to determine whether a given \
+ clear-text value matches a provided encoded password
+INFO_LDIFEXPORT_TOOL_DESCRIPTION=This utility can be used to export data \
+ from a Directory Server backend in LDIF form
+INFO_LDIFIMPORT_TOOL_DESCRIPTION=This utility can be used to import LDIF \
+ data into a Directory Server backend
+INFO_INSTALLDS_TOOL_DESCRIPTION=This utility can be used to setup the \
+ Directory Server
+INFO_LDAPCOMPARE_TOOL_DESCRIPTION=This utility can be used to perform \
+ LDAP compare operations in the Directory Server
+INFO_LDAPDELETE_TOOL_DESCRIPTION=This utility can be used to perform LDAP \
+ delete operations in the Directory Server
+INFO_LDAPMODIFY_TOOL_DESCRIPTION=This utility can be used to perform LDAP \
+ modify, add, delete, and modify DN operations in the Directory Server
+INFO_LDAPPWMOD_TOOL_DESCRIPTION=This utility can be used to perform LDAP \
+ password modify operations in the Directory Server
+INFO_LDAPSEARCH_TOOL_DESCRIPTION=This utility can be used to perform LDAP \
+ search operations in the Directory Server
+INFO_LDIFDIFF_TOOL_DESCRIPTION=This utility can be used to compare two \
+ LDIF files and report the differences in LDIF format
+INFO_LDIFMODIFY_TOOL_DESCRIPTION=This utility can be used to apply a set \
+ of modify, add, and delete operations against data in an LDIF file
+INFO_LDIFSEARCH_TOOL_DESCRIPTION=This utility can be used to perform \
+ search operations against data in an LDIF file
+INFO_MAKELDIF_TOOL_DESCRIPTION=This utility can be used to generate LDIF \
+ data based on a definition in a template file
+INFO_RESTOREDB_TOOL_DESCRIPTION=This utility can be used to restore a \
+ backup of a Directory Server backend
+INFO_STOPDS_TOOL_DESCRIPTION=This utility can be used to request that the \
+ Directory Server stop running or perform a restart
+INFO_VERIFYINDEX_TOOL_DESCRIPTION=This utility can be used to ensure that \
+ index data is consistent within a backend based on the Berkeley DB Java \
+ Edition
+INFO_WAIT4DEL_TOOL_DESCRIPTION=This utility can be used to wait for a \
+ file to be removed from the filesystem
+SEVERE_ERR_TOOL_CONFLICTING_ARGS=You may not provide both the --%s and \
+ the --%s arguments
+SEVERE_ERR_LDAPCOMPARE_NO_ATTR=No attribute was specified to use as the \
+ target for the comparison
+SEVERE_ERR_LDAPCOMPARE_INVALID_ATTR_STRING=Invalid attribute string '%s'. \
+ The attribute string must be in one of the following forms: \
+ 'attribute:value', 'attribute::base64value', or 'attribute:<valueFilePath'
+SEVERE_ERR_TOOL_INVALID_CONTROL_STRING=Invalid control specification '%s'
+SEVERE_ERR_TOOL_SASLEXTERNAL_NEEDS_SSL_OR_TLS=SASL EXTERNAL \
+ authentication may only be requested if SSL or StartTLS is used
+SEVERE_ERR_TOOL_SASLEXTERNAL_NEEDS_KEYSTORE=SASL EXTERNAL authentication \
+ may only be used if a client certificate key store is specified
+INFO_LDAPSEARCH_PSEARCH_CHANGE_TYPE=# Persistent search change type:  %s
+INFO_LDAPSEARCH_PSEARCH_PREVIOUS_DN=# Persistent search previous entry \
+ DN:  %s
+INFO_LDAPSEARCH_ACCTUSABLE_HEADER=# Account Usability Response Control
+INFO_LDAPSEARCH_ACCTUSABLE_IS_USABLE=#   The account is usable
+INFO_LDAPSEARCH_ACCTUSABLE_TIME_UNTIL_EXPIRATION=#   Time until password \
+ expiration:  %s
+INFO_LDAPSEARCH_ACCTUSABLE_NOT_USABLE=#   The account is not usable
+INFO_LDAPSEARCH_ACCTUSABLE_ACCT_INACTIVE=#   The account has been \
+ deactivated
+INFO_LDAPSEARCH_ACCTUSABLE_PW_RESET=#   The password has been reset
+INFO_LDAPSEARCH_ACCTUSABLE_PW_EXPIRED=#   The password has expired
+INFO_LDAPSEARCH_ACCTUSABLE_REMAINING_GRACE=#   Number of grace logins \
+ remaining:  %d
+INFO_LDAPSEARCH_ACCTUSABLE_LOCKED=#   The account is locked
+INFO_LDAPSEARCH_ACCTUSABLE_TIME_UNTIL_UNLOCK=#   Time until the account \
+ is unlocked:  %s
+INFO_DESCRIPTION_KEYSTOREPASSWORD_FILE=Certificate key store PIN file
+INFO_DESCRIPTION_TRUSTSTOREPASSWORD=Certificate trust store PIN
+INFO_DESCRIPTION_TRUSTSTOREPASSWORD_FILE=Certificate trust store PIN file
+INFO_LISTBACKENDS_TOOL_DESCRIPTION=This utility can be used to list the \
+ backends and base DNs configured in the Directory Server
+INFO_LISTBACKENDS_DESCRIPTION_BACKEND_ID=Backend ID of the backend for \
+ which to list the base DNs
+INFO_LISTBACKENDS_DESCRIPTION_BASE_DN=Base DN for which to list the \
+ backend ID
+INFO_LISTBACKENDS_DESCRIPTION_HELP=Display this usage information
+SEVERE_ERR_LISTBACKENDS_CANNOT_GET_BACKENDS=An error occurred while \
+ trying to read backend information from the server configuration:  %s
+SEVERE_ERR_LISTBACKENDS_INVALID_DN=The provided base DN value '%s' could \
+ not be parsed as a valid DN:  %s
+INFO_LISTBACKENDS_NOT_BASE_DN=The provided DN '%s' is not a base DN for \
+ any backend configured in the Directory Server
+INFO_LISTBACKENDS_NO_BACKEND_FOR_DN=The provided DN '%s' is not below any \
+ base DN for any of the backends configured in the Directory Server
+INFO_LISTBACKENDS_DN_BELOW_BASE=The provided DN '%s' is below '%s' which \
+ is configured as a base DN for backend '%s'
+INFO_LISTBACKENDS_BASE_FOR_ID=The provided DN '%s' is a base DN for \
+ backend '%s'
+INFO_LISTBACKENDS_LABEL_BACKEND_ID=Backend ID
+INFO_LISTBACKENDS_LABEL_BASE_DN=Base DN
+SEVERE_ERR_LISTBACKENDS_NO_SUCH_BACKEND=There is no backend with ID '%s' \
+ in the server configuration
+SEVERE_ERR_LISTBACKENDS_NO_VALID_BACKENDS=None of the provided backend \
+ IDs exist in the server configuration
+SEVERE_ERR_ENCPW_INVALID_ENCODED_USERPW=The provided password is not a \
+ valid encoded user password value:  %s
+INFO_ENCPW_DESCRIPTION_USE_COMPARE_RESULT=Use the LDAP compare result as \
+ an exit code for the password comparison
+INFO_DESCRIPTION_COUNT_ENTRIES=Count the number of entries returned by \
+ the server
+INFO_LDAPSEARCH_MATCHING_ENTRY_COUNT=# Total number of matching entries: \
+ %d
+INFO_INSTALLDS_DESCRIPTION_CLI=Use the command line install. \
+ If not specified the graphical interface will be launched.  The rest of the \
+ options (excluding help and version) will only be taken into account if this \
+ option is specified
+INFO_INSTALLDS_DESCRIPTION_SAMPLE_DATA=Specifies that the database should \
+ be populated with the specified number of sample entries
+INFO_INSTALLDS_HEADER_POPULATE_TYPE=Options for populating the database:
+INFO_INSTALLDS_POPULATE_OPTION_BASE_ONLY=Only create the base entry
+INFO_INSTALLDS_POPULATE_OPTION_LEAVE_EMPTY=Leave the database empty
+INFO_INSTALLDS_POPULATE_OPTION_IMPORT_LDIF=Import data from an LDIF file
+INFO_INSTALLDS_POPULATE_OPTION_GENERATE_SAMPLE=Load \
+ automatically-generated sample data
+INFO_INSTALLDS_PROMPT_POPULATE_CHOICE=Database population selection:
+SEVERE_ERR_INSTALLDS_NO_SUCH_LDIF_FILE=ERROR:  The specified LDIF file %s \
+ does not exist
+INFO_INSTALLDS_PROMPT_NUM_ENTRIES=Please specify the number of user \
+ entries to generate:
+SEVERE_ERR_INSTALLDS_CANNOT_CREATE_TEMPLATE_FILE=ERROR:  Cannot create \
+ the template file for generating sample data:  %s
+INFO_LDAPPWMOD_DESCRIPTION_KEYSTORE_PIN=The PIN needed to access the \
+ contents of the key store
+INFO_LDAPPWMOD_DESCRIPTION_TRUSTSTORE_PIN=The PIN needed to access the \
+ contents of the trust store
+INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_OPERATIONAL=Exclude operational \
+ attributes from the LDIF export
+INFO_LDAPPWMOD_PWPOLICY_WARNING=Password Policy Warning:  %s = %d
+INFO_LDAPPWMOD_PWPOLICY_ERROR=Password Policy Error:  %s
+MILD_ERR_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL=Unable to decode the \
+ password policy response control:  %s
+SEVERE_ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE=The \
+ connection to the Directory Server was closed before the bind response could \
+ be read
+INFO_DESCRIPTION_SIMPLE_PAGE_SIZE=Use the simple paged results control \
+ with the given page size
+SEVERE_ERR_PAGED_RESULTS_REQUIRES_SINGLE_FILTER=The simple paged results \
+ control may only be used with a single search filter
+SEVERE_ERR_PAGED_RESULTS_CANNOT_DECODE=Unable to decode the simple paged \
+ results control from the search response:  %s
+SEVERE_ERR_PAGED_RESULTS_RESPONSE_NOT_FOUND=The simple paged results \
+ response control was not found in the search result done message from the \
+ server
+INFO_LDIFDIFF_DESCRIPTION_SINGLE_VALUE_CHANGES=Each \
+ attribute-level change should be written as a separate modification per \
+ attribute value rather than one modification per entry
+SEVERE_ERR_PROMPTTM_REJECTING_CLIENT_CERT=Rejecting client certificate \
+ chain because the prompt trust manager may only be used to trust server \
+ certificates
+SEVERE_WARN_PROMPTTM_NO_SERVER_CERT_CHAIN=WARNING:  The server did not \
+ present a certificate chain.  Do you still wish to attempt connecting to the \
+ target server?
+SEVERE_WARN_PROMPTTM_CERT_EXPIRED=WARNING:  The server certificate is \
+ expired (expiration time:  %s)
+SEVERE_WARN_PROMPTTM_CERT_NOT_YET_VALID=WARNING:  The server certificate \
+ will not be valid until %s
+INFO_PROMPTTM_SERVER_CERT=The server is using the following certificate: \
+ \n    Subject DN:  %s\n    Issuer DN:  %s\n    Validity:  %s through %s\nDo \
+ you wish to trust this certificate and continue connecting to the server?
+INFO_PROMPTTM_YESNO_PROMPT=Please enter "yes" or "no":
+SEVERE_ERR_PROMPTTM_USER_REJECTED=The server certificate has been \
+ rejected by the user
+INFO_STOPDS_SERVER_ALREADY_STOPPED=Server already stopped
+INFO_STOPDS_GOING_TO_STOP=Stopping Server...\n
+INFO_STOPDS_CHECK_STOPPABILITY=Used to determine whether the server can \
+ be stopped or not and the mode to be used to stop it
+INFO_DESCRIPTION_CERT_NICKNAME=Nickname of certificate for SSL client \
+ authentication
+INFO_CONFIGDS_DESCRIPTION_JMX_PORT=Port on which the \
+ Directory Server should listen for JMX communication
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_JMX_PORT=An error occurred while \
+ attempting to update the port on which to listen for JMX communication:  %s
+INFO_INSTALLDS_DESCRIPTION_JMXPORT=Port on which the \
+ Directory Server should listen for JMX communication
+INFO_INSTALLDS_PROMPT_JMXPORT=On which port would you like the Directory \
+ Server to accept connections from JMX clients?
+SEVERE_ERR_TOOL_RESULT_CODE=Result Code:  %d (%s)
+SEVERE_ERR_TOOL_ERROR_MESSAGE=Additional Information:  %s
+SEVERE_ERR_TOOL_MATCHED_DN=Matched DN:  %s
+SEVERE_ERR_WINDOWS_SERVICE_NOT_FOUND=Could not find the service name for \
+ the server
+SEVERE_ERR_WINDOWS_SERVICE_START_ERROR=An unexpected error occurred \
+ starting the server as a windows service
+SEVERE_ERR_WINDOWS_SERVICE_STOP_ERROR=An unexpected error occurred \
+ stopping the server windows service
+INFO_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION=This utility can be used \
+ to configure the server as a Windows service
+INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE=Display this usage \
+ information
+INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE=Enables the server as a \
+ Windows service
+INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE=Disables the server as \
+ a Windows service and stops the server
+INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE=Provides information \
+ about the state of the server as a Windows service
+SEVERE_ERR_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS=You can only provide \
+ one of the following arguments:\nenableService, disableService, serviceState \
+ or cleanupService
+SEVERE_ERR_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS=You must provide at \
+ least one of the following arguments:\nenableService, disableService or \
+ serviceState or cleanupService
+INFO_WINDOWS_SERVICE_NAME=OpenDS
+INFO_WINDOWS_SERVICE_DESCRIPTION=Open source Next Generation Directory \
+ Server.  Installation path: %s
+INFO_WINDOWS_SERVICE_SUCCESSULLY_ENABLED=The server was successfully \
+ enabled to run as a Windows service
+INFO_WINDOWS_SERVICE_ALREADY_ENABLED=The server was already enabled to run \
+ as a Windows service
+SEVERE_ERR_WINDOWS_SERVICE_NAME_ALREADY_IN_USE=The server could not be \
+ enabled to run as a Windows service.  The service name is already in use
+SEVERE_ERR_WINDOWS_SERVICE_ENABLE_ERROR=An unexpected error occurred \
+ trying to enable the server as a Windows service.%nCheck that you have \
+ administrator rights (only Administrators can enable the server to run as a \
+ Windows Service)
+INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED=The server was successfully \
+ disabled as a Windows service
+INFO_WINDOWS_SERVICE_ALREADY_DISABLED=The server was already disabled as a \
+ Windows service
+SEVERE_WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION=The server has been marked \
+ for deletion as a Windows Service
+SEVERE_ERR_WINDOWS_SERVICE_DISABLE_ERROR=An unexpected error occurred \
+ trying to disable the server as a Windows service%nCheck that you have \
+ administrator rights (only Administrators can disable the server as a Windows \
+ Service)
+INFO_WINDOWS_SERVICE_ENABLED=The server is enabled as a Windows service.  \
+ The service name for the server is: %s
+INFO_WINDOWS_SERVICE_DISABLED=The server is disabled as a Windows service
+SEVERE_ERR_WINDOWS_SERVICE_STATE_ERROR=An unexpected error occurred \
+ trying to retrieve the state of the server as a Windows service
+INFO_STOPDS_DESCRIPTION_WINDOWS_NET_STOP=Used by the window service code \
+ to inform that stop-ds is being called from the window services after a call \
+ to net stop
+INFO_WAIT4DEL_DESCRIPTION_OUTPUT_FILE=Path to a file to \
+ which the command will write the output
+SEVERE_WARN_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE=WARNING:  Unable to open \
+ output file %s for writing:  %s
+INFO_INSTALLDS_ENABLING_WINDOWS_SERVICE=Enabling the server as a Windows \
+ service...
+INFO_INSTALLDS_PROMPT_ENABLE_SERVICE=Enable the server to run as a Windows \
+ Service?
+INFO_INSTALLDS_DESCRIPTION_ENABLE_WINDOWS_SERVICE=Enable the server to run \
+ as a Windows Service
+INFO_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_CLEANUP=Allows to disable the \
+ server service and to clean up the windows registry information associated \
+ with the provided service name
+INFO_WINDOWS_SERVICE_CLEANUP_SUCCESS=Clean up of service %s was \
+ successful
+SEVERE_ERR_WINDOWS_SERVICE_CLEANUP_NOT_FOUND=Could not find the service \
+ with name %s
+SEVERE_WARN_WINDOWS_SERVICE_CLEANUP_MARKED_FOR_DELETION=Service %s has \
+ been marked for deletion
+SEVERE_ERR_WINDOWS_SERVICE_CLEANUP_ERROR=An unexpected error occurred \
+ cleaning up the service %s
+INFO_REBUILDINDEX_TOOL_DESCRIPTION=This utility can be used to rebuild \
+ index data within a backend based on the Berkeley DB Java Edition
+INFO_REBUILDINDEX_DESCRIPTION_BASE_DN=Base DN of a backend \
+ supporting indexing. Rebuild is performed on indexes within the scope of the \
+ given base DN
+INFO_REBUILDINDEX_DESCRIPTION_INDEX_NAME=Names of index(es) \
+ to rebuild. For an attribute index this is simply an attribute name.  At \
+ least one index must be specified for rebuild
+SEVERE_ERR_REBUILDINDEX_ERROR_DURING_REBUILD=An error occurred while \
+ attempting to perform index rebuild:  %s
+SEVERE_ERR_REBUILDINDEX_WRONG_BACKEND_TYPE=The backend does not support \
+ rebuilding of indexes
+SEVERE_ERR_REBUILDINDEX_REQUIRES_AT_LEAST_ONE_INDEX=At least one index \
+ must be specified for the rebuild process
+SEVERE_ERR_REBUILDINDEX_CANNOT_EXCLUSIVE_LOCK_BACKEND=An error occurred \
+ while attempting to acquire a exclusive lock for backend %s:  %s.  This \
+ generally means that some other process has an lock on this backend or the \
+ server is running with this backend online. The rebuild process cannot \
+ continue
+SEVERE_WARN_REBUILDINDEX_CANNOT_UNLOCK_BACKEND=An error occurred while \
+ attempting to release the shared lock for backend %s:  %s.  This lock should \
+ automatically be cleared when the rebuild process exits, so no further action \
+ should be required
+SEVERE_ERR_REBUILDINDEX_CANNOT_SHARED_LOCK_BACKEND=An error occurred \
+ while attempting to acquire a shared lock for backend %s:  %s.  This \
+ generally means that some other process has an exclusive lock on this backend \
+ (e.g., an LDIF import or a restore). The rebuild process cannot continue
+INFO_CONFIGDS_DESCRIPTION_LDAPS_PORT=Port on which the \
+ Directory Server should listen for LDAPS communication
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_LDAPS_PORT=An error occurred while \
+ attempting to update the port on which to listen for LDAPS communication:  %s
+INFO_CONFIGDS_DESCRIPTION_ENABLE_START_TLS=Specifies whether to enable or \
+ not StartTLS
+INFO_CONFIGDS_DESCRIPTION_KEYMANAGER_PROVIDER_DN=DN of the \
+ key manager provider to use for SSL and/or StartTLS
+INFO_CONFIGDS_DESCRIPTION_TRUSTMANAGER_PROVIDER_DN=DN of \
+ the trust manager provider to use for SSL and/or StartTLS
+SEVERE_ERR_CONFIGDS_CANNOT_PARSE_KEYMANAGER_PROVIDER_DN=An error occurred \
+ while attempting to parse key manager provider DN value "%s" as a DN:  %s
+SEVERE_ERR_CONFIGDS_CANNOT_PARSE_TRUSTMANAGER_PROVIDER_DN=An error \
+ occurred while attempting to parse trust manager provider DN value "%s" as a \
+ DN:  %s
+SEVERE_ERR_CONFIGDS_CANNOT_ENABLE_STARTTLS=An error occurred while \
+ attempting to enable StartTLS: %s
+SEVERE_ERR_CONFIGDS_CANNOT_ENABLE_KEYMANAGER=An error occurred while \
+ attempting to enable key manager provider entry: %s
+SEVERE_ERR_CONFIGDS_CANNOT_ENABLE_TRUSTMANAGER=An error occurred while \
+ attempting to enable trust manager provider entry: %s
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_KEYMANAGER_REFERENCE=An error occurred \
+ while attempting to update the key manager provider DN used for LDAPS \
+ communication: %s
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_TRUSTMANAGER_REFERENCE=An error \
+ occurred while attempting to update the trust manager provider DN used for \
+ LDAPS communication: %s
+INFO_CONFIGDS_DESCRIPTION_KEYMANAGER_PATH=Path of the \
+ key store to be used by the key manager provider
+INFO_CONFIGDS_DESCRIPTION_CERTNICKNAME=Nickname of the \
+ certificate that the connection handler should use when accepting SSL-based \
+ connections or performing StartTLS negotiation
+SEVERE_ERR_CONFIGDS_KEYMANAGER_PROVIDER_DN_REQUIRED=ERROR:  You must \
+ provide the %s argument when providing the %s argument
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_CERT_NICKNAME=An error occurred while \
+ attempting to update the nickname of the certificate that the connection \
+ handler should use when accepting SSL-based connections or performing \
+ StartTLS negotiation: %s
+INFO_LDAPMODIFY_DESCRIPTION_FILENAME=LDIF file containing \
+ the changes to apply
+MILD_ERR_MAKELDIF_TEMPLATE_INVALID_PARENT_TEMPLATE=The parent template %s \
+ referenced on line %d for template %s is invalid because the referenced \
+ parent template is not defined before the template that extends it
+INFO_DESCRIPTION_SORT_ORDER=Sort the results using the provided sort \
+ order
+MILD_ERR_LDAP_SORTCONTROL_INVALID_ORDER=The provided sort order was \
+ invalid:  %s
+INFO_DESCRIPTION_VLV=Use the virtual list view control to retrieve the \
+ specified results page
+MILD_ERR_LDAPSEARCH_VLV_REQUIRES_SORT=If the --%s argument is provided, \
+ then the --%s argument must also be given
+MILD_ERR_LDAPSEARCH_VLV_INVALID_DESCRIPTOR=The provided virtual list view \
+ descriptor was invalid.  It must be a value in the form \
+ 'beforeCount:afterCount:offset:contentCount' (where offset specifies the \
+ index of the target entry and contentCount specifies the estimated total \
+ number of results or zero if it is not known), or \
+ 'beforeCount:afterCount:assertionValue' (where the entry should be the first \
+ entry whose primary sort value is greater than or equal to the provided \
+ assertionValue).  In either case, beforeCount is the number of entries to \
+ return before the target value and afterCount is the number of entries to \
+ return after the target value
+SEVERE_WARN_LDAPSEARCH_SORT_ERROR=# Server-side sort failed:  %s
+SEVERE_WARN_LDAPSEARCH_CANNOT_DECODE_SORT_RESPONSE=# Unable to decode the \
+ server-side sort response:  %s
+INFO_LDAPSEARCH_VLV_TARGET_OFFSET=# VLV Target Offset:  %d
+INFO_LDAPSEARCH_VLV_CONTENT_COUNT=# VLV Content Count:  %d
+SEVERE_WARN_LDAPSEARCH_VLV_ERROR=# Virtual list view processing failed: \
+ %s
+SEVERE_WARN_LDAPSEARCH_CANNOT_DECODE_VLV_RESPONSE=# Unable to decode the \
+ virtual list view response:  %s
+SEVERE_ERR_LDIFIMPORT_CANNOT_READ_FILE=The specified LDIF file %s cannot \
+ be read
+INFO_DESCRIPTION_EFFECTIVERIGHTS_USER=Use geteffectiverights control with \
+ the provided authzid
+INFO_DESCRIPTION_EFFECTIVERIGHTS_ATTR=Specifies geteffectiverights \
+ control specific attribute list
+MILD_ERR_EFFECTIVERIGHTS_INVALID_AUTHZID=The authorization ID "%s" \
+ contained in the geteffectiverights control is invalid because it does not \
+ start with "dn:" to indicate a user DN
+INFO_DESCRIPTION_PRODUCT_VERSION=Display Directory Server version \
+ information
+INFO_DESCRIPTION_QUIET=Use quiet mode
+INFO_DESCRIPTION_SCRIPT_FRIENDLY=Use script-friendly mode
+INFO_DESCRIPTION_NO_PROMPT=Use non-interactive mode.  If data in \
+the command is missing, the user is not prompted and the tool will fail
+INFO_PWPSTATE_TOOL_DESCRIPTION=This utility can be used to retrieve and \
+ manipulate the values of password policy state variables
+INFO_PWPSTATE_DESCRIPTION_HOST=Directory server hostname or IP address
+INFO_PWPSTATE_DESCRIPTION_PORT=Directory server administration port number
+INFO_PWPSTATE_DESCRIPTION_USESSL=Use SSL for secure communication with \
+ the server
+INFO_PWPSTATE_DESCRIPTION_USESTARTTLS=Use StartTLS to secure \
+ communication with the server
+INFO_PWPSTATE_DESCRIPTION_BINDDN=The DN to use to bind to the server
+INFO_PWPSTATE_DESCRIPTION_BINDPW=The password to use to bind to the \
+ server
+INFO_PWPSTATE_DESCRIPTION_BINDPWFILE=The path to the file containing the \
+ bind password
+INFO_PWPSTATE_DESCRIPTION_TARGETDN=The DN of the user entry for which to \
+ get and set password policy state information
+INFO_PWPSTATE_DESCRIPTION_SASLOPTIONS=SASL bind options
+INFO_PWPSTATE_DESCRIPTION_TRUST_ALL=Trust all server SSL certificates
+INFO_PWPSTATE_DESCRIPTION_KSFILE=Certificate key store path
+INFO_PWPSTATE_DESCRIPTION_KSPW=Certificate key store PIN
+INFO_PWPSTATE_DESCRIPTION_KSPWFILE=Certificate key store PIN file
+INFO_PWPSTATE_DESCRIPTION_TSFILE=Certificate trust store path
+INFO_PWPSTATE_DESCRIPTION_TSPW=Certificate trust store PIN
+INFO_PWPSTATE_DESCRIPTION_TSPWFILE=Certificate trust store PIN file
+INFO_PWPSTATE_DESCRIPTION_SHOWUSAGE=Display this usage information
+INFO_DESCRIPTION_PWPSTATE_GET_ALL=Display all password policy state \
+ information for the user
+INFO_DESCRIPTION_PWPSTATE_GET_PASSWORD_POLICY_DN=Display the DN of the \
+ password policy for the user
+INFO_DESCRIPTION_PWPSTATE_GET_ACCOUNT_DISABLED_STATE=Display information \
+ about whether the user account has been administratively disabled
+INFO_DESCRIPTION_PWPSTATE_SET_ACCOUNT_DISABLED_STATE=Specify whether the \
+ user account has been administratively disabled
+INFO_DESCRIPTION_OPERATION_BOOLEAN_VALUE='true' to indicate that the \
+ account is disabled, or 'false' to indicate that it is not disabled
+INFO_DESCRIPTION_PWPSTATE_CLEAR_ACCOUNT_DISABLED_STATE=Clear account \
+ disabled state information from the user account
+INFO_DESCRIPTION_PWPSTATE_GET_ACCOUNT_EXPIRATION_TIME=Display when the \
+ user account will expire
+INFO_DESCRIPTION_PWPSTATE_SET_ACCOUNT_EXPIRATION_TIME=Specify when the \
+ user account will expire
+INFO_DESCRIPTION_OPERATION_TIME_VALUE=A timestamp value using the \
+ generalized time syntax
+INFO_DESCRIPTION_PWPSTATE_CLEAR_ACCOUNT_EXPIRATION_TIME=Clear account \
+ expiration time information from the user account
+INFO_DESCRIPTION_PWPSTATE_GET_SECONDS_UNTIL_ACCOUNT_EXPIRATION=Display \
+ the length of time in seconds until the user account expires
+INFO_DESCRIPTION_PWPSTATE_GET_PASSWORD_CHANGED_TIME=Display the time \
+ that the user's password was last changed
+INFO_DESCRIPTION_PWPSTATE_SET_PASSWORD_CHANGED_TIME=Specify the time \
+ that the user's password was last changed.  This should be used only for \
+ testing purposes
+INFO_DESCRIPTION_PWPSTATE_CLEAR_PASSWORD_CHANGED_TIME=Clear information \
+ about the time that the user's password was last changed.  This should be \
+ used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_GET_PASSWORD_EXPIRATION_WARNED_TIME=Display \
+ the time that the user first received an expiration warning notice
+INFO_DESCRIPTION_PWPSTATE_SET_PASSWORD_EXPIRATION_WARNED_TIME=Specify \
+ the time that the user first received an expiration warning notice.  This \
+ should be used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_CLEAR_PASSWORD_EXPIRATION_WARNED_TIME=Clear \
+ information about the time that the user first received an expiration warning \
+ notice.  This should be used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_GET_SECONDS_UNTIL_PASSWORD_EXP=Display length \
+ of time in seconds until the user's password expires
+INFO_DESCRIPTION_PWPSTATE_GET_SECONDS_UNTIL_PASSWORD_EXP_WARNING=Display \
+ the length of time in seconds until the user should start receiving password \
+ expiration warning notices
+INFO_DESCRIPTION_PWPSTATE_GET_AUTH_FAILURE_TIMES=Display the \
+ authentication failure times for the user
+INFO_DESCRIPTION_PWPSTATE_ADD_AUTH_FAILURE_TIME=Add an authentication \
+ failure time to the user account.  This should be used only for testing \
+ purposes
+INFO_DESCRIPTION_PWPSTATE_SET_AUTH_FAILURE_TIMES=Specify the \
+ authentication failure times for the user.  This should be used only for \
+ testing purposes
+INFO_DESCRIPTION_OPERATION_TIME_VALUES=A timestamp value using the \
+ generalized time syntax.  Multiple timestamp values may be given by providing \
+ this argument multiple times
+INFO_DESCRIPTION_PWPSTATE_CLEAR_AUTH_FAILURE_TIMES=Clear authentication \
+ failure time information from the user's account.  This should be used only \
+ for testing purposes
+INFO_DESCRIPTION_PWPSTATE_GET_SECONDS_UNTIL_AUTH_FAILURE_UNLOCK=Display \
+ the length of time in seconds until the authentication failure lockout \
+ expires
+INFO_DESCRIPTION_PWPSTATE_GET_REMAINING_AUTH_FAILURE_COUNT=Display the \
+ number of remaining authentication failures until the user's account is \
+ locked
+INFO_DESCRIPTION_PWPSTATE_GET_LAST_LOGIN_TIME=Display the time that the \
+ user last authenticated to the server
+INFO_DESCRIPTION_PWPSTATE_SET_LAST_LOGIN_TIME=Specify the time that the \
+ user last authenticated to the server.  This should be used only for testing \
+ purposes
+INFO_DESCRIPTION_PWPSTATE_CLEAR_LAST_LOGIN_TIME=Clear the time that the \
+ user last authenticated to the server.  This should be used only for testing \
+ purposes
+INFO_DESCRIPTION_PWPSTATE_GET_SECONDS_UNTIL_IDLE_LOCKOUT=Display the \
+ length of time in seconds until user's account is locked because it has \
+ remained idle for too long
+INFO_DESCRIPTION_PWPSTATE_GET_PASSWORD_RESET_STATE=Display information \
+ about whether the user will be required to change his or her password on the \
+ next successful authentication
+INFO_DESCRIPTION_PWPSTATE_SET_PASSWORD_RESET_STATE=Specify whether the \
+ user will be required to change his or her password on the next successful \
+ authentication.  This should be used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_CLEAR_PASSWORD_RESET_STATE=Clear information \
+ about whether the user will be required to change his or her password on the \
+ next successful authentication.  This should be used only for testing \
+ purposes
+INFO_DESCRIPTION_PWPSTATE_GET_SECONDS_UNTIL_RESET_LOCKOUT=Display the \
+ length of time in seconds until user's account is locked because the user \
+ failed to change the password in a timely manner after an administrative \
+ reset
+INFO_DESCRIPTION_PWPSTATE_GET_GRACE_LOGIN_USE_TIMES=Display the grace \
+ login use times for the user
+INFO_DESCRIPTION_PWPSTATE_ADD_GRACE_LOGIN_USE_TIME=Add a grace login use \
+ time to the user account.  This should be used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_SET_GRACE_LOGIN_USE_TIMES=Specify the grace \
+ login use times for the user.  This should be used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_CLEAR_GRACE_LOGIN_USE_TIMES=Clear the set of \
+ grace login use times for the user.  This should be used only for testing \
+ purposes
+INFO_DESCRIPTION_PWPSTATE_GET_REMAINING_GRACE_LOGIN_COUNT=Display the \
+ number of grace logins remaining for the user
+INFO_DESCRIPTION_PWPSTATE_GET_PW_CHANGED_BY_REQUIRED_TIME=Display the \
+ required password change time with which the user last complied
+INFO_DESCRIPTION_PWPSTATE_SET_PW_CHANGED_BY_REQUIRED_TIME=Specify the \
+ required password change time with which the user last complied.  This should \
+ be used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_CLEAR_PW_CHANGED_BY_REQUIRED_TIME=Clear \
+ information about the required password change time with which the user last \
+ complied.  This should be used only for testing purposes
+INFO_DESCRIPTION_PWPSTATE_GET_SECONDS_UNTIL_REQUIRED_CHANGE_TIME=Display \
+ the length of time in seconds that the user has remaining to change his or \
+ her password before the account becomes locked due to the required change \
+ time
+SEVERE_ERR_PWPSTATE_NO_SUBCOMMAND=No subcommand was provided to indicate \
+ which password policy state operation should be performed
+SEVERE_ERR_PWPSTATE_INVALID_BOOLEAN_VALUE=The provided value '%s' was \
+ invalid for the requested operation.  A Boolean value of either 'true' or \
+ 'false' was expected
+SEVERE_ERR_PWPSTATE_NO_BOOLEAN_VALUE=No value was specified, but the \
+ requested operation requires a Boolean value of either 'true' or 'false'
+SEVERE_ERR_PWPSTATE_INVALID_SUBCOMMAND=Unrecognized subcommand '%s'
+SEVERE_ERR_PWPSTATE_CANNOT_SEND_REQUEST_EXTOP=An error occurred while \
+ attempting to send the request to the server:  %s
+SEVERE_ERR_PWPSTATE_CONNECTION_CLOSED_READING_RESPONSE=The Directory \
+ Server closed the connection before the response could be read
+SEVERE_ERR_PWPSTATE_REQUEST_FAILED=The server was unable to process the \
+ request:  result code %d (%s), error message '%s'
+SEVERE_ERR_PWPSTATE_CANNOT_DECODE_RESPONSE_MESSAGE=The server was unable \
+ to decode the response message from the server:  %s
+SEVERE_ERR_PWPSTATE_CANNOT_DECODE_RESPONSE_OP=Unable to decode \
+ information about an operation contained in the response:  %s
+INFO_PWPSTATE_LABEL_PASSWORD_POLICY_DN=Password Policy DN
+INFO_PWPSTATE_LABEL_ACCOUNT_DISABLED_STATE=Account Is Disabled
+INFO_PWPSTATE_LABEL_ACCOUNT_EXPIRATION_TIME=Account Expiration Time
+INFO_PWPSTATE_LABEL_SECONDS_UNTIL_ACCOUNT_EXPIRATION=Seconds Until \
+ Account Expiration
+INFO_PWPSTATE_LABEL_PASSWORD_CHANGED_TIME=Password Changed Time
+INFO_PWPSTATE_LABEL_PASSWORD_EXPIRATION_WARNED_TIME=Password Expiration \
+ Warned Time
+INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_EXPIRATION=Seconds Until \
+ Password Expiration
+INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_EXPIRATION_WARNING=Seconds \
+ Until Password Expiration Warning
+INFO_PWPSTATE_LABEL_AUTH_FAILURE_TIMES=Authentication Failure Times
+INFO_PWPSTATE_LABEL_SECONDS_UNTIL_AUTH_FAILURE_UNLOCK=Seconds Until \
+ Authentication Failure Unlock
+INFO_PWPSTATE_LABEL_REMAINING_AUTH_FAILURE_COUNT=Remaining \
+ Authentication Failure Count
+INFO_PWPSTATE_LABEL_LAST_LOGIN_TIME=Last Login Time
+INFO_PWPSTATE_LABEL_SECONDS_UNTIL_IDLE_LOCKOUT=Seconds Until Idle \
+ Account Lockout
+INFO_PWPSTATE_LABEL_PASSWORD_RESET_STATE=Password Is Reset
+INFO_PWPSTATE_LABEL_SECONDS_UNTIL_PASSWORD_RESET_LOCKOUT=Seconds Until \
+ Password Reset Lockout
+INFO_PWPSTATE_LABEL_GRACE_LOGIN_USE_TIMES=Grace Login Use Times
+INFO_PWPSTATE_LABEL_REMAINING_GRACE_LOGIN_COUNT=Remaining Grace Login \
+ Count
+INFO_PWPSTATE_LABEL_PASSWORD_CHANGED_BY_REQUIRED_TIME=Password Changed \
+ by Required Time
+INFO_PWPSTATE_LABEL_SECONDS_UNTIL_REQUIRED_CHANGE_TIME=Seconds Until \
+ Required Change Time
+SEVERE_ERR_PWPSTATE_INVALID_RESPONSE_OP_TYPE=Unrecognized or invalid \
+ operation type:  %s
+SEVERE_ERR_PWPSTATE_MUTUALLY_EXCLUSIVE_ARGUMENTS=ERROR:  You may not \
+ provide both the %s and the %s arguments
+SEVERE_ERR_PWPSTATE_CANNOT_INITIALIZE_SSL=ERROR:  Unable to perform SSL \
+ initialization:  %s
+SEVERE_ERR_PWPSTATE_CANNOT_PARSE_SASL_OPTION=ERROR:  The provided SASL \
+ option string "%s" could not be parsed in the form "name=value"
+SEVERE_ERR_PWPSTATE_NO_SASL_MECHANISM=ERROR:  One or more SASL options \
+ were provided, but none of them were the "mech" option to specify which SASL \
+ mechanism should be used
+SEVERE_ERR_PWPSTATE_CANNOT_DETERMINE_PORT=ERROR:  Cannot parse the value \
+ of the %s argument as an integer value between 1 and 65535:  %s
+SEVERE_ERR_PWPSTATE_CANNOT_CONNECT=ERROR:  Cannot establish a connection to \
+ the Directory Server %s.  Verify that the server is running and that \
+ the provided credentials are valid.  Details:  %s
+INFO_UPGRADE_DESCRIPTION_FILE=Specifies an existing server package \
+ (.zip) file to which the current build will be upgraded using the command \
+ line version of this tool
+INFO_UPGRADE_DESCRIPTION_NO_PROMPT=Use non-interactive mode.  Prompt for \
+ any required information rather than fail
+INFO_UPGRADE_DESCRIPTION_SILENT=Perform a quiet upgrade or reversion
+INFO_LDIFIMPORT_DESCRIPTION_COUNT_REJECTS=Count the number of entries \
+ rejected by the server and return that value as the exit code (values > 255 \
+ will be reduced to 255 due to exit code restrictions)
+INFO_LDIFIMPORT_DESCRIPTION_SKIP_FILE=Write skipped entries to the \
+ specified file
+SEVERE_ERR_LDIFIMPORT_CANNOT_OPEN_SKIP_FILE=An error occurred while \
+ trying to open the skip file %s for writing:  %s
+INFO_VERIFYINDEX_DESCRIPTION_COUNT_ERRORS=Count the number of errors \
+ found during the verification and return that value as the exit code (values \
+ > 255 will be reduced to 255 due to exit code restrictions)
+INFO_PWPSTATE_LABEL_PASSWORD_HISTORY=Password History
+INFO_DESCRIPTION_PWPSTATE_GET_PASSWORD_HISTORY=Display password history \
+ state values for the user
+INFO_DESCRIPTION_PWPSTATE_CLEAR_PASSWORD_HISTORY=Clear password history \
+ state values for the user.  This should be used only for testing purposes
+SEVERE_ERR_CONFIGDS_PORT_ALREADY_SPECIFIED=ERROR:  You have specified \
+ the value %s for different ports
+SEVERE_ERR_CLI_ERROR_PROPERTY_UNRECOGNIZED=The property "%s" is not a \
+ recognized property
+SEVERE_ERR_CLI_ERROR_MISSING_PROPERTY=The mandatory property "%s" is \
+ missing
+SEVERE_ERR_CLI_ERROR_INVALID_PROPERTY_VALUE=The value "%s" specified for \
+ the property "%s" is invalid
+INFO_CLI_HEADING_PROPERTY_DEFAULT_VALUE=Default value
+INFO_REVERT_DESCRIPTION_DIRECTORY=Directory where reversion files are \
+ stored.  This should be one of the child directories of the 'history' \
+ directory that is created when the upgrade tool is run
+INFO_REVERT_DESCRIPTION_RECENT=The installation will be \
+ reverted to the state before the most recent upgrade
+INFO_REVERT_DESCRIPTION_INTERACTIVE=Prompt for any required information \
+ rather than fail
+INFO_REVERT_DESCRIPTION_SILENT=Perform a quiet reversion
+INFO_LDIFIMPORT_DESCRIPTION_CLEAR_BACKEND=Remove all entries for all \
+ base DNs in the backend before importing
+SEVERE_ERR_LDIFIMPORT_MISSING_BACKEND_ARGUMENT=Neither the %s or the %s \
+ argument was provided.  One of these arguments must be given to specify the \
+ backend for the LDIF data to be imported to
+SEVERE_ERR_LDIFIMPORT_MISSING_CLEAR_BACKEND=Importing to a backend \
+ without the append argument will remove all entries for all base DNs (%s) in \
+ the backend. The %s argument must be given to continue with import
+MILD_ERR_MAKELDIF_TAG_LIST_NO_ARGUMENTS=The list tag on line %d of the \
+ template file does not contain any arguments to specify the list values.  At \
+ least one list value must be provided
+MILD_WARN_MAKELDIF_TAG_LIST_INVALID_WEIGHT=The list tag on line %d of \
+ the template file contains item '%s' that includes a semicolon but that \
+ semicolon is not followed by an integer.  The semicolon will be assumed to be \
+ part of the value and not a delimiter to separate the value from its relative \
+ weight
+FATAL_ERR_INITIALIZE_SERVER_ROOT=An unexpected error occurred \
+  attempting to set the server's root directory to %s: %s
+SEVERE_ERR_LDAP_CONN_MUTUALLY_EXCLUSIVE_ARGUMENTS=ERROR:  You may not \
+ provide both the %s and the %s arguments
+SEVERE_ERR_LDAP_CONN_CANNOT_INITIALIZE_SSL=ERROR:  Unable to perform SSL \
+ initialization:  %s
+SEVERE_ERR_LDAP_CONN_CANNOT_PARSE_SASL_OPTION=ERROR:  The provided SASL \
+ option string "%s" could not be parsed in the form "name=value"
+SEVERE_ERR_LDAP_CONN_NO_SASL_MECHANISM=ERROR:  One or more SASL options \
+ were provided, but none of them were the "mech" option to specify which SASL \
+ mechanism should be used
+SEVERE_ERR_LDAP_CONN_CANNOT_DETERMINE_PORT=ERROR:  Cannot parse the value \
+ of the %s argument as an integer value between 1 and 65535:  %s
+SEVERE_ERR_LDAP_CONN_CANNOT_CONNECT=ERROR:  Cannot establish a connection \
+ to the Directory Server %s.  Verify that the server is running and that \
+ the provided credentials are valid.  Details:  %s
+INFO_LDAP_CONN_DESCRIPTION_HOST=Directory server hostname or IP address
+INFO_LDAP_CONN_DESCRIPTION_PORT=Directory server port number
+INFO_LDAP_CONN_DESCRIPTION_USESSL=Use SSL for secure communication with \
+ the server
+INFO_LDAP_CONN_DESCRIPTION_USESTARTTLS=Use StartTLS for secure \
+ communication with the server
+INFO_LDAP_CONN_DESCRIPTION_BINDDN=DN to use to bind to the server
+INFO_LDAP_CONN_DESCRIPTION_BINDPW=Password to use to bind to the server
+INFO_LDAP_CONN_DESCRIPTION_BINDPWFILE=Bind password file
+INFO_LDAP_CONN_DESCRIPTION_SASLOPTIONS=SASL bind options
+INFO_LDAP_CONN_DESCRIPTION_TRUST_ALL=Trust all server SSL certificates
+INFO_LDAP_CONN_DESCRIPTION_KSFILE=Certificate key store path
+INFO_LDAP_CONN_DESCRIPTION_KSPW=Certificate key store PIN
+INFO_LDAP_CONN_DESCRIPTION_KSPWFILE=Certificate key store PIN file
+INFO_LDAP_CONN_DESCRIPTION_TSFILE=Certificate trust store path
+INFO_LDAP_CONN_DESCRIPTION_TSPW=Certificate trust store PIN
+INFO_LDAP_CONN_DESCRIPTION_TSPWFILE=Certificate trust store PIN file
+SEVERE_ERR_TASK_CLIENT_UNEXPECTED_CONNECTION_CLOSURE=NOTICE:  The \
+ connection to the Directory Server was closed while waiting for a response to \
+ the shutdown request.  This likely means that the server has started the \
+ shutdown process
+SEVERE_ERR_TASK_TOOL_IO_ERROR=ERROR:  An I/O error occurred while \
+ attempting to communicate with the Directory Server:  %s
+SEVERE_ERR_TASK_TOOL_DECODE_ERROR=ERROR:  An error occurred while \
+ trying to decode the response from the server:  %s
+SEVERE_ERR_TASK_CLIENT_INVALID_RESPONSE_TYPE=ERROR:  Expected an add \
+ response message but got a %s message instead
+INFO_TASK_TOOL_TASK_SCHEDULED_NOW=%s task %s scheduled to start \
+  immediately
+SEVERE_ERR_LDAP_CONN_INCOMPATIBLE_ARGS=ERROR:  argument %s is \
+ incompatible with use of this tool to interact with the directory as a client
+SEVERE_ERR_CREATERC_ONLY_RUNS_ON_UNIX=This tool may only be used on \
+ UNIX-based systems
+INFO_CREATERC_TOOL_DESCRIPTION=Create an RC script that may be used to \
+ start, stop, and restart the Directory Server on UNIX-based systems
+INFO_CREATERC_OUTFILE_DESCRIPTION=The path to the output file to create
+SEVERE_ERR_CREATERC_UNABLE_TO_DETERMINE_SERVER_ROOT=Unable to determine \
+ the path to the server root directory.  Please ensure that the %s system \
+ property or the %s environment variable is set to the path of the server \
+ root directory
+SEVERE_ERR_CREATERC_CANNOT_WRITE=An error occurred while attempting to \
+ generate the RC script:  %s
+SEVERE_ERR_DSCFG_ERROR_QUIET_AND_INTERACTIVE_INCOMPATIBLE=If you specify \
+ the {%s} argument you must also specify {%s}
+INFO_DESCRIPTION_DBTEST_TOOL=This utility can be used to debug the JE \
+  database
+INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_ROOT_CONTAINERS=List the root \
+  containers used by all JE backends
+INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_ENTRY_CONTAINERS=List the entry \
+  containers for a root container
+INFO_DESCRIPTION_DBTEST_SUBCMD_DUMP_DATABASE_CONTAINER=Dump records from \
+  a database container
+INFO_DESCRIPTION_DBTEST_BACKEND_ID=The backend ID of the JE backend to \
+  debug
+INFO_DESCRIPTION_DBTEST_BASE_DN=The base DN of the entry container to debug
+INFO_DESCRIPTION_DBTEST_DATABASE_NAME=The name of the database container \
+  to debug
+INFO_DESCRIPTION_DBTEST_SKIP_DECODE=Do not try to decode the JE data to \
+  their appropriate types
+MILD_ERR_DBTEST_DECODE_FAIL=An error occurred while decoding data: %s
+INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_INDEX_STATUS=List the status of \
+  indexes in an entry container
+INFO_DESCRIPTION_DBTEST_MAX_KEY_VALUE=Only show records with keys that \
+  should be ordered before the provided value using the comparator for the \
+  database container
+INFO_DESCRIPTION_DBTEST_MIN_KEY_VALUE=Only show records with keys that \
+  should be ordered after the provided value using the comparator for the \
+  database container
+INFO_DESCRIPTION_DBTEST_MAX_DATA_SIZE=Only show records whose data is no \
+  larger than the provided value
+INFO_DESCRIPTION_DBTEST_MIN_DATA_SIZE=Only show records whose data is no \
+  smaller than the provided value
+INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_DATABASE_CONTAINERS=List the database \
+  containers for an entry container
+INFO_LABEL_DBTEST_BACKEND_ID=Backend ID
+INFO_LABEL_DBTEST_DB_DIRECTORY=Database Directory
+INFO_LABEL_DBTEST_BASE_DN=Base DN
+INFO_LABEL_DBTEST_JE_DATABASE_PREFIX=JE Database Prefix
+INFO_LABEL_DBTEST_ENTRY_COUNT=Entry Count
+SEVERE_ERR_DBTEST_NO_BACKENDS_FOR_ID=None of the Directory Server \
+  backends are configured with the requested backend ID %s
+SEVERE_ERR_DBTEST_NO_ENTRY_CONTAINERS_FOR_BASE_DN=None of the entry \
+  containers are configured with the requested base DN %s in backend %s
+SEVERE_ERR_DBTEST_NO_DATABASE_CONTAINERS_FOR_NAME=No database container \
+  exists with the requested name %s in entry container %s and backend %s
+SEVERE_ERR_DBTEST_ERROR_INITIALIZING_BACKEND=An unexpected error occurred \
+  while attempting to initialize the JE backend %s: %s
+SEVERE_ERR_DBTEST_ERROR_READING_DATABASE=An unexpected error occurred \
+  while attempting to read and/or decode records from the database: %s
+SEVERE_ERR_DBTEST_DECODE_BASE_DN=Unable to decode base DN string "%s" as \
+  a valid distinguished name:  %s
+INFO_LABEL_DBTEST_DATABASE_NAME=Database Name
+INFO_LABEL_DBTEST_DATABASE_TYPE=Database Type
+INFO_LABEL_DBTEST_JE_DATABASE_NAME=JE Database Name
+INFO_LABEL_DBTEST_JE_RECORD_COUNT=Record Count
+INFO_LABEL_DBTEST_INDEX_NAME=Index Name
+INFO_LABEL_DBTEST_INDEX_TYPE=Index Type
+INFO_LABEL_DBTEST_INDEX_STATUS=Index Status
+INFO_LABEL_DBTEST_KEY=Key
+INFO_LABEL_DBTEST_DATA=Data
+SEVERE_WARN_DBTEST_CANNOT_UNLOCK_BACKEND=An error occurred while \
+ attempting to release the shared lock for backend %s:  %s.  This lock should \
+ automatically be cleared when the process exits, so no further action \
+ should be required
+SEVERE_ERR_DBTEST_CANNOT_LOCK_BACKEND=An error occurred while \
+ attempting to acquire a shared lock for backend %s:  %s.  This generally \
+ means that some other process has exclusive access to this backend (e.g., a \
+ restore or an LDIF import)
+SEVERE_ERR_DBTEST_CANNOT_DECODE_KEY=An error occurred while decoding the \
+  min/max key value %s: %s. Values prefixed with "0x" will be decoded as raw \
+  bytes in hex. When dumping the DN2ID database, the value must be a valid \
+  distinguished name. When dumping the ID2Entry database, the value will be \
+  decoded as a entry ID. When dumping all other databases, the value will be \
+  decoded as a string
+INFO_LABEL_DBTEST_ENTRY=Entry
+INFO_LABEL_DBTEST_ENTRY_ID=Entry ID
+INFO_LABEL_DBTEST_ENTRY_DN=Entry DN
+INFO_LABEL_DBTEST_URI=URI
+INFO_LABEL_DBTEST_INDEX_VALUE=Indexed Value
+INFO_LABEL_DBTEST_INDEX_ENTRY_ID_LIST=Entry ID List
+INFO_LABEL_DBTEST_VLV_INDEX_LAST_SORT_KEYS=Last Sort Keys
+SEVERE_ERR_DBTEST_CANNOT_DECODE_SIZE=An error occurred while parsing the \
+  min/max data size %s as a integer: %s
+SEVERE_ERR_CONFIGDS_CANNOT_ENABLE_ADS_TRUST_STORE=An error occurred while \
+ attempting to enable the ADS trust store: %s
+SEVERE_ERR_DBTEST_MISSING_SUBCOMMAND=A sub-command must be specified
+INFO_CREATERC_USER_DESCRIPTION=The name of the user account under which \
+ the server should run
+INFO_CREATERC_JAVA_HOME_DESCRIPTION=The path to the Java installation \
+ that should be used to run the server
+INFO_CREATERC_JAVA_ARGS_DESCRIPTION=A set of arguments that should be \
+ passed to the JVM when running the server
+SEVERE_ERR_CREATERC_JAVA_HOME_DOESNT_EXIST=The directory %s specified \
+ as the OPENDS_JAVA_HOME path does not exist or is not a directory
+INFO_INSTALLDS_STATUS_COMMAND_LINE=To see basic server configuration \
+status and configuration you can launch %s
+INFO_INSTALLDS_PROMPT_ENABLE_SSL=Do you want to enable SSL?
+INFO_INSTALLDS_PROMPT_LDAPSPORT=On which port would you like the \
+ Directory Server to accept connections from LDAPS clients?
+INFO_INSTALLDS_ENABLE_STARTTLS=Do you want to enable Start TLS?
+INFO_INSTALLDS_PROMPT_JKS_PATH=Java Key Store (JKS) path:
+INFO_INSTALLDS_PROMPT_PKCS12_PATH=PKCS#12 key Store path:
+INFO_INSTALLDS_PROMPT_KEYSTORE_PASSWORD=Key store PIN:
+INFO_INSTALLDS_PROMPT_CERTNICKNAME=Use nickname %s?
+INFO_INSTALLDS_HEADER_CERT_TYPE=Certificate server options:
+INFO_INSTALLDS_CERT_OPTION_SELF_SIGNED=Generate self-signed certificate \
+ (recommended for testing purposes only)
+INFO_INSTALLDS_CERT_OPTION_JKS=Use an existing certificate located on a \
+ Java Key Store (JKS)
+INFO_INSTALLDS_CERT_OPTION_PKCS12=Use an existing certificate located on \
+ a PKCS#12 key store
+INFO_INSTALLDS_CERT_OPTION_PKCS11=Use an existing certificate on a \
+ PKCS#11 token
+INFO_INSTALLDS_PROMPT_CERT_TYPE_CHOICE=Certificate type selection:
+INFO_INSTALLDS_PROMPT_START_SERVER=Do you want to start the server when \
+ the configuration is completed?
+SEVERE_ERR_INSTALLDS_CERTNICKNAME_NOT_FOUND=The provided certificate \
+ nickname could not be found.  The key store contains the following \
+ certificate nicknames: %s
+SEVERE_ERR_INSTALLDS_MUST_PROVIDE_CERTNICKNAME=The key store contains the \
+ following certificate nicknames: %s.%nYou have to provide the nickname of the \
+ certificate you want to use
+INFO_INSTALLDS_DESCRIPTION_DO_NOT_START=Do not start the server when the \
+ configuration is completed
+INFO_INSTALLDS_DESCRIPTION_ENABLE_STARTTLS=Enable StartTLS to allow \
+ secure communication with the server using the LDAP port
+INFO_INSTALLDS_DESCRIPTION_LDAPSPORT=Port on which the \
+ Directory Server should listen for LDAPS communication.  The LDAPS port will \
+ be configured and SSL will be enabled only if this argument is explicitly \
+ specified
+INFO_INSTALLDS_DESCRIPTION_USE_SELF_SIGNED=Generate a \
+ self-signed certificate that the server should use when accepting SSL-based \
+ connections or performing StartTLS negotiation
+INFO_INSTALLDS_DESCRIPTION_USE_PKCS11=Use a certificate in a \
+ PKCS#11 token that the server should use when accepting SSL-based \
+ connections or performing StartTLS negotiation
+INFO_INSTALLDS_DESCRIPTION_USE_JAVAKEYSTORE=Path of a Java \
+ Key Store (JKS) containing a certificate to be used as the server certificate
+INFO_INSTALLDS_DESCRIPTION_USE_PKCS12=Path of a PKCS#12 key \
+ store containing the certificate that the server should use when accepting \
+ SSL-based connections or performing StartTLS negotiation
+INFO_INSTALLDS_DESCRIPTION_KEYSTOREPASSWORD=Certificate key store PIN.  \
+ A PIN is required when you specify to use an existing certificate (JKS, \
+ JCEKS, PKCS#12 or PKCS#11) as server certificate
+INFO_INSTALLDS_DESCRIPTION_KEYSTOREPASSWORD_FILE=Certificate key store \
+ PIN file.  A PIN is required when you specify to use an existing certificate \
+ (JKS, JCEKS, PKCS#12 or PKCS#11) as server certificate
+INFO_INSTALLDS_DESCRIPTION_CERT_NICKNAME=Nickname of the \
+ certificate that the server should use when accepting SSL-based \
+ connections or performing StartTLS negotiation
+SEVERE_ERR_INSTALLDS_SEVERAL_CERTIFICATE_TYPE_SPECIFIED=You have \
+ specified several certificate types to be used.  Only one certificate type \
+ (self-signed, JKS, JCEKS, PKCS#12 or PCKS#11) is allowed
+SEVERE_ERR_INSTALLDS_CERTIFICATE_REQUIRED_FOR_SSL_OR_STARTTLS=You have \
+ chosen to enable SSL or StartTLS.  You must specify which type of certificate \
+ you want the server to use
+SEVERE_ERR_INSTALLDS_NO_KEYSTORE_PASSWORD=You must provide the PIN of the \
+ keystore to retrieve the certificate to be used by the server.  You can use \
+ {%s} or {%s}
+INFO_INSTALLDS_DESCRIPTION_NO_PROMPT=Perform an installation in \
+ non-interactive mode.  If some data in the command is missing the user will \
+ not be prompted and the tool will fail
+SEVERE_ERR_INSTALLDS_SSL_OR_STARTTLS_REQUIRED=You have specified to use a \
+ certificate as server certificate.  You must enable SSL (using option {%s}) \
+ or Start TLS (using option %s)
+SEVERE_ERR_UPGRADE_INCOMPATIBLE_ARGS=The argument '%s' is incompatible \
+ with '%s'
+INFO_TASKINFO_TOOL_DESCRIPTION=This utility can be used to obtain a list \
+ of tasks scheduled to run within the Directory Server as well as information \
+ about individual tasks
+INFO_TASKINFO_SUMMARY_ARG_DESCRIPTION=Print a summary of tasks
+INFO_TASKINFO_TASK_ARG_DESCRIPTION=ID of a particular task \
+ about which this tool will display information
+INFO_TASKINFO_CMD_REFRESH=refresh
+INFO_TASKINFO_CMD_CANCEL=cancel task
+INFO_TASKINFO_CMD_VIEW_LOGS=view logs
+INFO_TASKINFO_MENU_PROMPT=Enter a menu item or task number
+INFO_TASKINFO_CMD_CANCEL_NUMBER_PROMPT=Enter the number of a task to \
+  cancel [%d]
+INFO_TASKINFO_MENU=Menu
+MILD_ERR_TASKINFO_INVALID_TASK_NUMBER=Task number must be between 1 and \
+  %d
+MILD_ERR_TASKINFO_INVALID_MENU_KEY=Invalid menu item or task number '%s'
+INFO_TASKINFO_FIELD_ID=ID
+INFO_TASKINFO_FIELD_TYPE=Type
+INFO_TASKINFO_FIELD_STATUS=Status
+INFO_TASKINFO_FIELD_SCHEDULED_START=Scheduled Start Time
+INFO_TASKINFO_FIELD_ACTUAL_START=Actual Start Time
+INFO_TASKINFO_FIELD_COMPLETION_TIME=Completion Time
+INFO_TASKINFO_FIELD_DEPENDENCY=Dependencies
+INFO_TASKINFO_FIELD_FAILED_DEPENDENCY_ACTION=Failed Dependency Action
+INFO_TASKINFO_FIELD_LOG=Log Message(s)
+INFO_TASKINFO_FIELD_LAST_LOG=Last Log Message
+INFO_TASKINFO_FIELD_NOTIFY_ON_COMPLETION=Email Upon Completion
+INFO_TASKINFO_FIELD_NOTIFY_ON_ERROR=Email Upon Error
+INFO_TASKINFO_CMD_CANCEL_SUCCESS=Task %s canceled
+SEVERE_ERR_TASKINFO_CMD_CANCEL_ERROR=Error canceling task %s:  %s
+SEVERE_ERR_TASKINFO_RETRIEVING_TASK_ENTRY=Error retrieving task entry \
+  %s:  %s
+MILD_ERR_TASKINFO_UNKNOWN_TASK_ENTRY=There are no tasks with ID %s
+INFO_TASKINFO_DETAILS=Task Details
+INFO_TASKINFO_OPTIONS=%s Options
+INFO_TASKINFO_NO_TASKS=No tasks exist
+INFO_TASKINFO_NONE=None
+INFO_TASKINFO_NONE_SPECIFIED=None Specified
+INFO_TASKINFO_IMMEDIATE_EXECUTION=Immediate execution
+INFO_TASKINFO_LDAP_EXCEPTION=Error connecting to the directory server: \
+  '%s'. Verify that the connection options are correct and that the server is \
+  running
+SEVERE_ERR_INCOMPATIBLE_ARGUMENTS=Options '%s' and '%s' are incompatible \
+  with each other and cannot be used together
+INFO_TASKINFO_TASK_ARG_CANCEL=ID of a particular task to cancel
+SEVERE_ERR_TASKINFO_CANCELING_TASK=Error canceling task '%s': %s
+SEVERE_ERR_TASKINFO_ACCESSING_LOGS=Error accessing logs for task '%s': %s
+SEVERE_ERR_TASKINFO_NOT_CANCELABLE_TASK_INDEX=Task at index %d is not \
+  cancelable
+SEVERE_ERR_TASKINFO_NOT_CANCELABLE_TASK=Task %s has finished and cannot \
+  be canceled
+INFO_TASKINFO_NO_CANCELABLE_TASKS=There are currently no cancelable tasks
+SEVERE_ERR_TASK_CLIENT_UNKNOWN_TASK=There are no tasks defined with ID '%s'
+SEVERE_ERR_TASK_CLIENT_UNCANCELABLE_TASK=Task '%s' has finished and \
+  cannot be canceled
+SEVERE_ERR_TASK_CLIENT_TASK_STATE_UNKNOWN=State for task '%s' cannot be \
+  determined
+INFO_DESCRIPTION_START_DATETIME=Indicates the date/time at which this \
+  operation will start when scheduled as a server task expressed in format \
+  'YYYYMMDDhhmmss'.  A value of '0' will cause the task to be scheduled for \
+  immediate execution.  When this option is specified the operation will be \
+  scheduled to start at the specified time after which this utility will exit \
+  immediately
+SEVERE_ERR_START_DATETIME_FORMAT=The start date/time must in format \
+  'YYYYMMDDhhmmss'
+INFO_TASK_TOOL_TASK_SCHEDULED_FUTURE=%s task %s scheduled to start %s
+SEVERE_ERR_TASK_TOOL_START_TIME_NO_LDAP=You have provided options for \
+  scheduling this operation as a task but options provided for connecting to \
+  the server's tasks backend resulted in the following error: '%s'
+INFO_DESCRIPTION_PROP_FILE_PATH=Path to the file containing default \
+  property values used for command line arguments
+INFO_DESCRIPTION_NO_PROP_FILE=No properties file will be \
+  used to get default command line argument values
+INFO_DESCRIPTION_TASK_TASK_ARGS=Task Scheduling Options
+INFO_DESCRIPTION_TASK_LDAP_ARGS=Task Backend Connection Options
+INFO_DESCRIPTION_GENERAL_ARGS=General Options
+INFO_DESCRIPTION_IO_ARGS=Utility Input/Output Options
+INFO_DESCRIPTION_LDAP_CONNECTION_ARGS=LDAP Connection Options
+INFO_DESCRIPTION_CONFIG_OPTIONS_ARGS=Configuration Options
+INFO_DESCRIPTION_TASK_COMPLETION_NOTIFICATION=Email address \
+  of a recipient to be notified when the task completes.  This option may be \
+  specified more than once
+INFO_DESCRIPTION_TASK_ERROR_NOTIFICATION=Email address \
+  of a recipient to be notified if an error occurs when this task executes.  \
+  This option may be specified more than once
+INFO_DESCRIPTION_TASK_DEPENDENCY_ID=ID of a task upon which \
+  this task depends.  A task will not start execution until all its \
+  dependencies have completed execution
+INFO_DESCRIPTION_TASK_FAILED_DEPENDENCY_ACTION=Action this task will \
+  take should one if its dependent tasks fail.  The value must be one of %s.  \
+  If not specified defaults to %s
+SEVERE_ERR_TASKTOOL_OPTIONS_FOR_TASK_ONLY=The option %s is only \
+  applicable when scheduling this operation as a task
+SEVERE_ERR_TASKTOOL_INVALID_EMAIL_ADDRESS=The value %s for option %s is \
+  not a valid email address
+SEVERE_ERR_TASKTOOL_INVALID_FDA=The failed dependency action value %s is \
+  invalid.  The value must be one of %s
+SEVERE_ERR_TASKTOOL_FDA_WITH_NO_DEPENDENCY=The failed dependency action \
+  option is to be used in conjunction with one or more dependencies
+SEVERE_ERR_TASKINFO_TASK_NOT_CANCELABLE_TASK=Error:  task %s is not in a \
+  cancelable state
+NOTICE_BACKUPDB_CANCELLED=The backup process was cancelled
+INFO_INSTALLDS_DESCRIPTION_REJECTED_FILE=Write rejected entries to the \
+ specified file
+MILD_ERR_INSTALLDS_CANNOT_WRITE_REJECTED=Cannot write to rejected entries \
+ file %s.  Verify that you have enough write rights on the file
+INFO_INSTALLDS_PROMPT_REJECTED_FILE=Write rejected entries to file:
+INFO_INSTALLDS_DESCRIPTION_SKIPPED_FILE=Write skipped entries to the \
+ specified file
+MILD_ERR_INSTALLDS_CANNOT_WRITE_SKIPPED=Cannot write to skipped entries \
+ file %s.  Verify that you have enough write rights on the file
+INFO_INSTALLDS_PROMPT_SKIPPED_FILE=Write skipped entries to file:
+SEVERE_ERR_INSTALLDS_TOO_MANY_KEYSTORE_PASSWORD_TRIES=The maximum number \
+ of tries to provide the certificate key store PIN is %s.  Install canceled
+INFO_JAVAPROPERTIES_TOOL_DESCRIPTION=This utility can be used to change \
+ the java arguments and java home that are used by the different server \
+ commands.%n%nBefore launching the command, edit the properties file located \
+ in %s to specify the java arguments and java home. When you have edited the \
+ properties file, run this command for the changes to be taken into account.\
+ %n%nNote that the changes will only apply to this server installation. No \
+ modifications will be made to your environment variables
+INFO_JAVAPROPERTIES_DESCRIPTION_SILENT=Run the tool in quiet mode.  Quiet \
+ mode will not output progress information to standard output
+INFO_JAVAPROPERTIES_DESCRIPTION_PROPERTIES_FILE=The properties file to \
+ be used to generate the scripts.  If this attribute is not specified %s will \
+ be used
+INFO_JAVAPROPERTIES_DESCRIPTION_DESTINATION_FILE=The script file that \
+ will be written.  If not specified %s will be written
+INFO_JAVAPROPERTIES_DESCRIPTION_HELP=Display this usage information
+SEVERE_ERR_JAVAPROPERTIES_WITH_PROPERTIES_FILE=The file properties "%s" \
+ cannot be read.  Check that it exists and that you have read rights to it
+SEVERE_ERR_JAVAPROPERTIES_WITH_DESTINATION_FILE=The destination file "%s" \
+ cannot be written.  Check that you have right reads to it
+SEVERE_ERR_JAVAPROPERTIES_WRITING_DESTINATION_FILE=The destination file \
+ "%s" cannot be written.  Check that you have right reads to it
+INFO_JAVAPROPERTIES_SUCCESSFUL_NON_DEFAULT=The script file %s was \
+ successfully created.  For the command-lines to use the java properties \
+ specified on %s you must copy the created script file to %s
+INFO_JAVAPROPERTIES_SUCCESSFUL=The operation was successful.  The server \
+ commands will use the java arguments and java home specified in the \
+ properties file located in %s
+INFO_DESCRIPTION_TEST_IF_OFFLINE=When this is set test if the command \
+ must be run in offline or online mode, returning the appropriate error code
+SEVERE_ERR_BACKUPDB_REPEATED_BACKEND_ID=The backend ID '%s' has been \
+ specified several times
+MILD_ERR_INSTALLDS_EMPTY_DN_RESPONSE=ERROR:  The empty LDAP DN is not \
+ a valid value
+INFO_FILE_PLACEHOLDER={file}
+INFO_DIRECTORY_PLACEHOLDER={directory}
+INFO_CONFIGFILE_PLACEHOLDER={configFile}
+INFO_LDIFFILE_PLACEHOLDER={ldifFile}
+INFO_SEED_PLACEHOLDER={seed}
+INFO_KEYSTOREPATH_PLACEHOLDER={keyStorePath}
+INFO_TRUSTSTOREPATH_PLACEHOLDER={trustStorePath}
+INFO_BINDPWD_FILE_PLACEHOLDER={bindPasswordFile}
+INFO_CONFIGCLASS_PLACEHOLDER={configClass}
+INFO_HOST_PLACEHOLDER={host}
+INFO_PORT_PLACEHOLDER={port}
+INFO_BASEDN_PLACEHOLDER={baseDN}
+INFO_ROOT_USER_DN_PLACEHOLDER={rootUserDN}
+INFO_BINDDN_PLACEHOLDER={bindDN}
+INFO_BINDPWD_PLACEHOLDER={bindPassword}
+INFO_KEYSTORE_PWD_PLACEHOLDER={keyStorePassword}
+INFO_PATH_PLACEHOLDER={path}
+INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER={path}
+INFO_TRUSTSTORE_PWD_PLACEHOLDER={trustStorePassword}
+INFO_NICKNAME_PLACEHOLDER={nickname}
+INFO_ASSERTION_FILTER_PLACEHOLDER={filter}
+INFO_FILTER_PLACEHOLDER={filter}
+INFO_PROXYAUTHID_PLACEHOLDER={authzID}
+INFO_SASL_OPTION_PLACEHOLDER={name=value}
+INFO_PROTOCOL_VERSION_PLACEHOLDER={version}
+INFO_DESCRIPTION_PLACEHOLDER={description}
+INFO_GROUPNAME_PLACEHOLDER={groupName}
+INFO_MEMBERNAME_PLACEHOLDER={memberName}
+INFO_BACKENDNAME_PLACEHOLDER={backendName}
+INFO_SERVERID_PLACEHOLDER={serverID}
+INFO_USERID_PLACEHOLDER={userID}
+INFO_VALUE_SET_PLACEHOLDER={PROP:VALUE}
+INFO_START_DATETIME_PLACEHOLDER={startTime}
+INFO_PROP_FILE_PATH_PLACEHOLDER={propertiesFilePath}
+INFO_EMAIL_ADDRESS_PLACEHOLDER={emailAddress}
+INFO_TASK_ID_PLACEHOLDER={taskID}
+INFO_ACTION_PLACEHOLDER={action}
+INFO_TYPE_PLACEHOLDER={type}
+INFO_CATEGORY_PLACEHOLDER={category}
+INFO_PROPERTY_PLACEHOLDER={property}
+INFO_NAME_PLACEHOLDER={name}
+INFO_UNIT_PLACEHOLDER={unit}
+INFO_BACKUPID_PLACEHOLDER={backupID}
+INFO_BACKUPDIR_PLACEHOLDER={backupDir}
+INFO_LDAPPORT_PLACEHOLDER={ldapPort}
+INFO_JMXPORT_PLACEHOLDER={jmxPort}
+INFO_KEY_MANAGER_PROVIDER_DN_PLACEHOLDER={keyManagerProviderDN}
+INFO_TRUST_MANAGER_PROVIDER_DN_PLACEHOLDER={trustManagerProviderDN}
+INFO_KEY_MANAGER_PATH_PLACEHOLDER={keyManagerPath}
+INFO_ROOT_USER_PWD_PLACEHOLDER={rootUserPassword}
+INFO_SERVER_ROOT_DIR_PLACEHOLDER={serverRootDir}
+INFO_SERVICE_NAME_PLACEHOLDER={serviceName}
+INFO_USER_NAME_PLACEHOLDER={userName}
+INFO_ARGS_PLACEHOLDER={args}
+INFO_DATABASE_NAME_PLACEHOLDER={databaseName}
+INFO_MAX_KEY_VALUE_PLACEHOLDER={maxKeyValue}
+INFO_MIN_KEY_VALUE_PLACEHOLDER={minKeyValue}
+INFO_MAX_DATA_SIZE_PLACEHOLDER={maxDataSize}
+INFO_MIN_DATA_SIZE_PLACEHOLDER={minDataSize}
+INFO_CLEAR_PWD={clearPW}
+INFO_ENCODED_PWD_PLACEHOLDER={encodedPW}
+INFO_STORAGE_SCHEME_PLACEHOLDER={scheme}
+INFO_BRANCH_DN_PLACEHOLDER={branchDN}
+INFO_ATTRIBUTE_PLACEHOLDER={attribute}
+INFO_WRAP_COLUMN_PLACEHOLDER={wrapColumn}
+INFO_TEMPLATE_FILE_PLACEHOLDER={templateFile}
+INFO_REJECT_FILE_PLACEHOLDER={rejectFile}
+INFO_SKIP_FILE_PLACEHOLDER={skipFile}
+INFO_PROGRAM_NAME_PLACEHOLDER={programName}
+INFO_NUM_ENTRIES_PLACEHOLDER={numEntries}
+INFO_ROOT_USER_PWD_FILE_PLACEHOLDER={rootUserPasswordFile}
+INFO_LDAP_CONTROL_PLACEHOLDER={controloid[:criticality[:value|::b64value|:<filePath]]}
+INFO_ENCODING_PLACEHOLDER={encoding}
+INFO_ATTRIBUTE_LIST_PLACEHOLDER={attrList}
+INFO_NEW_PASSWORD_PLACEHOLDER={newPassword}
+INFO_CURRENT_PASSWORD_PLACEHOLDER={currentPassword}
+INFO_SEARCH_SCOPE_PLACEHOLDER={searchScope}
+INFO_SORT_ORDER_PLACEHOLDER={sortOrder}
+INFO_VLV_PLACEHOLDER={before:after:index:count | before:after:value}
+INFO_DEREFERENCE_POLICE_PLACEHOLDER={dereferencePolicy}
+INFO_SIZE_LIMIT_PLACEHOLDER={sizeLimit}
+INFO_TIME_LIMIT_PLACEHOLDER={timeLimit}
+INFO_SCOPE_PLACEHOLDER={scope}
+INFO_FILTER_FILE_PLACEHOLDER={filterFile}
+INFO_OUTPUT_FILE_PLACEHOLDER={outputFile}
+INFO_TARGETDN_PLACEHOLDER={targetDN}
+INFO_TIME_PLACEHOLDER={time}
+INFO_TRUE_FALSE_PLACEHOLDER={true|false}
+INFO_INDEX_PLACEHOLDER={index}
+INFO_STOP_REASON_PLACEHOLDER={stopReason}
+INFO_STOP_TIME_PLACEHOLDER={stopTime}
+INFO_SECONDS_PLACEHOLDER={seconds}
+INFO_DATA_PLACEHOLDER={data}
+INFO_ADDRESS_PLACEHOLDER={address}
+INFO_SUBJECT_PLACEHOLDER={subject}
+INFO_ADMINUID_PLACEHOLDER={adminUID}
+INFO_KEYSTORE_PWD_FILE_PLACEHOLDER={keyStorePasswordFile}
+INFO_PSEARCH_PLACEHOLDER=ps[:changetype[:changesonly[:entrychgcontrols]]]
+INFO_MULTICHOICE_TRUE_VALUE=true
+INFO_MULTICHOICE_FALSE_VALUE=false
+INFO_INSTALLDS_SERVER_JMXPORT_LABEL=JMX Listener Port:
+INFO_INSTALLDS_START_SERVER=Start Server when the configuration is completed
+INFO_INSTALLDS_DO_NOT_START_SERVER=Do not start Server when the configuration \
+ is completed
+INFO_INSTALLDS_SUMMARY=Setup Summary%n=============
+INFO_INSTALLDS_CONFIRM_INSTALL_PROMPT=What would you like to do?
+INFO_INSTALLDS_CONFIRM_INSTALL=Setup the server with the parameters above
+INFO_INSTALLDS_PROVIDE_DATA_AGAIN=Provide the setup parameters again
+INFO_INSTALLDS_CANCEL=Cancel the setup
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_CRYPTO_MANAGER=An error occurred while \
+ attempting to update the crypto manager in the Directory Server: %s
+INFO_TASK_TOOL_TASK_SUCESSFULL=%s task %s has been successfully completed
+INFO_TASK_TOOL_TASK_NOT_SUCESSFULL=%s task %s did not complete \
+ successfully
+SEVERE_ERR_CANNOT_READ_TRUSTSTORE=Cannot access trust store '%s'.  Verify \
+ that the provided trust store exists and that you have read access rights to it
+SEVERE_ERR_CANNOT_READ_KEYSTORE=Cannot access key store '%s'.  Verify \
+ that the provided key store exists and that you have read access rights to it
+INFO_LDIFDIFF_DESCRIPTION_IGNORE_ATTRS=File containing a list of attributes \
+ to ignore when computing the difference
+INFO_LDIFDIFF_DESCRIPTION_IGNORE_ENTRIES=File containing a list of entries (DN) \
+ to ignore when computing the difference
+SEVERE_ERR_LDIFDIFF_CANNOT_READ_FILE_IGNORE_ENTRIES=An error occurred while attempting \
+ to read the file '%s' containing the list of ignored entries: %s
+SEVERE_ERR_LDIFDIFF_CANNOT_READ_FILE_IGNORE_ATTRIBS=An error occurred while attempting \
+ to read the file '%s' containing the list of ignored attributes: %s
+INFO_LDIFDIFF_CANNOT_PARSE_STRING_AS_DN=The string '%s' from file '%s' could \
+ not be parsed as a dn
+INFO_CHANGE_NUMBER_CONTROL_RESULT=The %s operation change number is %s
+INFO_INSTALLDS_PROMPT_ADMINCONNECTORPORT=On which port would you like the \
+ Administration Connector to accept connections?
+INFO_INSTALLDS_DESCRIPTION_ADMINCONNECTORPORT=Port on which the \
+ Administration Connector should listen for communication
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_ADMIN_CONNECTOR_PORT=An error occurred \
+ while attempting to update the administration connector port:  %s
+SEVERE_ERR_TASKINFO_LDAP_EXCEPTION_SSL=Error connecting to the directory server at %s on %s. \
+Check this port is an administration port
+INFO_DESCRIPTION_ADMIN_PORT=Directory server administration port number
+INFO_INSTALLDS_DESCRIPTION_USE_JCEKS=Path of a JCEKS containing a \
+ certificate to be used as the server certificate
+INFO_INSTALLDS_CERT_OPTION_JCEKS=Use an existing certificate located on a \
+ JCEKS key store
+INFO_INSTALLDS_PROMPT_JCEKS_PATH=JCEKS Key Store path:
+SEVERE_ERR_CONFIG_KEYMANAGER_CANNOT_CREATE_JCEKS_PROVIDER=Error creating \
+ JCEKS Key Provider configuration:  %s
+SEVERE_ERR_CONFIG_KEYMANAGER_CANNOT_CREATE_JCEKS_TRUST_MANAGER=Error \
+ creating JCEKS Trust Manager configuration:  %s
+SEVERE_ERR_STOPDS_CANNOT_CONNECT_SSL=ERROR:  Cannot establish a connection to \
+ the Directory Server at %s on port %s. Check this port is an administration port
+SEVERE_ERR_PWPSTATE_CANNOT_CONNECT_SSL=ERROR:  Cannot establish a connection to \
+ the Directory Server at %s on port %s. Check this port is an administration port
+INFO_IPATH_PLACEHOLDER={instancePath}
+INFO_CURRENT_USER_PLACEHOLDER={currentUser}
+INFO_CONFIGURE_DESCRIPTION_IPATH=Path where the instance will be located
+INFO_CONFIGURE_DESCRIPTION_USERNAME=User name of the owner of the instance
+INFO_CONFIGURE_DESCRIPTION_GROUPNAME=Group name of the owner of the instance
+INFO_CONFIGURE_USAGE_DESCRIPTION=This utility sets the instance location
+SEVERE_ERR_CONFIGURE_NOT_DIRECTORY=[%s] is not a directory. Only directories can \
+be used as {instancePath}
+SEVERE_ERR_CONFIGURE_DIRECTORY_NOT_EMPTY=[%s] is not empty. Only empty directories can \
+be used as {instancePath}
+SEVERE_ERR_CONFIGURE_DIRECTORY_NOT_WRITABLE=[%s] is not writable. Cannot create \
+Directory Server instance
+SEVERE_ERR_CONFIGURE_BAD_USER_NAME=[%s] does not start with a letter. \
+Cannot be specified as {userName}
+SEVERE_ERR_CONFIGURE_GET_GROUP_ERROR=Unable to retrieve group for [%s]. \
+Check that [%s] exists
+SEVERE_ERR_CONFIGURE_CHMOD_ERROR=Unable to use [%s]/[%s] as {userName}/{groupName}. \
+Check that %s exists and belongs to %s
+SEVERE_ERR_CONFIGURE_CURRENT_USER_ERROR=Unauthorized user. \
+Only user that can write [%s] can use this command
+INFO_CHECK_DESCRIPTION=This utility checks version and owner of the instance
+INFO_CHECK_DESCRIPTION_CURRENT_USER=Current user
+INFO_CHECK_DESCRIPTION_CHECK_VERSION=Specifies that check on version should be done
+SEVERE_ERR_CHECK_USER_ERROR=Current user is not owner of the instance. Only [%s] can run this command
+SEVERE_ERR_CHECK_VERSION_NOT_MATCH=Data version does not match binaries. Run upgrade script to solve this
+SEVERE_ERR_CONFIGURE_USER_NOT_EXIST=User [%s] does not exist
+SEVERE_ERR_CONFIGURE_LDAPUSER_NOT_EXIST=User/role [%s] does not exist. \
+Create it or use --userName option to specify another user
+SEVERE_ERR_BACKUPDB_CANNOT_BACKUP_IN_DIRECTORY=The target backend %s \
+ cannot be backed up to the backup directory %s: this directory is \
+ already a backup location for backend %s
+INFO_RECURRING_TASK_PLACEHOLDER={schedulePattern}
+SEVERE_ERR_ENCPW_CANNOT_INITIALIZE_SERVER_COMPONENTS=An error occurred \
+ while attempting to initialize server components to run the encode \
+ password tool:  %s
+SEVERE_ERR_LDIFIMPORT_COUNT_REJECTS_REQUIRES_OFFLINE=The %s \
+ argument is not supported for online imports
+INFO_DESCRIPTION_RECURRING_TASK=Indicates the task is recurring and will \
+ be scheduled according to the value argument expressed in crontab(5) \
+ compatible time/date pattern
+INFO_TASK_TOOL_RECURRING_TASK_SCHEDULED=Recurring %s task %s scheduled \
+ successfully
+INFO_UNCONFIGURE_USAGE_DESCRIPTION=This utility unsets the instance location
+INFO_DESCRIPTION_CHECK_OPTIONS=Checks options are valid
+FATAL_ERR_INTERNAL=Internal Error: %s
+FATAL_ERR_INSTALL_ROOT_NOT_SPECIFIED=INSTALL_ROOT property not specified
+FATAL_ERR_INSTANCE_ROOT_NOT_SPECIFIED=INSTANCE_ROOT property not specified
+FATAL_ERR_CONFIG_LDIF_NOT_FOUND=The "config.ldif" file is not present in \
+the instance directory %s.\nInstance directory is referenced by %s
+INFO_LDIFEXPORT_PATH_TO_LDIF_FILE=Exporting to %s
+INFO_PROMPT_YES_COMPLETE_ANSWER=yes
+INFO_PROMPT_YES_FIRST_LETTER_ANSWER=y
+INFO_PROMPT_NO_COMPLETE_ANSWER=no
+INFO_PROMPT_NO_FIRST_LETTER_ANSWER=n
+SEVERE_ERR_START_DATETIME_ALREADY_PASSED=The specified start time '%s' \
+ has already passed
+SEVERE_ERR_LDAPCOMPARE_ERROR_READING_FILE=An error occurred reading file \
+ '%s'.  Check that the file exists and that you have read access rights to \
+ it.  Details: %s
+SEVERE_ERR_STOPDS_DATETIME_ALREADY_PASSED=The specified stop time '%s' \
+ has already passed
+SEVERE_ERR_LDAPCOMPARE_FILENAME_AND_DNS=Both entry DNs and a file name \
+ were provided for the compare operation.  These arguments are not compatible
+INFO_TASKINFO_CMD_REFRESH_CHAR=r
+INFO_TASKINFO_CMD_CANCEL_CHAR=c
+INFO_TASKINFO_CMD_VIEW_LOGS_CHAR=l
+INFO_LDIFDIFF_DESCRIPTION_CHECK_SCHEMA=Takes into account the syntax of \
+ the attributes as defined in the schema to make the value comparison.  The \
+ provided LDIF files must be conform to the server schema
+SEVERE_WARN_LDIFDIFF_NO_CONFIG_FILE=WARNING:  no configuration file was \
+ provided as argument.  No schema check will be performed.  If this is being \
+ called throught the '%s' command-line, verify that the script has not been \
+ modified
+INFO_LDAPAUTH_NON_EMPTY_PASSWORD=You must provide a non-empty password \
+to continue
+INFO_BATCH_FILE_PATH_PLACEHOLDER={batchFilePath}
+INFO_DESCRIPTION_BATCH_FILE_PATH=Path to a batch file containing \
+a set of dsconfig commands to be executed
+SEVERE_ERR_DSCFG_ERROR_BATCH_FILE_AND_INTERACTIVE_INCOMPATIBLE=If you specify \
+ the {%s} argument you must also specify {%s}
+SEVERE_ERR_TIMEOUT_DURING_STARTUP=The timeout of '%d' seconds to start \
+ the server has been reached.  You can use the argument '--%s' to increase \
+ this timeout
+INFO_INSTALLDS_ENABLE_WINDOWS_SERVICE=Enable the server to run as a \
+ Windows Service
+INFO_INSTALLDS_DO_NOT_ENABLE_WINDOWS_SERVICE=Do not enable the server to \
+ run as a Windows Service
+INFO_ERROR_EMPTY_RESPONSE=ERROR: a response must be provided in order to continue
+SEVERE_ERR_ACCTUSABLEREQ_CONTROL_BAD_OID=Cannot decode the provided \
+ control as an account availability request control because it contained \
+ the OID '%s', when '%s' was expected
+SEVERE_ERR_ACCTUSABLERES_CONTROL_BAD_OID=Cannot decode the provided \
+ control as an account availability response control because it contained \
+ the OID '%s', when '%s' was expected
+SEVERE_ERR_LDAPASSERT_CONTROL_BAD_OID=Cannot decode the provided \
+ control as an assertion control because it contained \
+ the OID '%s', when '%s' was expected
+SEVERE_ERR_AUTHZIDREQ_CONTROL_BAD_OID=Cannot decode the provided \
+ control as an authorization identity request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_AUTHZIDRESP_CONTROL_BAD_OID=Cannot decode the provided \
+ control as an authorization identity response control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_ECN_CONTROL_BAD_OID=Cannot decode the provided \
+ control as an entry change notification response control because it \
+ contained the OID '%s', when '%s' was expected
+MILD_ERR_ECN_INVALID_PREVIOUS_DN=Cannot decode the provided entry change \
+ notification control because it contains an invalid previous DN: %s
+SEVERE_ERR_GETEFFECTIVERIGHTS_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a get effective rights request control because it \
+ contained the OID '%s', when '%s' was expected
+MILD_ERR_GETEFFECTIVERIGHTS_INVALID_AUTHZIDDN=Cannot decode the provided \
+ get effective rights request control because it contains an invalid \
+ authorization ID distinguished name: %s
+MILD_ERR_GETEFFECTIVERIGHTS_UNKNOWN_ATTRIBUTE=Cannot decode the provided \
+ get effective rights request control because it contained an unrecognized \
+ attribute type: %s
+SEVERE_ERR_MATCHEDVALUES_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a matched values request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_LDAP_PAGED_RESULTS_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a simple paged results control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_SUBTREE_DELETE_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a tree delete request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PWEXPIRED_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a Netscape password expired response control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PWEXPIRING_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a Netscape password expiring response control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PSEARCH_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a persistent search request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PSEARCH_BAD_CHANGE_TYPES=Cannot decode the provided \
+ control as a persistent search request control because it an \
+ invalid changeTypes field '%d', when a value between 0 and 15 was expected
+SEVERE_ERR_ECN_BAD_CHANGE_TYPE=Cannot decode the provided \
+ control as a entry change notification control because it an \
+ invalid changeTypes field '%d', when a value of 1, 2, 4, or 8 was expected
+SEVERE_ERR_POSTREAD_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a post-read control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PREREAD_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a pre-read control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PROXYAUTH1_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a proxy authorization v1 control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PROXYAUTH1_INVALID_AUTHZIDDN=Cannot decode the provided \
+ proxy authorization v1 control because it contains an invalid \
+ authorization distinguished name: %s
+SEVERE_ERR_PROXYAUTH2_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a proxy authorization v2 control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PROXYAUTH2_INVALID_AUTHZIDDN=Cannot decode the provided \
+ proxy authorization v2 control because it contains an invalid \
+ authorization distinguished name: %s
+SEVERE_ERR_PROXYAUTH2_INVALID_AUTHZID_TYPE=Cannot decode the provided \
+ proxy authorization v2 control because the control value '%s' does not \
+ begin with a valid authorization ID type 'dn:' or 'u:'
+SEVERE_ERR_SORT_KEY_DEFAULT_MRULE_NOT_FOUND=The sort key '%s' could not be \
+ decoded because the attribute description '%s' does not have a default \
+ ordering matching rule
+SEVERE_ERR_SORT_KEY_MRULE_NOT_FOUND=The sort key '%s' could not be decoded \
+ because the ordering matching rule '%s' was not found in the schema
+SEVERE_ERR_SORT_KEY_NO_ATTR_NAME=The sort key '%s' could not be decoded \
+ because it did not contain an attribute description
+SEVERE_ERR_SORT_KEY_NO_MATCHING_RULE=The sort key '%s' could not be decoded \
+ because it contained a colon but no ordering matching rule name
+SEVERE_ERR_SORT_KEY_NO_SORT_KEYS=The list of sort keys '%s' could not be \
+ decoded because it did not contain any sort keys
+SEVERE_ERR_SORTREQ_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a server side sort request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_SORTRES_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a server side sort response control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_VLVREQ_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a virtual list view request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_VLVRES_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a virtual list view response control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PWPOLICYREQ_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a password policy request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PWPOLICYRES_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a password policy response control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_MANAGEDSAIT_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a ManageDsaIT request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_MANAGEDSAIT_INVALID_CONTROL_VALUE=Cannot decode the provided \
+ ManageDsaIT control because it contains a value
+SEVERE_ERR_SUBENTRIES_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a sub-entries request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_SUBENTRIES_INVALID_CONTROL_VALUE=Cannot decode the provided \
+ sub-entries control because it contains a value
+SEVERE_ERR_DECODE_CONTROL_FAILURE=# %s
+SEVERE_ERR_WHOAMI_INVALID_AUTHZID_TYPE=The provided authorization ID '%s' \
+ does not begin with a valid authorization ID type 'dn:' or 'u:'
+SEVERE_ERR_PERMISSIVE_MODIFY_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a permissive modify request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_PERMISSIVE_MODIFY_INVALID_CONTROL_VALUE=Cannot decode the provided \
+ permissive modify control because it contains a value
+SEVERE_ERR_REAL_ATTRS_ONLY_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a real attributes only request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_REAL_ATTRS_ONLY_INVALID_CONTROL_VALUE=Cannot decode the provided \
+ real attributes only control because it contains a value
+SEVERE_ERR_VIRTUAL_ATTRS_ONLY_CONTROL_BAD_OID=Cannot decode the provided \
+ control as a virtual attributes only request control because it \
+ contained the OID '%s', when '%s' was expected
+SEVERE_ERR_VIRTUAL_ATTRS_ONLY_INVALID_CONTROL_VALUE=Cannot decode the provided \
+ virtual attributes only control because it contains a value
+WARN_CLIENT_DUPLICATE_MESSAGE_ID=The Directory Server is already processing \
+ another request on the same client connection with the same message ID of %d
+INFO_CANCELED_BY_ABANDON_REQUEST=The operation was canceled because the client \
+ issued an abandon request (message ID %d) for this operation
+INFO_CANCELED_BY_CANCEL_REQUEST=The operation was canceled because the client \
+ issued a cancel request (message ID %d) for this operation
+INFO_CANCELED_BY_CLIENT_DISCONNECT=The operation was canceled because the \
+ client disconnected
+INFO_CANCELED_BY_CLIENT_ERROR=The operation was canceled because the \
+ client connection failed
+INFO_SEARCHRATE_TOOL_DESCRIPTION=This utility can be used to measure \
+  search throughput and response time of a directory service using \
+  user-defined searches
+INFO_SEARCHRATE_TOOL_DESCRIPTION_BASEDN=Base DN format string.
+INFO_MODRATE_TOOL_DESCRIPTION=This utility can be used to measure \
+  modify throughput and response time of a directory service using \
+  user-defined modifications
+INFO_MODRATE_TOOL_DESCRIPTION_TARGETDN=Target entry DN format string
+INFO_AUTHRATE_TOOL_DESCRIPTION=This utility can be used to measure \
+  bind throughput and response time of a directory service using \
+  user-defined bind or search-then-bind operations. Format strings may be \
+  used in the bind DN option as well as the authid and authzid SASL bind \
+  options. A search operation may be used to retrieve the bind DN by \
+  specifying the base DN and a filter. The retrieved entry DN will be appended \
+  as the last argument in the argument list when evaluating format strings. \
+  For example, to measure simple bind performance using the retrieved user \
+  DN as the bind DN: authrate -D '%2$s' -p password -b "dc=example,dc=com" \
+  -g 'rand(0,10000)' '(user=user.%1$d)'
+
+
+
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_de.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_de.properties
new file mode 100755
index 0000000..11514dd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_de.properties
@@ -0,0 +1,531 @@
+# 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
+#
+#      Copyright 2009 Sun Microsystems, Inc.
+#
+# Global directives
+#
+global.ordinal=-1
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE_1=Unable to retrieve \
+### approximate matching rule %s used as the default for the %s attribute syntax. \
+### Approximate matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE_2=Unable to retrieve \
+### equality matching rule %s used as the default for the %s attribute syntax. \
+### Equality matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE_3=Unable to retrieve \
+### ordering matching rule %s used as the default for the %s attribute syntax. \
+### Ordering matches will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE_4=Unable to retrieve \
+### substring matching rule %s used as the default for the %s attribute syntax. \
+### Substring matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN_5=The provided value "%s" is not \
+### allowed for attributes with a Boolean syntax.  The only allowed values are \
+### 'TRUE' and 'FALSE'
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT_6=The provided value "%s" is too \
+### short to be a valid bit string.  A bit string must be a series of binary \
+### digits surrounded by single quotes and followed by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED_7=The provided value "%s" is not \
+### a valid bit string because it is not surrounded by single quotes and followed \
+### by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT_8=The provided value "%s" is \
+### not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=Der angegebene Wert "%s" ist keine g\u00fcltige L\u00e4nderzeichenkette, da die L\u00e4nge nicht exakt zwei Zeichen betr\u00e4gt
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE_10=Der angegebene Wert "%s" ist keine g\u00fcltige L\u00e4nderzeichenkette, da er ein oder mehrere nicht druckbare Zeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=Der angegebene Wert "%s" ist keine g\u00fcltige Liefermethode, da er keine Elemente enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT_12=Der angegebene Wert "%s" ist keine g\u00fcltige Liefermethode, da "%s" keine g\u00fcltige Methode ist
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT_13=The provided value "%s" \
+### is too short to be a valid generalized time value
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR_14=The provided value \
+### "%s" is not a valid generalized time value because the '%s' character is not \
+### allowed in the century or year specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH_15=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid month \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY_16=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid day \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR_17=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid hour \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE_18=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid minute \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND_19=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid second \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND_20=The provided \
+### value "%s" is not a valid generalized time value because the sub-second \
+### component is not valid (between 1 and 3 numeric digits)
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND_21=The provided value \
+### "%s" is not a valid generalized time value because the sub-second value may \
+### not contain more than three digits
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET_22=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+### offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR_23=The provided value \
+### "%s" is not a valid generalized time value because it contains an invalid \
+### character '%s' at position %d
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE_24=The provided value \
+### "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_25=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden: %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA_26=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das letzte nicht-Leerzeichen ein Komma oder Semikolon ist
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT_27=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da die numerische Ziffer '%s' als erstes Zeichen in einem Attributnamen unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR_28=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das Zeichen '%c' an Position '%d' in einem Attributnamen unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR_29=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das Unterstrich-Zeichen in einem Attributnamen unzul\u00e4ssig ist, au\u00dfer wenn die Konfigurationsoption %s aktiviert ist
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH_30=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das Bindestrich-Zeichen als erstes Zeichen in einem Attributnamen unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE_31=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das Unterstrich-Zeichen als erstes Zeichen in einem Attributnamen unzul\u00e4ssig ist, selbst wenn die Konfigurationsoption %s aktiviert ist
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT_32=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da die Ziffer '%c' nicht als erstes Zeichen in einem Attributnamen zul\u00e4ssig ist, au\u00dfer wenn der Name als OID festgelegt oder die Konfigurationsoption %s aktiviert ist
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME_33=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da er einen RDN mit leerem Attributnamen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD_34=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da der geparste Attributname %s einen Punkt enth\u00e4lt, der Name aber anscheinend kein g\u00fcltiger OID ist
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME_35=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das letzte nicht-Leerzeichen Teil des Attributnamens '%s' ist
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL_36=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das n\u00e4chste nicht-Leerzeichen nach dem Attributnamen "%s" ein Gleichheitszeichen sein m\u00fcsste, stattdessen aber '%c' ist
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR_37=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da das Zeichen '%c' an Position %d unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT_38=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da ein Attributwert zwar mit einem Rautezeichen (#) beginnt, diesem aber kein positives Vielfaches von zwei hexadezimalen Ziffern folgt
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT_39=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da ein Attributwert zwar mit einem Rautezeichen (#) beginnt, aber auch das Zeichen %c enth\u00e4lt, welches keine g\u00fcltige hexadezimale Ziffer darstellt
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE_40=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da ein unerwarteter Fehler beim Versuch aufgetreten ist, einen Attributwert von einem der RDN-Komponenten zu parsen: "%s"
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE_41=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da einer der RDN-Komponenten einen Wert mit Anf\u00fchrungszeichen enth\u00e4lt, bei dem das schlie\u00dfende Anf\u00fchrungszeichen fehlt
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID_42=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name (DN) geparst werden, da einer der RDN-Komponenten einen Wert mit einer vereinzelten hexadezimalen Ziffer enth\u00e4lt, auf die keine zweite hexadezimale Ziffer folgt
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO_43=The provided value "%s" could \
+### not be parsed as a valid integer because the first digit may not be zero \
+### unless it is the only digit
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH_44=The provided value "%s" \
+### could not be parsed as a valid integer because the dash may only appear if it \
+### is the first character of the value followed by one or more digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER_45=The provided value "%s" \
+### could not be parsed as a valid integer because character '%c' at position %d \
+### is not allowed in an integer value
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE_46=The provided value "%s" could \
+### not be parsed as a valid integer because it did not contain any digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE_47=The provided value "%s" \
+### could not be parsed as a valid integer because it contained only a dash not \
+### followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE_48=Der angegebene Wert kann nicht als g\u00fcltiger OID geparst werden, da er keine Zeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER_49=Der angegebene Wert "%s"kann nicht als g\u00fcltiger OID geparst werden, da er ein unzul\u00e4ssiges Zeichen an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS_50=Der angegebene Wert "%s" kann nicht als g\u00fcltiger OID geparst werden, da er zwei aufeinanderfolgende Punkte an oder bei Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD_51=Der angegebene Wert "%s" kann nicht als g\u00fcltiger OID geparst werden, da er mit einem Punkt endet
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE_52=Der angegebene Wert kann nicht als g\u00fcltige Attributtypbeschreibung geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS_53=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE_54=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID_55=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID_56=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID_57=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_58=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da er das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS_59=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_60=Der angegebene Wert "%s" kann nicht als Attributtypbeschreibung geparst werden, da ein einfaches Anf\u00fchrungszeichen als erstes nicht-Leerzeichen nach Token %s erwartet, stattdessen aber das Zeichen %s gefunden wurde 
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE_61=The definition for \
+### the attribute type with OID %s declared a superior type with an OID of %s. \
+### No attribute type with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR_62=The definition for \
+### the attribute type with OID %s declared that approximate matching should be \
+### performed using the matching rule "%s".  No such approximate matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR_63=The definition for \
+### the attribute type with OID %s declared that equality matching should be \
+### performed using the matching rule "%s".  No such equality matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR_64=The definition for \
+### the attribute type with OID %s declared that ordering matching should be \
+### performed using the matching rule "%s".  No such ordering matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR_65=The definition for \
+### the attribute type with OID %s declared that substring matching should be \
+### performed using the matching rule "%s".  No such substring matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX_66=The definition for the \
+### attribute type with OID %s declared that it should have a syntax with OID %s. \
+### No such syntax is configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE_67=The definition \
+### for the attribute type with OID %s declared that it should have an attribute \
+### usage of %s.  This is an invalid usage
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS_68=The provided value \
+### "%s" could not be parsed as an attribute type description because a single \
+### quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE_69=Der angegebene Wert kann nicht als g\u00fcltige Objektklassenbeschreibung geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS_70=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE_71=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID_72=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID_73=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID_74=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_75=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da er das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS_76=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_77=Der angegebene Wert "%s" kann nicht als Objektklassenbeschreibung geparst werden, da ein einfaches Anf\u00fchrungszeichen als erstes nicht-Leerzeichen nach Token %s erwartet, stattdessen aber das Zeichen %s gefunden wurde
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS_78=The definition \
+### for the objectclass with OID %s declared a superior objectclass with an OID \
+### of %s.  No objectclass with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS_79=The provided \
+### value "%s" could not be parsed as an objectclass description because a single \
+### quote was expected at position %d but the character %s was found instead
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR_80=The definition \
+### for the objectclass with OID %s declared that it should include required \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR_81=The definition \
+### for the objectclass with OID %s declared that it should include optional \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER_82=The provided value "%s" \
+### cannot be parsed as a valid IA5 string because it contains an illegal \
+### character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE_83=Gibt an, ob die Telefonnummer-Attributsyntax einen Strict-Modus verwenden soll, bei dem nur Werte im ITU-T E.123-Format zul\u00e4ssig sind.  Wenn dieser aktiviert ist, werden alle anderen Werte, die nicht diesem Format entsprechen, zur\u00fcckgewiesen.  Wenn dieser deaktiviert ist, werden allen anderen Werte akzeptiert, es werden aber nur die Ziffern bei der \u00dcbereinstimmung ber\u00fccksichtigt
+###SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE_84=An error \
+### occurred while trying to retrieve attribute \
+### ds-cfg-strict-format from configuration entry %s:  %s.  The \
+### Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+### for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY_85=Der angegebene Wert ist keine g\u00fcltige Telefonnummer, da er leer oder Null ist
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS_86=Der angegebene Wert "%s" ist keine g\u00fcltige Telefonnummer, da die strikte Telefonnummerpr\u00fcfung aktiviert ist und der Wert nicht in \u00dcbereinstimmung mit der ITU-T E.123-Spezifikation mit einem Pluszeichen beginnt
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR_87=Der angegebene Wert "%s" ist keine g\u00fcltige Telefonnummer, da die strikte Telefonnummerpr\u00fcfung aktiviert ist und das Zeichen %s an Position %d gem\u00e4\u00df der ITU-T E.123-Spezifikation unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS_88=Der angegebene Wert "%s" ist keine g\u00fcltige Telefonnummer, da er keine numerischen Ziffern enth\u00e4lt
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE_89=Der Wert des Konfigurationsattributs ds-cfg-strict-format, der angibt ob die strikte Telefonnummer-Syntaxpr\u00fcfung verwendet wird, wurde aktualisiert auf %s in Konfigurationseintrag %s
+###SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR_90=The provided value \
+### "%s" is not a valid numeric string because it contained character %s at \
+### position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE_91=Der angegebene Wert ist keine g\u00fcltige numerische Zeichenkette, da er keine Zeichen enth\u00e4lt.  Ein numerischer Zeichenkettenwert muss mindestens eine numerische Ziffer oder ein Leerzeichen enthalten
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE_92=Der angegebene Wert kann nicht als g\u00fcltige Attributsyntaxbeschreibung geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS_93=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE_94=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID_95=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID_96=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID_97=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS_98=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN_99=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da ein unerwarteter Fehler aufgetreten ist beim Versuch, den Token "DESC" aus der Zeichenkette an oder bei Position %d zu lesen: %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC_100=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da der Token  "DESC" erwartet, stattdessen aber die Zeichenkette "%s" gefunden wurde
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE_101=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da ein unerwarteter Fehler aufgetreten ist beim Versuch, den Wert des Token "DESC" aus der Zeichenkette an oder bei Position %d zu lesen: %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS_102=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da eine schlie\u00dfende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE_103=Der angegebene Wert "%s" kann nicht als Attributsyntaxbeschreibung geparst werden, da das unzul\u00e4ssige Zeichen %s an Position %d hinter der schlie\u00dfenden Klammer gefunden wurde
+###SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS_104=The provided \
+### value "%s" could not be parsed as an attribute syntax description because a \
+### single quote was expected at position %d but the character %s was found \
+### instead
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE_105=The provided value \
+### could not be parsed as a printable string because it was null or empty.  A \
+### printable string must contain at least one character
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER_106=The provided \
+### value "%s" could not be parsed as a printable string because it contained an \
+### invalid character %s at position %d
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD_107=The provided value "*" \
+### could not be parsed as a substring assertion because it consists only of a \
+### wildcard character and zero-length substrings are not allowed
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS_108=The provided \
+### value "%s" could not be parsed as a substring assertion because it contains \
+### consecutive wildcard characters at position %d and zero-length substrings are \
+### not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT_109=Der angegebene Wert %s ist zu kurz, um ein g\u00fcltiger UTC-Zeitwert zu sein
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR_110=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da das Zeichen %s im Jahrhundert bzw. in der Jahresangabe unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH_111=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da %s keine g\u00fcltige Monatsangabe ist 
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY_112=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da %s keine g\u00fcltige Tagesangabe ist 
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR_113=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da %s keine g\u00fcltige Stundenangabe ist 
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE_114=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da %s keine g\u00fcltige Minutenangabe ist 
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR_115=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da er das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND_116=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da %s keine g\u00fcltige Sekundenangabe ist 
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET_117=Der angegebene Wert %s ist kein g\u00fcltiger UTC-Zeitwert, da %s keine g\u00fcltiger GMT-Offset ist 
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE_118=Der angegebene Wert %s kann nicht als g\u00fcltige UTC-Zeit geparst werden: %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE_119=Der angegebene Wert kann nicht als g\u00fcltige DIT-Inhaltsregelbeschreibung geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS_120=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE_121=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID_122=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID_123=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID_124=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS_125=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_126=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da er das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS_127=Die DIT-Inhaltsregel "%s" ist mit der strukturellen Objektklasse %s verkn\u00fcpft, die nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL_128=Die DIT-Inhaltsregel "%s" ist mit der Objektklasse mit dem OID %s (%s) verkn\u00fcpft.  Diese Objektklasse ist zwar im Serverschema vorhanden, ist aber nicht als strukturelle Klasse, sondern als %s definiert
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS_129=Die DIT-Inhaltsregel "%s" ist mit der Hilfobjektklasse %s verkn\u00fcpft, die nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY_130=Die DIT-Inhaltsregel "%s" ist mit der Hilfsobjektklasse %s verkn\u00fcpft. Diese Objektklasse ist zwar im Serverschema vorhanden, ist aber nicht als Hilfsklasse, sondern als %s definiert
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR_131=Die DIT-Inhaltsregel "%s" ist mit dem erforderlichen Attributtyp %s verkn\u00fcpft, der nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR_132=Die DIT-Inhaltsregel "%s" ist mit dem optionalen Attributtyp %s verkn\u00fcpft, der nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR_133=Die DIT-Inhaltsregel "%s" ist mit dem unzul\u00e4ssigen Attributtyp %s verkn\u00fcpft, der nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS_134=Der angegebene Wert "%s" kann nicht als DIT-Inhaltsregelbeschreibung geparst werden, da ein einfaches Anf\u00fchrungszeichen an Position %d erwartet wurde. Stattdessen wurde das Zeichen %s gefunden
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE_135=Der angegebene Wert kann nicht als g\u00fcltige Namensformbeschreibung geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS_136=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%c' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE_137=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID_138=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID_139=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %c an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID_140=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %c an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS_141=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_142=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da er das unzul\u00e4ssige Zeichen %c an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS_143=Die Namensformbeschreibung "%s" ist mit der strukturellen Objektklasse %s verkn\u00fcpft, die nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL_144=Die Namensformbeschreibung "%s" ist mit der Objektklasse mit dem OID %s (%s) verkn\u00fcpft. Diese Objektklasse ist zwar im Serverschema vorhanden, ist aber nicht als strukturelle Klasse, sondern als %s definiert
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR_145=Die Definition der Namensform mit dem OID %s gibt an, dass das erforderliche Attribut "%s" enthalten sein muss.  Im Serverschema ist kein Attributtyp vorhanden, der mit diesem Namen oder OID \u00fcbereinstimmt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR_146=Die Definition der Namensform mit dem OID %s gibt an, dass das optionale Attribut "%s" enthalten sein muss.  Im Serverschema ist kein Attributtyp vorhanden, der mit diesem Namen oder OID \u00fcbereinstimmt
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS_147=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da er nicht die strukturelle Objektklasse angibt, der er zugeordnet ist
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS_148=Der angegebene Wert "%s" kann nicht als Namensformbeschreibung geparst werden, da ein einfaches Anf\u00fchrungszeichen an Position %d erwartet, stattdessen aber das Zeichen %c gefunden wurde
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE_149=Der angegebene Wert kann nicht als g\u00fcltige \u00dcbereinstimmungsregelbeschreibung geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS_150=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE_151=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID_152=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID_153=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID_154=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS_155=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_156=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da er das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX_157=Die \u00dcbereinstimmungsregelbeschreibung "%s" ist der Attributsyntax %s zugeordnet, welche nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX_158=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da er nicht die Attributsyntax angibt, der er zugeordnet ist
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS_159=Der angegebene Wert "%s" kann nicht als \u00dcbereinstimmungsregelbeschreibung geparst werden, da ein einfaches Anf\u00fchrungszeichen an Position %d erwartet, stattdessen aber das Zeichen %s gefunden wurde
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE_160=Der angegebene Wert kann nicht als g\u00fcltige Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS_161=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE_162=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID_163=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID_164=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID_165=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE_166=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da die angegebene \u00dcbereinstimmungsregel %s unbekannt ist
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS_167=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_168=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da er das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR_169=Die Verwendungsbeschreibung der \u00dcbereinstimmungsregel "%s" ist dem Attributtyp %s zugeordnet, der nicht im Serverschema definiert ist
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR_170=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da er nicht den Satz von Attributtypen angibt, die mit dem zugeordneten OID verwendet werden k\u00f6nnen
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS_171=Der angegebene Wert "%s" kann nicht als Verwendungsbeschreibung der \u00dcbereinstimmungsregel geparst werden, da ein einfaches Anf\u00fchrungszeichen an Position %d erwartet, stattdessen aber das Zeichen %s gefunden wurde
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE_172=Der angegebene Wert kann nicht als g\u00fcltige DIT-Strukturregelbeschreibung geparst werden, da er leer ist oder nur Leerzeichen enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS_173=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE_174=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da das Ende des Werts erreicht wurde, obwohl der Directory-Server noch mehr Daten erwartet hat
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID_175=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da die Regel-ID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS_176=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da er eine unerwartete schlie\u00dfende Klammer an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_177=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da er das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM_178=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da er auf die unbekannte Namensform %s verweist
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID_179=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da er auf die unbekannte Regel-ID %d f\u00fcr eine \u00fcbergeordnete DIT-Strukturregel verweist
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM_180=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da er nicht die Namensform f\u00fcr die Regel angibt
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS_181=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da eine \u00f6ffnende Klammer an Position %d erwartet, stattdessen aber das Zeichen '%s' gefunden wurde
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID_182=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da der numerische OID zwei aufeinanderfolgende Punkte an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID_183=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da der numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID_184=Der angegebene Wert "%s" kann nicht als DIT-Strukturregelbeschreibung geparst werden, da der nicht-numerische OID das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT_185=Der angegebene Wert "%s" ist zu kurz, um ein g\u00fcltiger Telexnummerwert zu sein
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE_186=Der angegebene Wert "%s" enth\u00e4lt keine g\u00fcltige Telexnummer, da das Zeichen %s an Position %d kein g\u00fcltiges druckbares Zeichenkettenzeichen ist
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR_187=Der angegebene Wert "%s" enth\u00e4lt keine g\u00fcltige Telexnummer, da das Zeichen %s an Position %d weder ein g\u00fcltiges druckbares Zeichenkettenzeichen noch ein Dollarzeichen enh\u00e4lt, das die Telexnummerkomponenten trennt
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED_188=Der angegebene Wert "%s" enth\u00e4lt keine g\u00fcltige Telexnummer, da das Ende des Werts gefunden wurde, bevor eine durch drei Dollarzeichen getrennte druckbare Zeichenkette gelesen werden konnte
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY_189=Der angegebene Wert kann nicht als g\u00fcltige Faxnummer geparst werden, da er leer ist
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE_190=Der angegebene Wert "%s" kann nicht als g\u00fcltige Faxnummer geparst werden, da das Zeichen %s an Position %d kein g\u00fcltiges druckbares Zeichenkettenzeichen ist
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR_191=Der angegebene Wert "%s" kann nicht als g\u00fcltige Faxnummer geparst werden, da er auf ein Dollarzeichen endet, diesem aber ein Faxparameter folgen m\u00fcsste
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER_192=Der angegebene Wert "%s" kann nicht als g\u00fcltige Faxnummer geparst werden, da die Zeichenkette %s zwischen den Positionen %d und %d kein g\u00fcltiger Faxparameter ist
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN_193=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Namens- und optionaler UID-Wert geparst werden, da ein Fehler aufgetreten ist beim Versuch, den DN-Teil zu parsen: %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT_194=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Namens- und optionaler UID-Wert geparst werden, da der UID-Teil die unzul\u00e4ssige bin\u00e4re Ziffer %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY_195=Der angegebene Wert kann nicht als g\u00fcltige Teletexendger\u00e4te-ID geparst werden, da er leer ist
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE_196=Der angegebene Wert "%s" kann nicht als g\u00fcltige Teletexendger\u00e4te-ID geparst werden, da das Zeichen %s an Position %d kein g\u00fcltiges druckbares Zeichenkettenzeichen ist
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR_197=Der angegebene Wert "%s" kann nicht als g\u00fcltige Teletexendger\u00e4te-ID geparst werden, da er auf ein Dollarzeichen endet, diesem aber ein TTX-Parameter folgen m\u00fcsste
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON_198=Der angegebene Wert "%s" kann nicht als g\u00fcltige Teletexendger\u00e4te-ID geparst werden, da die Parameterzeichenkette keinen Doppelpunkt enth\u00e4lt, der den Namen vom Wert trennt
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER_199=Der angegebene Wert "%s" kann nicht als g\u00fcltige Teletexendger\u00e4te-ID geparst werden, da die Zeichenkette "%s" kein g\u00fcltiger TTX-Parametername ist
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE_200=Der angegebene Wert kann nicht als sonstiger Mailboxwert geparst werden, da er leer ist
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE_201=Der angegebene Wert "%s" kann nicht als sonstiger Mailboxwert geparst werden, da kein Mailboxtyp vor dem Dollarzeichen angegeben ist
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR_202=Der angegebene Wert "%s" kann nicht als sonstiger Mailboxwert geparst werden, da der Mailboxtyp das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX_203=Der angegebene Wert "%s" kann nicht als sonstiger Mailboxwert geparst werden, da keine Mailbox hinter dem Dollarzeichen angegeben ist
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR_204=Der angegebene Wert "%s" kann nicht als sonstiger Mailboxwert geparst werden, da die Mailbox das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC_205=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da er keinen Objektklassennamen oder OID vor dem Rautezeichen (#) enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR_206=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da der Kriterienteil %s das unzul\u00e4ssige Zeichen %c an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN_207=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da beim Kriterienteil %s die zur \u00f6ffnenden Klammer geh\u00f6rende schlie\u00dfende Klammer fehlt
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK_208=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da der Kriterienteil %s mit einem Fragezeichen beginnt, diesem aber als Zeichenkette weder "true" noch "false" folgen
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR_209=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da der Kriterienteil %s kein Dollarzeichen enth\u00e4lt, das den Attributtyp vom \u00dcbereinstimmungstyp trennt
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR_210=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da im Kriterienteil %s kein Attributtyp vor dem Dollarzeichen festgelegt ist
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE_211=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da im Kriterienteil %s kein \u00dcbereinstimmungstyp nach dem Dollarzeichen festgelegt ist
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE_212=Der angegebene Wert "%s" kann nicht als Richtwert geparst werden, da im Kriterienteil %s ein ung\u00fcltiger \u00dcbereinstimmungstyp an Position %d festgelegt ist
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP_213=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da er kein Rautzeichen (#) enth\u00e4lt, das die Objektklasse vom Kriterium trennt
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC_214=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da er keinen Objektklassennamen oder OID vor dem Rautezeichen (#) enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID_215=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da der numerische OID %s, der die Objektklasse festlegt, zwei aufeinanderfolgende Punkt an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID_216=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da der numerische OID %s, der die Objektklasse festlegt, das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME_217=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da der Objektklassennamen %s das unzul\u00e4ssige Zeichen %s an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP_218=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da er kein Rautzeichen (#) enth\u00e4lt, das das Kriterium vom Umfang trennt
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE_219=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da kein Umfang nach dem Rautezeichen (#) angegeben ist
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE_220=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da der angegebene Umfang %s ung\u00fcltig ist
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA_221=Der angegebene Wert "%s" kann nicht als verbesserter Richtwert geparst werden, da keine Kriterien zwischen den Rautezeichen (#) festgelegt sind
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE_222=Der angegebene Wert %s kann nicht als g\u00fcltiger OID geparst werden: %s
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE_223=An unexpected \
+### error occurred while trying to normalize value %s as a generalized time \
+### value:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE_224=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseExactOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE_225=An error occurred while \
+### attempting to compare two objects using the caseExactOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE_226=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE_227=An error occurred while \
+### attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE_228=An error \
+### occurred while attempting to compare two AttributeValue objects using the \
+### generalizedTimeOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE_229=An error occurred \
+### while attempting to compare two objects using the \
+### generalizedTimeOrderingMatch matching rule because the objects were of an \
+### unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+### value objects may be compared
+###SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE_230=An error occurred while \
+### attempting to compare two AttributeValue objects using the \
+### integerOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE_231=An error occurred while \
+### attempting to compare two objects using the integerOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE_232=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### numericStringOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE_233=An error occurred \
+### while attempting to compare two objects using the numericStringOrderingMatch \
+### matching rule because the objects were of an unsupported type %s.  Only byte \
+### arrays, ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE_234=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### octetStringOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE_235=An error occurred while \
+### attempting to compare two objects using the octetStringOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH_236=The provided value "%s" has \
+### an invalid length for a UUID.  All UUID values must have a length of exactly \
+### 36 bytes, but the provided value had a length of %d bytes
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH_237=The provided value "%s" should \
+### have had a dash at position %d, but the character '%s' was found instead
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX_238=The provided value "%s" should \
+### have had a hexadecimal digit at position %d, but the character '%s' was found \
+### instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH_239=Gibt an, ob Attribute mit der Verzeichniszeichenkettensyntax Werte der L\u00e4nge Null haben d\u00fcrfen.  Dies wird von den LDAP-Spezifikationen technisch nicht zugelassen, kann aber f\u00fcr die Abw\u00e4rtskompatibilit\u00e4t mit vorherigen Directory-Server-Versionen n\u00fctzlich sein
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH_240=An \
+### error occurred while trying to determine the value of the %s configuration \
+### attribute, which indicates whether directory string attributes should be \
+### allowed to have zero-length values:  %s
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE_241=The \
+### operation attempted to assign a zero-length value to an attribute with the \
+### directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH_242=Das Attribut %s im Konfigurationseintrag %s wurde mit dem neuen Wert %s aktualisiert
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR_243=The provided \
+### authPassword value had an invalid scheme character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_244=The provided authPassword value \
+### had a zero-length scheme element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR_245=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the scheme and authInfo elements
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR_246=The provided \
+### authPassword value had an invalid authInfo character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_247=The provided authPassword \
+### value had a zero-length authInfo element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR_248=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the authInfo and authValue elements
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS_249=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### it did not start with a parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE_250=The provided value "%s" could not \
+### be parsed by the integer first component matching rule because it did not \
+### have any non-space characters after the opening parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT_251=The provided value "%s" \
+### could not be parsed by the integer first component matching rule because it \
+### did not have any space characters after the first component
+###SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT_252=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### the first component does not appear to be an integer value
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE_253=No value was given to decode by \
+### the user password attribute syntax
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE_254=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not start with the opening curly brace ("{") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE_255=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not contain a closing curly brace ("}") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME_256=Unable to decode the provided \
+### value according to the user password syntax because the value does not \
+### contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID_257=Der angegebene Wert "%s" kann nicht als g\u00fcltige RFC 3672-Unteransichtsspezifikation geparst werden
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID_258=Der angegebene Wert "%s" kann nicht als g\u00fcltige absolute Unteransichtsspezifikation geparst werden
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID_259=Der angegebene Wert "%s" kann nicht als g\u00fcltige relative Unteransichtsspezifikation geparst werden
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER_260=The provided value %s is not \
+### allowed for attributes with a Integer syntax
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR_261=The provided \
+### authPassword value had an invalid authValue character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE_262=The provided authPassword \
+### value had a zero-length authValue element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR_263=The provided \
+### authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER_264=Der angegebene Wert "%s" kann nicht als Attributsyntaxerweiterung geparst werden, da er ein unzul\u00e4ssige Zeichen an Position %d enth\u00e4lt
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION_265=Der Attributsyntax kann wegen einer ung\u00fcltigen Erweiterung nicht geparst werden.%s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE_266=The definition \
+### for objectclass %s is invalid because it has an objectclass type of %s but \
+### this is incompatible with the objectclass type %s for the superior class %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP_267=The \
+### definition for objectclass %s is invalid because it is defined as a \
+### structural class but its superior chain does not include the "top" \
+### objectclass
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
+### for attribute type %s is invalid because its attribute usage %s is not the \
+### same as the usage for its superior type %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \
+### definition for attribute type %s is invalid because it is defined as a \
+### collective type but the superior type %s is not collective
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
+### definition for attribute type %s is invalid because it is not defined as a \
+### collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=Die DIT-Inhaltsregel "%s" ist ung\u00fcltig, da sie die Verwendung des Attributtyps %s verbietet, der von der zugeordneten strukturellen Objektklasse %s erfordert wird
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=Die DIT-Inhaltsregel "%s" ist ung\u00fcltig, da sie die Verwendung des Attributtyps %s verbietet, der von der zugeordneten Hilfsobjektklasse %s erfordert wird
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \
+### for attribute type %s is invalid because it is declared COLLECTIVE but does \
+### not have a usage of userApplications
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \
+### definition for attribute type %s is invalid because it is declared \
+### NO-USER-MODIFICATION but does not have an operational usage
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR_275=The \
+### provided value %s is not a valid generalized time value because it contains \
+### illegal character %s in the fraction component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION_276=The provided \
+### value %s is not a valid generalized time value because it does not contain at \
+### least one digit after the period to use as the fractional component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO_277=The provided \
+### value %s is not a valid generalized time value because it does not end with \
+### 'Z' or a time zone offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME_278=The provided value \
+### %s is not a valid generalized time value because it represents an invalid \
+### time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED_279=Ein Schemaelement konnte nicht importiert werden: %s, %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE_280=Die Sortierregel %s unter dem entsprechenden Regeleintrag %s ist ung\u00fcltig, da JVM das Gebietsschema %s nicht unterst\u00fctzt
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT_281=Die angegebene Sortierregel %s enth\u00e4lt kein g\u00fcltiges Format von OID:LOCALE
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=Der angegebene Wert "%s" kann nicht als g\u00fcltiger Distinguished Name geparst werden, da ein Attributswert mit einem Zeichen an Position '%d' vermieden werden muss
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR_283=Der angegebene Wert "%s" kann nicht als g\u00fcltige Attributstypedefinition geparst werden, da das Zeichen '%c' an Position '%d' in einem Attributstypnamen unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_284=Der angegebene Wert "%s" kann nicht als g\u00fcltige Attributstypdefiinition geparst werden, da das Unterstrich-Zeichen in einem Attributtypenamen unzul\u00e4ssig ist, au\u00dfer wenn die Konfigurationsoption %s aktiviert ist
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_285=Der angegebene Wert "%s" kann nicht als g\u00fcltige Attributstypdefinition geparst werden, da das Bindestrich-Zeichen als erstes Zeichen in einem Attributstypnamen unzul\u00e4ssig ist
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_286=Der angegebene Wert "%s" kann nicht als g\u00fcltige Attributstypdefinition geparst werden, da das Unterstrich-Zeichen als erstes Zeichen in einem Attributstypnamen unzul\u00e4ssig ist, selbst wenn die Konfigurationsoption %s aktiviert ist
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_287=Der angegebene Wert "%s" kann nicht als g\u00fcltige Attributstypdefinition geparst werden, da die Ziffer '%c' nicht als erstes Zeichen in einem Attributstypnamen zul\u00e4ssig ist, au\u00dfer wenn der Name als OID festgelegt oder die Konfigurationsoption %s aktiviert ist
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR_288=Der angegebene Wert "%s" kann nicht als g\u00fcltige Objektklassendefinition geparst werden, da das Zeichen '%c' an Position '%d' in einem Objektklassenamen unzul\u00e4ssig ist
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_289=Der angegebene Wert "%s" kann nicht als g\u00fcltige Objektklassendefinition geparst werden, da das Unterstrich-Zeichen in einem Attributnamen unzul\u00e4ssig ist, au\u00dfer wenn die Konfigurationsoption %s aktiviert ist
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_290=Der angegebene Wert "%s" kann nicht als g\u00fcltige Objektklassendefinition geparst werden, da das Bindestrich-Zeichen als erstes Zeichen in einem Objektklassennamen unzul\u00e4ssig ist
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_291=Der angegebene Wert "%s" kann nicht als g\u00fcltige Objektklassendefinition geparst werden, da das Unterstrich-Zeichen als erstes Zeichen in einem Objektklassennamen unzul\u00e4ssig ist, selbst wenn die Konfigurationsoption %s aktiviert ist
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_292=Der angegebene Wert "%s" kann nicht als g\u00fcltige Objektklassendefinition geparst werden, da das erste Zeichen '%c' in einem Objektklassennamen unzul\u00e4ssig ist, selbst wenn die Konfigurationsoption %s aktiviert ist
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_es.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_es.properties
new file mode 100755
index 0000000..5dda414
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_es.properties
@@ -0,0 +1,531 @@
+# 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
+#
+#      Copyright 2009 Sun Microsystems, Inc.
+#
+# Global directives
+#
+global.ordinal=-1
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE_1=Unable to retrieve \
+### approximate matching rule %s used as the default for the %s attribute syntax. \
+### Approximate matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE_2=Unable to retrieve \
+### equality matching rule %s used as the default for the %s attribute syntax. \
+### Equality matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE_3=Unable to retrieve \
+### ordering matching rule %s used as the default for the %s attribute syntax. \
+### Ordering matches will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE_4=Unable to retrieve \
+### substring matching rule %s used as the default for the %s attribute syntax. \
+### Substring matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN_5=The provided value "%s" is not \
+### allowed for attributes with a Boolean syntax.  The only allowed values are \
+### 'TRUE' and 'FALSE'
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT_6=The provided value "%s" is too \
+### short to be a valid bit string.  A bit string must be a series of binary \
+### digits surrounded by single quotes and followed by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED_7=The provided value "%s" is not \
+### a valid bit string because it is not surrounded by single quotes and followed \
+### by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT_8=The provided value "%s" is \
+### not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=El valor proporcionado "%s" no es una cadena de pa\u00edses v\u00e1lida porque no tiene una longitud de dos caracteres. 
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE_10=El valor proporcionado "%s" no es una cadena de pa\u00edses v\u00e1lida porque contiene uno o m\u00e1s caracteres no imprimibles. 
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=El valor proporcionado "%s" no es un valor de m\u00e9todo de entrega v\u00e1lido porque no contiene elementos
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT_12=El valor proporcionado "%s" no es un valor de m\u00e9todo de entrega v\u00e1lido porque "%s" no es un m\u00e9todo v\u00e1lido
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT_13=The provided value "%s" \
+### is too short to be a valid generalized time value
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR_14=The provided value \
+### "%s" is not a valid generalized time value because the '%s' character is not \
+### allowed in the century or year specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH_15=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid month \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY_16=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid day \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR_17=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid hour \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE_18=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid minute \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND_19=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid second \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND_20=The provided \
+### value "%s" is not a valid generalized time value because the sub-second \
+### component is not valid (between 1 and 3 numeric digits)
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND_21=The provided value \
+### "%s" is not a valid generalized time value because the sub-second value may \
+### not contain more than three digits
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET_22=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+### offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR_23=The provided value \
+### "%s" is not a valid generalized time value because it contains an invalid \
+### character '%s' at position %d
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE_24=The provided value \
+### "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_25=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido: %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA_26=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque el \u00faltimo car\u00e1cter distinto a un espacio era una coma o punto y coma
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT_27=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque no se permite el d\u00edgito num\u00e9rico '%s' como primer car\u00e1cter en un nombre de atributo
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR_28=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque no se permite el car\u00e1cter '%c'  en la posici\u00f3n %d en un nombre de atributo
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR_29=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque no se permite el car\u00e1cter de subrayado en un nombre de atributo a menos que est\u00e9 habilitada la opci\u00f3n de configuraci\u00f3n %s
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH_30=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque no se permite el car\u00e1cter de gui\u00f3n como primer car\u00e1cter de un nombre de atributo
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE_31=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque no se permite el car\u00e1cter de subrayado como primer car\u00e1cter de un nombre de atributo incluso si est\u00e1 habilitada la opci\u00f3n de configuraci\u00f3n %s
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT_32=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque no se permite el d\u00edgito '%c' como primer car\u00e1cter de un nombre de atributo a menos que est\u00e9 especificado el nombre como un OID o que est\u00e9 habilitada la opci\u00f3n de configuraci\u00f3n %s
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME_33=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque conten\u00eda un RDN que a su vez conten\u00eda un nombre de atributo vac\u00edo
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD_34=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque el nombre de atributo analizado %s inclu\u00eda un punto, sin embargo no parec\u00eda ser un OID v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME_35=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque el \u00faltimo car\u00e1cter distinto a un espacio formaba parte del nombre de atributo '%s'
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL_36=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque el siguiente car\u00e1cter distinto a un espacio detr\u00e1s del nombre de atributo "%s" deber\u00eda haber sido un signo igual en lugar de '%c'
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR_37=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque el car\u00e1cter '%c'  en la posici\u00f3n %d no es v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT_38=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque un valor de atributo comenzaba con un signo de almohadilla (#), sin embargo, no estaba seguido por un m\u00faltiplo positivo de dos d\u00edgitos hexadecimales
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT_39=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque un valor de atributo comenzaba con un signo de almohadilla (#) sin embargo conten\u00eda un car\u00e1cter %c que no era un d\u00edgito hexadecimal v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE_40=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque se ha producido un fallo inesperado al intentar analizar un valor de atributo desde uno de los componentes de RDN: "%s"
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE_41=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque uno de los componentes de RDN inclu\u00eda un valor citado que no ten\u00eda la comilla de cierre correspondiente
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID_42=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque uno de los componentes de RDN inclu\u00eda un valor con un d\u00edgito hexadecimal escapado que no estaba seguido por un segundo d\u00edgito hexadecimal
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO_43=The provided value "%s" could \
+### not be parsed as a valid integer because the first digit may not be zero \
+### unless it is the only digit
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH_44=The provided value "%s" \
+### could not be parsed as a valid integer because the dash may only appear if it \
+### is the first character of the value followed by one or more digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER_45=The provided value "%s" \
+### could not be parsed as a valid integer because character '%c' at position %d \
+### is not allowed in an integer value
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE_46=The provided value "%s" could \
+### not be parsed as a valid integer because it did not contain any digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE_47=The provided value "%s" \
+### could not be parsed as a valid integer because it contained only a dash not \
+### followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE_48=No se pudo analizar el valor proporcionado como un OID v\u00e1lido porque no conten\u00eda caracteres
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER_49=No se pudo analizar el valor proporcionado "%s" como un OID v\u00e1lido porque ten\u00eda un car\u00e1cter no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS_50=No se pudo analizar el valor proporcionado "%s" como un OID v\u00e1lido porque ten\u00eda dos puntos consecutivos en o cerca de la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD_51=No se pudo analizar el valor proporcionado "%s" como un OID v\u00e1lido porque finaliza con un punto
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE_52=No se pudo analizar el valor proporcionado como descripci\u00f3n de tipo de atributo v\u00e1lido porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS_53=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de tipo de atributo porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar del par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE_54=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de tipo de atributo porque se encontr\u00f3 el final del valor si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID_55=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de tipo de atributo porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID_56=No se pudo analizar el valor proporcionado  "%s" como descripci\u00f3n de tipo de atributo porque el OID num\u00e9rico conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID_57=No se pudo analizar el valor proporcionado  "%s" como descripci\u00f3n de tipo de atributo porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_58=No se pudo analizar el valor proporcionado  "%s" como descripci\u00f3n de tipo de atributo porque conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS_59=No se pudo analizar el valor proporcionado  "%s" como descripci\u00f3n de tipo de atributo porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_60=No se pudo analizar el valor proporcionado  "%s" como descripci\u00f3n de tipo de atributo porque se esperaba una comilla como el primer car\u00e1cter no blanco a continuaci\u00f3n del token %s.  Sin embargo, se encontr\u00f3 el car\u00e1cter %s en su lugar
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE_61=The definition for \
+### the attribute type with OID %s declared a superior type with an OID of %s. \
+### No attribute type with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR_62=The definition for \
+### the attribute type with OID %s declared that approximate matching should be \
+### performed using the matching rule "%s".  No such approximate matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR_63=The definition for \
+### the attribute type with OID %s declared that equality matching should be \
+### performed using the matching rule "%s".  No such equality matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR_64=The definition for \
+### the attribute type with OID %s declared that ordering matching should be \
+### performed using the matching rule "%s".  No such ordering matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR_65=The definition for \
+### the attribute type with OID %s declared that substring matching should be \
+### performed using the matching rule "%s".  No such substring matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX_66=The definition for the \
+### attribute type with OID %s declared that it should have a syntax with OID %s. \
+### No such syntax is configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE_67=The definition \
+### for the attribute type with OID %s declared that it should have an attribute \
+### usage of %s.  This is an invalid usage
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS_68=The provided value \
+### "%s" could not be parsed as an attribute type description because a single \
+### quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE_69=No se pudo analizar el valor proporcionado como descripci\u00f3n de clase de objeto v\u00e1lido porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS_70=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de clase de objeto porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar de un par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE_71=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de clase de objeto porque se encontr\u00f3 el final del valor si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID_72=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de clase de objeto porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID_73=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de clase de objeto porque el OID num\u00e9rico conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID_74=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de clase de objeto porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_75=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de clase de objeto porque conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS_76=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de clase de objeto porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_77=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de clase de objeto porque se esperaba una comilla como el primer car\u00e1cter no blanco a continuaci\u00f3n del token %s. Sin embargo, se encontr\u00f3 el car\u00e1cter %s en su lugar
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS_78=The definition \
+### for the objectclass with OID %s declared a superior objectclass with an OID \
+### of %s.  No objectclass with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS_79=The provided \
+### value "%s" could not be parsed as an objectclass description because a single \
+### quote was expected at position %d but the character %s was found instead
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR_80=The definition \
+### for the objectclass with OID %s declared that it should include required \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR_81=The definition \
+### for the objectclass with OID %s declared that it should include optional \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER_82=The provided value "%s" \
+### cannot be parsed as a valid IA5 string because it contains an illegal \
+### character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE_83=Indica si la sintaxis de atributo de n\u00famero de tel\u00e9fono deber\u00eda utilizar un modo estricto en el que s\u00f3lo se aceptar\u00e1n valores con el formato E.123 de ITU-T.  Si est\u00e1 habilitado, se rechazar\u00e1 cualquier valor con este formato.  En el caso de que est\u00e9 deshabilitado, se aceptar\u00e1 cualquier valor, pero s\u00f3lo se tendr\u00e1n en cuenta los d\u00edgitos a la hora de llevar a cabo la comparaci\u00f3n
+###SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE_84=An error \
+### occurred while trying to retrieve attribute \
+### ds-cfg-strict-format from configuration entry %s:  %s.  The \
+### Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+### for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY_85=El valor proporcionado no es un n\u00famero de tel\u00e9fono v\u00e1lido porque est\u00e1 vac\u00edo o es nulo
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS_86=El valor proporcionado "%s" no es un n\u00famero de tel\u00e9fono v\u00e1lido porque est\u00e1 habilitada la comprobaci\u00f3n estricta de n\u00famero de tel\u00e9fono y el valor no comienza con un signo m\u00e1s (+) en cumplimiento de la especificaci\u00f3n E.123 de ITU-T
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR_87=El valor proporcionado "%s" no es un n\u00famero de tel\u00e9fono v\u00e1lido porque est\u00e1 habilitada la comprobaci\u00f3n estricta de n\u00famero de tel\u00e9fono y la especificaci\u00f3n E.123 de ITU-T no permite el car\u00e1cter %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS_88=El valor proporcionado "%s" no es un n\u00famero de tel\u00e9fono v\u00e1lido porque no contiene d\u00edgitos num\u00e9ricos
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE_89=El valor de atributo de configuraci\u00f3n ds-cfg-strict-format, que indica si se utiliza la comprobaci\u00f3n estricta de sintaxis de n\u00famero de tel\u00e9fono, se ha actualizado a %s en la entrada de configuraci\u00f3n %s
+###SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR_90=The provided value \
+### "%s" is not a valid numeric string because it contained character %s at \
+### position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE_91=El valor proporcionado no era una cadena num\u00e9rica v\u00e1lida porque no conten\u00eda caracteres.  Un valor de cadena num\u00e9rico debe contener un espacio o un d\u00edgito num\u00e9rico como m\u00ednimo
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE_92=No se pudo analizar el valor proporcionado como descripci\u00f3n de sintaxis de atributo v\u00e1lido porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS_93=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de sintaxis de atributo porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar del par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE_94=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque se encontr\u00f3 el final del valor, si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID_95=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID_96=No se pudo analizar el valor proporcionado  "%s" como descripci\u00f3n de sintaxis de atributo porque el OID num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID_97=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS_98=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN_99=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque se produjo un error inesperado al intentar leer el token "DESC" desde la cadena en o cerca de la posici\u00f3n %d:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC_100=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque se encontr\u00f3 la cadena "%s" en lugar del token "DESC"
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE_101=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque se produjo un error inesperado al intentar leer el valor del token "DESC" desde la cadena en o cerca de la posici\u00f3n %d:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS_102=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de sintaxis de atributo porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar del par\u00e9ntesis de cierre en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE_103=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de sintaxis de atributo porque se encontr\u00f3 un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d detr\u00e1s del par\u00e9ntesis de cierre
+###SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS_104=The provided \
+### value "%s" could not be parsed as an attribute syntax description because a \
+### single quote was expected at position %d but the character %s was found \
+### instead
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE_105=The provided value \
+### could not be parsed as a printable string because it was null or empty.  A \
+### printable string must contain at least one character
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER_106=The provided \
+### value "%s" could not be parsed as a printable string because it contained an \
+### invalid character %s at position %d
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD_107=The provided value "*" \
+### could not be parsed as a substring assertion because it consists only of a \
+### wildcard character and zero-length substrings are not allowed
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS_108=The provided \
+### value "%s" could not be parsed as a substring assertion because it contains \
+### consecutive wildcard characters at position %d and zero-length substrings are \
+### not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT_109=El valor proporcionado %s es demasiado corto para considerarse un valor de tiempo UTC v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR_110=El valor proporcionado %s  no es un valor de tiempo UTC v\u00e1lido porque no se permite el car\u00e1cter %s en la especificaci\u00f3n de a\u00f1o o siglo
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH_111=El valor proporcionado %s no es un valor de tiempo UTC v\u00e1lido porque %s no es una especificaci\u00f3n de mes v\u00e1lida
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY_112=El valor proporcionado %s no es un valor de tiempo UTC v\u00e1lido porque %s no es una especificaci\u00f3n de d\u00eda v\u00e1lida
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR_113=El valor proporcionado %s no es un valor de tiempo UTC v\u00e1lido porque %s no es una especificaci\u00f3n de hora v\u00e1lida
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE_114=El valor proporcionado %s no es un valor de tiempo UTC v\u00e1lido porque %s no es una especificaci\u00f3n de minuto v\u00e1lida
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR_115=El valor proporcionado %s no es un valor de tiempo UTC v\u00e1lido porque contiene un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND_116=El valor proporcionado %s no es un valor de tiempo UTC v\u00e1lido porque %s no es una especificaci\u00f3n de segundo v\u00e1lida
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET_117=El valor proporcionado %s no es un valor de tiempo UTC v\u00e1lido porque %s no es un ajuste GMT v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE_118=No se pudo analizar el valor proporcionado %s como tiempo UTC v\u00e1lido: %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE_119=No se pudo analizar el valor proporcionado como descripci\u00f3n de regla de contenido del DIT v\u00e1lida porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS_120=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de regla de contenido del DIT porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar del par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE_121=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de contenido del DIT porque se encontr\u00f3 el final del valor si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID_122=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de contenido del DIT porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID_123=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de contenido del DIT porque el OID num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID_124=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de contenido del DIT porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS_125=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de contenido del DIT porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_126=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de contenido del DIT porque conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS_127=La regla de contenido del DIT "%s" est\u00e1 asociada a una clase de objeto estructural %s que no est\u00e1 definida en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL_128=La regla de contenido del DIT "%s" est\u00e1 asociada a la clase de objeto con OID %s (%s).  Esta clase de objeto existe en el esquema del servidor pero no est\u00e1 definida como estructural sino como %s. 
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS_129=La regla de contenido del DIT "%s" est\u00e1 asociada a una clase de objeto auxiliar %s que no est\u00e1 definida en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY_130=La regla de contenido del DIT "%s" est\u00e1 asociada a una clase de objeto auxiliar %s. Esta clase de objeto existe en el esquema del servidor pero no se define como auxiliar sino como %s
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR_131=La regla de contenido del DIT "%s" est\u00e1 asociada a un tipo de atributo necesario %s que no est\u00e1 definido en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR_132=La regla de contenido del DIT "%s" est\u00e1 asociada a un tipo de atributo opcional %s que no est\u00e1 definido en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR_133=La regla de contenido del DIT "%s" est\u00e1 asociada a un tipo de atributo prohibido %s que no est\u00e1 definido en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS_134=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de regla de contenido del DIT porque se encontr\u00f3 el car\u00e1cter %3$s en lugar de una comilla en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE_135=No se pudo analizar el valor proporcionado como descripci\u00f3n de formato de nombre v\u00e1lido porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS_136=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de formato de nombre porque se encontr\u00f3 un car\u00e1cter '%3$c' en lugar de un par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE_137=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de formato de nombre porque se encontr\u00f3 el final del valor si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID_138=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de formato de nombre porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID_139=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de formato de nombre porque el OID num\u00e9rico conten\u00eda un car\u00e1cter %c no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID_140=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de formato de nombre porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter %c no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS_141=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de formato de nombre porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_142=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de formato de nombre porque conten\u00eda un car\u00e1cter %c no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS_143=La descripci\u00f3n de formato de nombre "%s" est\u00e1 asociada a una clase de objeto estructural %s que no est\u00e1 definida en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL_144=La descripci\u00f3n de formato de nombre "%s" est\u00e1 asociada a la clase de objeto con OID %s (%s). Esta clase de objeto existe en el esquema del servidor pero no est\u00e1 definida como estructural sino como %s. 
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR_145=La definici\u00f3n del formato de nombre con OID %s declar\u00f3 que deber\u00eda incluir el atributo necesario "%s".  No existe ning\u00fan tipo de atributo que coincida con este nombre u OID en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR_146=La definici\u00f3n del formato de nombre con OID %s declar\u00f3 que deber\u00eda incluir el atributo opcional "%s".  No existe ning\u00fan tipo de atributo que coincida con este nombre u OID en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS_147=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de formato de nombre porque no especifica la clase de objeto estructural con la que est\u00e1 asociada
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS_148=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de formato de nombre porque se encontr\u00f3 el car\u00e1cter %3$c en lugar de una comilla en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE_149=No se pudo analizar el valor proporcionado como descripci\u00f3n de regla de coincidencia v\u00e1lida porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS_150=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de regla de coincidencia porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar de un par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE_151=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque se encontr\u00f3 el final del valor si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID_152=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID_153=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque el OID num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID_154=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS_155=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_156=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX_157=La descripci\u00f3n de regla de coincidencia "%s" est\u00e1 asociada a la sintaxis de atributo %s que no est\u00e1 definida en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX_158=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque no especifica la sintaxis de atributo con la que est\u00e1 asociada
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS_159=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de regla de coincidencia porque se encontr\u00f3 el car\u00e1cter %3$s en lugar de una comilla en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE_160=No se pudo analizar el valor proporcionado como descripci\u00f3n de uso de regla de coincidencia v\u00e1lida porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS_161=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de uso de regla de coincidencia porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar de un par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE_162=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de uso de regla de coincidencia porque se encontr\u00f3 el final del valor si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID_163=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de uso de regla de coincidencia porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID_164=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de uso de regla de coincidencia porque el OID num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID_165=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de uso de regla de coincidencia porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE_166=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de uso de regla de coincidencia porque la regla de coincidencia especificada %s es desconocida
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS_167=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de uso de regla de coincidencia porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_168=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de uso de regla de coincidencia porque conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR_169=La descripci\u00f3n de uso de regla de coincidencia "%s" est\u00e1 asociada al tipo de atributo %s que no est\u00e1 definido en el esquema del servidor
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR_170=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de coincidencia porque no especifica el conjunto de tipos de atributo que se pueden utilizar con el OID asociado
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS_171=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de uso de regla de coincidencia porque se encontr\u00f3 el car\u00e1cter %3$s en lugar de una comilla en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE_172=No se pudo analizar el valor proporcionado como descripci\u00f3n de regla de estructura del DIT v\u00e1lida porque estaba vac\u00edo o conten\u00eda s\u00f3lo espacios en blanco
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS_173=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de regla de estructura del DIT porque se encontr\u00f3 un car\u00e1cter '%3$s' en lugar del par\u00e9ntesis de apertura en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE_174=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque se encontr\u00f3 el final del valor si bien Directory Server esperaba que se proporcionaran m\u00e1s datos
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID_175=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque el ID de regla conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS_176=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque conten\u00eda un par\u00e9ntesis de cierre inesperado en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_177=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM_178=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque hac\u00eda referencia a un formato de nombre desconocido %s
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID_179=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque hac\u00eda referencia a un ID de regla desconocido %d para una regla de estructura del DIT superior
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM_180=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque no especific\u00f3 el formato de nombre para la regla
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS_181=No se pudo analizar el valor proporcionado "%1$s" como descripci\u00f3n de regla de estructura del DIT porque se encontr\u00f3 el car\u00e1cter %3$s en lugar de una comilla en la posici\u00f3n %2$d
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID_182=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque el OID num\u00e9rico conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID_183=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque el OID num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID_184=No se pudo analizar el valor proporcionado "%s" como descripci\u00f3n de regla de estructura del DIT porque el OID no num\u00e9rico conten\u00eda un car\u00e1cter %s no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT_185=El valor proporcionado "%s" es demasiado corto para considerarse un valor de n\u00famero de t\u00e9lex v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE_186=El valor proporcionado "%s" no tiene un n\u00famero de t\u00e9lex v\u00e1lido porque un car\u00e1cter %s en la posici\u00f3n %d no era un car\u00e1cter de cadena imprimible v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR_187=El valor proporcionado "%s" no tiene un n\u00famero de t\u00e9lex v\u00e1lido porque un car\u00e1cter %s en la posici\u00f3n %d no era ni un car\u00e1cter de cadena imprimible v\u00e1lido ni un signo de d\u00f3lar para separar los componentes de n\u00famero de t\u00e9lex
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED_188=El valor proporcionado "%s" no tiene un n\u00famero de t\u00e9lex v\u00e1lido porque se encontr\u00f3 el final del valor antes de que se pudieran leer tres cadenas imprimibles delimitadas por el s\u00edmbolo del d\u00f3lar
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY_189=No se pudo analizar el valor proporcionado como n\u00famero de tel\u00e9fono de facs\u00edmil v\u00e1lido porque estaba vac\u00edo
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE_190=No se pudo analizar el valor proporcionado "%s" como n\u00famero de tel\u00e9fono de facs\u00edmil v\u00e1lido porque un car\u00e1cter %s en la posici\u00f3n %d no era un car\u00e1cter de cadena imprimible v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR_191=No se pudo analizar el valor proporcionado "%s" como n\u00famero de tel\u00e9fono de facs\u00edmil v\u00e1lido porque finaliza con un signo de d\u00f3lar que deber\u00eda estar seguido por un par\u00e1metro de fax
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER_192=No se pudo analizar el valor proporcionado "%s" como n\u00famero de tel\u00e9fono de facs\u00edmil v\u00e1lido porque la cadena "%s" entre las posiciones %d y %d no era un par\u00e1metro de fax v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN_193=No se pudo analizar el valor proporcionado "%s" como nombre v\u00e1lido y valor UID opcional porque se produjo un error al intentar analizar la parte de ND: %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT_194=No se pudo analizar el valor proporcionado "%s" como nombre v\u00e1lido y valor UID opcional porque la parte de UID conten\u00eda un d\u00edgito binario no v\u00e1lido %s en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY_195=No se pudo analizar el valor proporcionado como identificador de terminal de teletexto v\u00e1lido porque estaba vac\u00edo
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE_196=No se pudo analizar el valor proporcionado "%s" como identificador de terminal de teletexto v\u00e1lido porque un car\u00e1cter %s en la posici\u00f3n %d no era un car\u00e1cter de cadena imprimible v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR_197=No se pudo analizar el valor proporcionado "%s" como identificador de terminal de teletexto v\u00e1lido porque finaliza con un signo de d\u00f3lar que deber\u00eda ser seguido por un par\u00e1metro de TTX
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON_198=No se pudo analizar el valor proporcionado "%s" como identificador de terminal de teletexto v\u00e1lido porque la cadena de par\u00e1metros no conten\u00eda un signo de dos puntos para separar el nombre del valor
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER_199=No se pudo analizar el valor proporcionado "%s" como identificador de terminal de teletexto v\u00e1lido porque la cadena "%s" no es un nombre de par\u00e1metro TTX v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE_200=No se pudo analizar el valor proporcionado como otro valor de buz\u00f3n porque estaba vac\u00edo
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE_201=No se pudo analizar el valor proporcionado "%s" como otro valor de buz\u00f3n porque no hab\u00eda ning\u00fan tipo de buz\u00f3n delante del signo de d\u00f3lar
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR_202=No se pudo analizar el valor proporcionado "%s" como otro valor de buz\u00f3n porque el tipo de buz\u00f3n conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d. 
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX_203=No se pudo analizar el valor proporcionado "%s" como otro valor de buz\u00f3n porque no hab\u00eda ning\u00fan buz\u00f3n detr\u00e1s del signo de d\u00f3lar
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR_204=No se pudo analizar el valor proporcionado "%s" como otro valor de buz\u00f3n porque el buz\u00f3n conten\u00eda un car\u00e1cter no v\u00e1lido %s en la posici\u00f3n %d. 
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC_205=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque no conten\u00eda un nombre de clase de objeto u OID delante del car\u00e1cter de almohadilla (#)
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR_206=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque la parte de criterios %s conten\u00eda un car\u00e1cter no v\u00e1lido %c en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN_207=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque la parte de criterios %s no conten\u00eda un par\u00e9ntesis de cierre que correspond\u00eda al par\u00e9ntesis de apertura inicial
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK_208=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque la parte de criterios %s comenzaba con un signo de interrogaci\u00f3n aunque no seguido por la cadena "true" (verdadero) o "false" (falso)
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR_209=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque la parte de criterios %s no conten\u00eda un signo de d\u00f3lar para separar el tipo de atributo del tipo de coincidencia
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR_210=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque la parte de criterios %s no especificaba un tipo de atributo delante del signo de d\u00f3lar
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE_211=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque la parte de criterios %s no especificaba un tipo de coincidencia detr\u00e1s del signo de d\u00f3lar
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE_212=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda porque la parte de criterios %s ten\u00eda un tipo de coincidencia no v\u00e1lido que comenzaba en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP_213=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque no conten\u00eda un car\u00e1cter de almohadilla (#) para separar la clase de objeto de los criterios
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC_214=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque no conten\u00eda un nombre de clase de objeto u OID delante del car\u00e1cter de almohadilla (#)
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID_215=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque el OID num\u00e9rico %s que especifica la clase de objeto conten\u00eda dos puntos consecutivos en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID_216=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque el OID num\u00e9rico %s que especifica la clase de objeto conten\u00eda un car\u00e1cter no v\u00e1lido %s  en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME_217=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque el nombre de clase de objeto %s conten\u00eda un car\u00e1cter no v\u00e1lido %s  en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP_218=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque no ten\u00eda un car\u00e1cter de almohadilla (#) para separar los criterios del \u00e1mbito
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE_219=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque no se proporcion\u00f3 ning\u00fan \u00e1mbito detr\u00e1s del car\u00e1cter almohadilla (#) final
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE_220=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque el \u00e1mbito %s especificado no era v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA_221=No se pudo analizar el valor proporcionado "%s" como valor de gu\u00eda mejorado porque no se especific\u00f3 ning\u00fan criterio entre los caracteres de almohadilla (#). 
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE_222=No se pudo analizar el valor proporcionado %s como OID v\u00e1lido: %s
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE_223=An unexpected \
+### error occurred while trying to normalize value %s as a generalized time \
+### value:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE_224=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseExactOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE_225=An error occurred while \
+### attempting to compare two objects using the caseExactOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE_226=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE_227=An error occurred while \
+### attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE_228=An error \
+### occurred while attempting to compare two AttributeValue objects using the \
+### generalizedTimeOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE_229=An error occurred \
+### while attempting to compare two objects using the \
+### generalizedTimeOrderingMatch matching rule because the objects were of an \
+### unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+### value objects may be compared
+###SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE_230=An error occurred while \
+### attempting to compare two AttributeValue objects using the \
+### integerOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE_231=An error occurred while \
+### attempting to compare two objects using the integerOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE_232=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### numericStringOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE_233=An error occurred \
+### while attempting to compare two objects using the numericStringOrderingMatch \
+### matching rule because the objects were of an unsupported type %s.  Only byte \
+### arrays, ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE_234=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### octetStringOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE_235=An error occurred while \
+### attempting to compare two objects using the octetStringOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH_236=The provided value "%s" has \
+### an invalid length for a UUID.  All UUID values must have a length of exactly \
+### 36 bytes, but the provided value had a length of %d bytes
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH_237=The provided value "%s" should \
+### have had a dash at position %d, but the character '%s' was found instead
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX_238=The provided value "%s" should \
+### have had a hexadecimal digit at position %d, but the character '%s' was found \
+### instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH_239=Indica si se permitir\u00e1 que los atributos con la sintaxis de cadena de directorios tengan valores de longitud cero.  Las especificaciones LDAP no lo permiten t\u00e9cnicamente, pero puede resultar \u00fatil para la compatibilidad de retroceso con versiones anteriores de Directory Server
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH_240=An \
+### error occurred while trying to determine the value of the %s configuration \
+### attribute, which indicates whether directory string attributes should be \
+### allowed to have zero-length values:  %s
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE_241=The \
+### operation attempted to assign a zero-length value to an attribute with the \
+### directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH_242=El %s atributo de la entrada de configuraci\u00f3n %s se ha actualizado con un nuevo valor de %s
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR_243=The provided \
+### authPassword value had an invalid scheme character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_244=The provided authPassword value \
+### had a zero-length scheme element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR_245=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the scheme and authInfo elements
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR_246=The provided \
+### authPassword value had an invalid authInfo character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_247=The provided authPassword \
+### value had a zero-length authInfo element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR_248=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the authInfo and authValue elements
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS_249=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### it did not start with a parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE_250=The provided value "%s" could not \
+### be parsed by the integer first component matching rule because it did not \
+### have any non-space characters after the opening parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT_251=The provided value "%s" \
+### could not be parsed by the integer first component matching rule because it \
+### did not have any space characters after the first component
+###SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT_252=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### the first component does not appear to be an integer value
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE_253=No value was given to decode by \
+### the user password attribute syntax
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE_254=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not start with the opening curly brace ("{") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE_255=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not contain a closing curly brace ("}") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME_256=Unable to decode the provided \
+### value according to the user password syntax because the value does not \
+### contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID_257=No se pudo analizar el valor proporcionado "%s" como especificaci\u00f3n de sub\u00e1rbol RFC 3672 v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID_258=No se pudo analizar el valor proporcionado "%s" como especificaci\u00f3n de sub\u00e1rbol absoluto v\u00e1lido
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID_259=No se pudo analizar el valor proporcionado "%s" como especificaci\u00f3n de sub\u00e1rbol relativo v\u00e1lido
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER_260=The provided value %s is not \
+### allowed for attributes with a Integer syntax
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR_261=The provided \
+### authPassword value had an invalid authValue character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE_262=The provided authPassword \
+### value had a zero-length authValue element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR_263=The provided \
+### authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER_264=No se pudo analizar el valor proporcionado "%s" como extensi\u00f3n de sintaxis de atributo porque se encontr\u00f3 un car\u00e1cter no v\u00e1lido en la posici\u00f3n %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION_265=No se pudo analizar la sintaxis de atributo debido a una extensi\u00f3n no v\u00e1lida.%s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE_266=The definition \
+### for objectclass %s is invalid because it has an objectclass type of %s but \
+### this is incompatible with the objectclass type %s for the superior class %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP_267=The \
+### definition for objectclass %s is invalid because it is defined as a \
+### structural class but its superior chain does not include the "top" \
+### objectclass
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
+### for attribute type %s is invalid because its attribute usage %s is not the \
+### same as the usage for its superior type %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \
+### definition for attribute type %s is invalid because it is defined as a \
+### collective type but the superior type %s is not collective
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
+### definition for attribute type %s is invalid because it is not defined as a \
+### collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=La regla de contenido del DIT "%s" no es v\u00e1lida porque proh\u00edbe el uso del tipo de atributo %s que necesita la clase de objeto estructural asociada %s
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=La regla de contenido del DIT "%s" no es v\u00e1lida porque proh\u00edbe el uso del tipo de atributo %s que necesita la clase de objeto auxiliar asociada %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \
+### for attribute type %s is invalid because it is declared COLLECTIVE but does \
+### not have a usage of userApplications
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \
+### definition for attribute type %s is invalid because it is declared \
+### NO-USER-MODIFICATION but does not have an operational usage
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR_275=The \
+### provided value %s is not a valid generalized time value because it contains \
+### illegal character %s in the fraction component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION_276=The provided \
+### value %s is not a valid generalized time value because it does not contain at \
+### least one digit after the period to use as the fractional component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO_277=The provided \
+### value %s is not a valid generalized time value because it does not end with \
+### 'Z' or a time zone offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME_278=The provided value \
+### %s is not a valid generalized time value because it represents an invalid \
+### time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED_279=No se pudo importar un elemento de esquema: %s, %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE_280=La regla de intercalaci\u00f3n %s que se encuentra en la entrada de regla de coincidencia %s no es v\u00e1lida, ya que JVM no admite la configuraci\u00f3n regional %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT_281=La regla de intercalaci\u00f3n proporcionada %s no contiene un formato v\u00e1lido de OID:CONFIGURACI\u00d3N REGIONAL
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=No se pudo analizar el valor proporcionado "%s" como nombre \u00fanico v\u00e1lido porque un valor de atributo empezaba con un car\u00e1cter en la posici\u00f3n %d al que hay que aplicarle caracteres de escape
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR_283=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de tipo de atributo v\u00e1lida porque no se permite el car\u00e1cter '%c' en la posici\u00f3n %d en un nombre de tipo de atributo
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_284=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de tipo de atributo v\u00e1lida porque no se permite el car\u00e1cter de subrayado en un nombre de tipo de atributo a menos que est\u00e9 habilitada la opci\u00f3n de configuraci\u00f3n %s
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_285=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de tipo de atributo v\u00e1lida porque no se permite el car\u00e1cter de gui\u00f3n como primer car\u00e1cter de un nombre de tipo de atributo
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_286=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de tipo de atributo v\u00e1lida porque no se permite el car\u00e1cter de subrayado como primer car\u00e1cter de un nombre de tipo de atributo, incluso si est\u00e1 habilitada la opci\u00f3n de configuraci\u00f3n %s 
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_287=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de tipo de atributo v\u00e1lida porque no se permite el d\u00edgito '%c' como primer car\u00e1cter de un nombre de tipo de atributo a menos que est\u00e9 especificado el nombre como un OID o que est\u00e9 habilitada la opci\u00f3n de configuraci\u00f3n %s
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR_288=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de clase de objeto v\u00e1lida porque no se permite el car\u00e1cter '%c' en la posici\u00f3n %d en un nombre de clase de objeto
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_289=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de clase de objeto v\u00e1lida porque no se permite el car\u00e1cter de subrayado en un nombre de clase de objeto a menos que est\u00e9 habilitada la opci\u00f3n de configuraci\u00f3n %s
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_290=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de clase de objeto v\u00e1lida porque no se permite el car\u00e1cter de gui\u00f3n como primer car\u00e1cter de un nombre de clase de objeto
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_291=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de clase de objeto v\u00e1lida porque no se permite el car\u00e1cter de subrayado como primer car\u00e1cter de un nombre de clase de objeto, incluso si est\u00e1 habilitada la opci\u00f3n de configuraci\u00f3n %s
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_292=No se pudo analizar el valor proporcionado "%s" como definici\u00f3n de clase de objeto v\u00e1lida porque no se permite el d\u00edgito '%c' como primer car\u00e1cter de un nombre de clase de objeto a menos que est\u00e9 especificado el nombre como un OID o que est\u00e9 habilitada la opci\u00f3n de configuraci\u00f3n %s
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_fr.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_fr.properties
new file mode 100755
index 0000000..6959d0b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_fr.properties
@@ -0,0 +1,531 @@
+# 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
+#
+#      Copyright 2009 Sun Microsystems, Inc.
+#
+# Global directives
+#
+global.ordinal=-1
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE_1=Unable to retrieve \
+### approximate matching rule %s used as the default for the %s attribute syntax. \
+### Approximate matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE_2=Unable to retrieve \
+### equality matching rule %s used as the default for the %s attribute syntax. \
+### Equality matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE_3=Unable to retrieve \
+### ordering matching rule %s used as the default for the %s attribute syntax. \
+### Ordering matches will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE_4=Unable to retrieve \
+### substring matching rule %s used as the default for the %s attribute syntax. \
+### Substring matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN_5=The provided value "%s" is not \
+### allowed for attributes with a Boolean syntax.  The only allowed values are \
+### 'TRUE' and 'FALSE'
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT_6=The provided value "%s" is too \
+### short to be a valid bit string.  A bit string must be a series of binary \
+### digits surrounded by single quotes and followed by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED_7=The provided value "%s" is not \
+### a valid bit string because it is not surrounded by single quotes and followed \
+### by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT_8=The provided value "%s" is \
+### not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=La valeur indiqu\u00e9e "%s" n'est pas une cha\u00eene de pays valide car elle n'a pas une longueur de deux caract\u00e8res exactement
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE_10=La valeur indiqu\u00e9e "%s" n'est pas une cha\u00eene de pays valide car elle contient au moins un caract\u00e8re non imprimable
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=La valeur indiqu\u00e9e "%s" n'est pas une m\u00e9thode de distribution valide car elle ne contient aucun \u00e9l\u00e9ment
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT_12=La valeur indiqu\u00e9e "%s" n'est pas une m\u00e9thode de distribution valide car "%s" n'est pas une m\u00e9thode valide
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT_13=The provided value "%s" \
+### is too short to be a valid generalized time value
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR_14=The provided value \
+### "%s" is not a valid generalized time value because the '%s' character is not \
+### allowed in the century or year specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH_15=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid month \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY_16=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid day \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR_17=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid hour \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE_18=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid minute \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND_19=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid second \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND_20=The provided \
+### value "%s" is not a valid generalized time value because the sub-second \
+### component is not valid (between 1 and 3 numeric digits)
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND_21=The provided value \
+### "%s" is not a valid generalized time value because the sub-second value may \
+### not contain more than three digits
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET_22=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+### offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR_23=The provided value \
+### "%s" is not a valid generalized time value because it contains an invalid \
+### character '%s' at position %d
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE_24=The provided value \
+### "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_25=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide\u00a0:  %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA_26=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le dernier caract\u00e8re autre qu'un espace est une virgule ou un point-virgule
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT_27=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le chiffre num\u00e9rique "%s" n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom d'attribut
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR_28=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le caract\u00e8re '%c' \u00e0 la position %d n'est pas autoris\u00e9 dans un nom d'attribut
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR_29=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le trait de soulignement n'est pas autoris\u00e9 dans un nom d'attribut, sauf si l'option de configuration %s est activ\u00e9e 
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH_30=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le trait d'union n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom d'attribut
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE_31=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le tiret de soulignement n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom d'attribut, m\u00eame si l'option de configuration %s est activ\u00e9e 
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT_32=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le chiffre '%c' n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom d'attribut, sauf si le nom est sp\u00e9cifi\u00e9 comme un OID ou que l'option de configuration %s est activ\u00e9e 
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME_33=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car il contient un NRD contenant un nom d'attribut vide
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD_34=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le nom d'attribut analys\u00e9 %s inclut un point mais ne semble pas \u00eatre un OID valide
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME_35=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le dernier caract\u00e8re autre qu'un espace fait partie du nom d'attribut '%s'
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL_36=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le caract\u00e8re suivant autre qu'un espace apr\u00e8s le nom d'attribut "%s" devrait \u00eatre un signe \u00e9gal au lieu de '%c'
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR_37=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le caract\u00e8re '%c' \u00e0 la position %d n'est pas valide
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT_38=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car une valeur d'attribut commence par un di\u00e8se (#) sans \u00eatre suivie d'un multiple positif de deux chiffres hexad\u00e9cimaux 
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT_39=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car une valeur d'attribut commence par un di\u00e8se (#) mais contient un caract\u00e8re %c qui n'est pas un chiffre hexad\u00e9cimal valide
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE_40=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car un \u00e9chec inattendu s'est produit lors d'une tentative d'analyse d'une valeur d'attribut de l'un des composants du NRD\u00a0:  "%s" 
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE_41=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car un des composants du NRD inclut une valeur cit\u00e9e sans le guillemet de fermeture correspondant
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID_42=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car un des composants du NRD inclut une valeur contenant un chiffre hexad\u00e9cimal neutralis\u00e9 qui n'est pas suivi d'un second chiffre hexad\u00e9cimal
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO_43=The provided value "%s" could \
+### not be parsed as a valid integer because the first digit may not be zero \
+### unless it is the only digit
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH_44=The provided value "%s" \
+### could not be parsed as a valid integer because the dash may only appear if it \
+### is the first character of the value followed by one or more digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER_45=The provided value "%s" \
+### could not be parsed as a valid integer because character '%c' at position %d \
+### is not allowed in an integer value
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE_46=The provided value "%s" could \
+### not be parsed as a valid integer because it did not contain any digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE_47=The provided value "%s" \
+### could not be parsed as a valid integer because it contained only a dash not \
+### followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE_48=Impossible d'analyser la valeur indiqu\u00e9e en tant qu'OID valide car il ne contient aucun caract\u00e8re
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER_49=Impossible d'analyser la valeur indiqu\u00e9e %s en tant qu'OID valide car il contient un caract\u00e8re ill\u00e9gal \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS_50=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'OID valide car il contient deux points cons\u00e9cutifs \u00e0 la position %d ou \u00e0 proximit\u00e9
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD_51=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'OID valide car il se termine par un point
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE_52=Impossible d'analyser la valeur indiqu\u00e9e en tant que description de type d'attribut valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS_53=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE_54=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID_55=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID_56=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID_57=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car l'OID non num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_58=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car elle contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS_59=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_60=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de type d'attribut car le premier caract\u00e8re non vide suivant un jeton %s devrait \u00eatre un guillemet simple et non le caract\u00e8re %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE_61=The definition for \
+### the attribute type with OID %s declared a superior type with an OID of %s. \
+### No attribute type with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR_62=The definition for \
+### the attribute type with OID %s declared that approximate matching should be \
+### performed using the matching rule "%s".  No such approximate matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR_63=The definition for \
+### the attribute type with OID %s declared that equality matching should be \
+### performed using the matching rule "%s".  No such equality matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR_64=The definition for \
+### the attribute type with OID %s declared that ordering matching should be \
+### performed using the matching rule "%s".  No such ordering matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR_65=The definition for \
+### the attribute type with OID %s declared that substring matching should be \
+### performed using the matching rule "%s".  No such substring matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX_66=The definition for the \
+### attribute type with OID %s declared that it should have a syntax with OID %s. \
+### No such syntax is configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE_67=The definition \
+### for the attribute type with OID %s declared that it should have an attribute \
+### usage of %s.  This is an invalid usage
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS_68=The provided value \
+### "%s" could not be parsed as an attribute type description because a single \
+### quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE_69=Impossible d'analyser la valeur indiqu\u00e9e en tant que description de classe d'objet valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS_70=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE_71=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID_72=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID_73=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID_74=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car l'OID non num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_75=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car elle contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS_76=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_77=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de classe d'objet car le premier caract\u00e8re non vide suivant un jeton %s devrait \u00eatre un guillemet simple et non le caract\u00e8re %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS_78=The definition \
+### for the objectclass with OID %s declared a superior objectclass with an OID \
+### of %s.  No objectclass with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS_79=The provided \
+### value "%s" could not be parsed as an objectclass description because a single \
+### quote was expected at position %d but the character %s was found instead
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR_80=The definition \
+### for the objectclass with OID %s declared that it should include required \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR_81=The definition \
+### for the objectclass with OID %s declared that it should include optional \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER_82=The provided value "%s" \
+### cannot be parsed as a valid IA5 string because it contains an illegal \
+### character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE_83=Ceci indique si la syntaxe d'attribut de num\u00e9ro de t\u00e9l\u00e9phone doit utiliser un mode strict dans lequel seules les valeurs au format ITU-T E.123 seront accept\u00e9es.  Si cette option est activ\u00e9e, toutes les valeurs dans un autre format seront refus\u00e9es.  Si elle est d\u00e9sactiv\u00e9e, toutes les valeurs seront accept\u00e9es mais seuls les chiffres sont pris en compte lors de la recherche de correspondance 
+###SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE_84=An error \
+### occurred while trying to retrieve attribute \
+### ds-cfg-strict-format from configuration entry %s:  %s.  The \
+### Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+### for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY_85=La valeur indiqu\u00e9e n'est pas un num\u00e9ro de t\u00e9l\u00e9phone valide car elle est vide ou null
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS_86=La valeur indiqu\u00e9e "%s" n'est pas un num\u00e9ro de t\u00e9l\u00e9phone valide car la v\u00e9rification stricte des num\u00e9ros de t\u00e9l\u00e9phone est activ\u00e9e et la valeur ne commence pas par un signe plus respectant la sp\u00e9cification ITU-T E.123
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR_87=La valeur indiqu\u00e9e "%s" n'est pas un num\u00e9ro de t\u00e9l\u00e9phone valide car la v\u00e9rification stricte des num\u00e9ros de t\u00e9l\u00e9phone est activ\u00e9e et le caract\u00e8re %s \u00e0 la position %d n'est pas autoris\u00e9 par la sp\u00e9cification ITU-T E.123
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS_88=La valeur indiqu\u00e9e "%s" n'est pas un num\u00e9ro de t\u00e9l\u00e9phone valide car il ne contient aucun chiffre num\u00e9rique
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE_89=La valeur de l'attribut de configuration ds-cfg-strict-format, qui indique si la v\u00e9rification stricte des num\u00e9ros de t\u00e9l\u00e9phone doit \u00eatre utilis\u00e9e, a \u00e9t\u00e9 mise \u00e0 jour sur %s dans l'entr\u00e9e de configuration %s
+###SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR_90=The provided value \
+### "%s" is not a valid numeric string because it contained character %s at \
+### position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE_91=La valeur indiqu\u00e9e n'est pas une cha\u00eene num\u00e9rique valide car elle ne contient aucun caract\u00e8re.  Une valeur de cha\u00eene num\u00e9rique doit contenir au moins un chiffre num\u00e9rique ou un espace
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE_92=Impossible d'analyser la valeur indiqu\u00e9e en tant que description de syntaxe d'attribut valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS_93=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE_94=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID_95=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID_96=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID_97=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car l'OID non num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS_98=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN_99=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car une erreur inattendue s'est produite lors de la tentative de lecture du jeton "DESC" \u00e0 partir de la cha\u00eene ou pr\u00e8s de la position %d\u00a0:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC_100=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car le jeton "DESC" devrait \u00eatre pr\u00e9sent au lieu de la cha\u00eene "%s"
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE_101=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car une erreur inattendue s'est produite lors de la tentative de lecture de la valeur du jeton "DESC" \u00e0 partir de la cha\u00eene ou pr\u00e8s de la position %d\u00a0:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS_102=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car une parenth\u00e8se ferm\u00e9e devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE_103=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de syntaxe d'attribut car un caract\u00e8re ill\u00e9gal %s se trouve \u00e0 la position %d apr\u00e8s la parenth\u00e8se ferm\u00e9e
+###SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS_104=The provided \
+### value "%s" could not be parsed as an attribute syntax description because a \
+### single quote was expected at position %d but the character %s was found \
+### instead
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE_105=The provided value \
+### could not be parsed as a printable string because it was null or empty.  A \
+### printable string must contain at least one character
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER_106=The provided \
+### value "%s" could not be parsed as a printable string because it contained an \
+### invalid character %s at position %d
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD_107=The provided value "*" \
+### could not be parsed as a substring assertion because it consists only of a \
+### wildcard character and zero-length substrings are not allowed
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS_108=The provided \
+### value "%s" could not be parsed as a substring assertion because it contains \
+### consecutive wildcard characters at position %d and zero-length substrings are \
+### not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT_109=La valeur indiqu\u00e9e %s est trop courte pour \u00eatre une valeur de temps UTC valide
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR_110=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car le caract\u00e8re '%s' n'est pas autoris\u00e9 dans la sp\u00e9cification de si\u00e8cle ou d'ann\u00e9e
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH_111=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car %s n'est pas une sp\u00e9cification de mois valide
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY_112=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car %s n'est pas une sp\u00e9cification de jour valide
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR_113=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car %s n'est pas une sp\u00e9cification d'heure valide
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE_114=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car %s n'est pas une sp\u00e9cification de minute valide
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR_115=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car elle contient un caract\u00e8re invalide %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND_116=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car %s n'est pas une sp\u00e9cification de seconde valide
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET_117=La valeur indiqu\u00e9e %s n'est pas une valeur de temps UTC valide car %s n'est pas un d\u00e9calage GMT valide
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE_118=Impossible d'analyser la valeur indiqu\u00e9e %s en tant que temps UTC valide\u00a0:  %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE_119=Impossible d'analyser la valeur indiqu\u00e9e en tant que description de r\u00e8gle de contenu DIT valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS_120=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE_121=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID_122=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID_123=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID_124=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car l'OID non num\u00e9rique contenient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS_125=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_126=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car elle contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS_127=La r\u00e8gle de contenu DIT "%s" est associ\u00e9e \u00e0 une classe d'objet structurelle %s non d\u00e9finie dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL_128=La r\u00e8gle de contenu DIT "%s" est associ\u00e9e \u00e0 la classe d'objet avec OID %s (%s).  Cette classe d'objet existe dans le sch\u00e9ma de serveur mais est plut\u00f4t d\u00e9finie comme %s que comme structurelle 
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS_129=La r\u00e8gle de contenu DIT "%s" est associ\u00e9e \u00e0 une classe d'objet auxiliaire %s non d\u00e9finie dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY_130=La r\u00e8gle de contenu DIT "%s" est associ\u00e9e \u00e0 une classe d'objet auxiliaire %s. Cette classe d'objet existe dans le sch\u00e9ma de serveur mais est d\u00e9finie comme %s plut\u00f4t que comme auxiliaire
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR_131=La r\u00e8gle de contenu DIT "%s" est associ\u00e9e \u00e0 un type d'attribut requis %s non d\u00e9fini dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR_132=La r\u00e8gle de contenu DIT "%s" est associ\u00e9e \u00e0 un type d'attribut facultatif %s non d\u00e9fini dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR_133=La r\u00e8gle de contenu DIT "%s" est associ\u00e9e \u00e0 un type d'attribut interdit %s non d\u00e9fini dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS_134=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de contenu DIT car un guillemet simple aurait d\u00fb se trouver \u00e0 la position %d au lieu du caract\u00e8re %s
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE_135=Impossible d'analyser la valeur indiqu\u00e9e en tant que description de formulaire de nom valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS_136=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%c'
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE_137=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID_138=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID_139=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %c \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID_140=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car l'OID non num\u00e9rique contient un caract\u00e8re ill\u00e9gal %c \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS_141=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_142=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car elle contient un caract\u00e8re ill\u00e9gal %c \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS_143=La description de formulaire de nom "%s" est associ\u00e9e \u00e0 une classe d'objet structurelle %s non d\u00e9finie dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL_144=La description de formulaire de nom "%s" est associ\u00e9e \u00e0 la classe d'objet avec OID %s (%s). Cette classe d'objet existe dans le sch\u00e9ma de serveur mais est plut\u00f4t d\u00e9finie comme %s que comme structurelle 
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR_145=La d\u00e9finition pour le formulaire de nom avec l'OID %s d\u00e9clare qu'il devrait inclure l'attribut requis "%s".  Aucun type d'attribut correspondant \u00e0 ce nom ou cet OID n'existe dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR_146=La d\u00e9finition pour le formulaire de nom avec l'OID %s d\u00e9clare qu'elle devrait inclure l'attribut facultatif "%s".  Aucun type d'attribut correspondant \u00e0 ce nom ou cet OID n'existe dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS_147=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car elle ne sp\u00e9cifie pas la classe d'objet structurelle avec laquelle elle est associ\u00e9e
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS_148=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de formulaire de nom car un guillemet simple devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re %c
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE_149=Impossible d'analyser la valeur indiqu\u00e9e en tant que description de r\u00e8gle de correspondance valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS_150=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE_151=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID_152=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID_153=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID_154=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car l'OID non num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS_155=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_156=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car elle contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX_157=La description de r\u00e8gle de correspondance "%s" est associ\u00e9e \u00e0 une syntaxe d'attribut %s non d\u00e9finie dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX_158=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car elle ne sp\u00e9cifie par la syntaxe d'attribut avec laquelle elle est associ\u00e9e
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS_159=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car un guillemet simple devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re %s
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE_160=Impossible d'analyser la valeur indiqu\u00e9e en tant que description d'utilisation d'une r\u00e8gle de correspondance valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS_161=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE_162=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID_163=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID_164=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID_165=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car l'OID non num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE_166=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car la r\u00e8gle de correspondance %s est inconnue
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS_167=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_168=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car elle contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR_169=La description d'utilisation d'une r\u00e8gle de correspondance "%s" est associ\u00e9e \u00e0 un type d'attribut %s non d\u00e9fini dans le sch\u00e9ma de serveur
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR_170=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de correspondance car elle ne sp\u00e9cifie pas l'ensemble de types d'attributs \u00e0 utiliser avec l'OID associ\u00e9
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS_171=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description d'utilisation d'une r\u00e8gle de correspondance car un guillemet simple devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re %s
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE_172=Impossible d'analyser la valeur indiqu\u00e9e en tant que description de r\u00e8gle de structure DIT valide car elle est vide ou ne contient que des blancs
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS_173=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car une parenth\u00e8se ouverte devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re '%s'
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE_174=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car la fin de la valeur est atteinte alors que Directory Server attend plus de donn\u00e9es
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID_175=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car la r\u00e8gle DIT contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS_176=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car elle contient une parenth\u00e8se de fermeture inattendue \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_177=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car elle contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM_178=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car elle fait r\u00e9f\u00e9rence \u00e0 une forme de nom inconnu %s
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID_179=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car elle fait r\u00e9f\u00e9rence \u00e0 un ID %d de r\u00e8gle inconnu pour une r\u00e8gle de structure DIT sup\u00e9rieure
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM_180=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car elle ne sp\u00e9cifie par le formulaire de nom pour la r\u00e8gle
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS_181=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car un guillemet simple devrait se trouver \u00e0 la position %d au lieu du caract\u00e8re %s
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID_182=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car l'OID num\u00e9rique contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID_183=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car l'OID num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID_184=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que description de r\u00e8gle de structure DIT car l'OID non num\u00e9rique contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT_185=La valeur indiqu\u00e9e "%s" est trop courte pour \u00eatre une valeur de num\u00e9ro de t\u00e9lex valide
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE_186=La valeur indiqu\u00e9e "%s" ne contient pas un num\u00e9ro de t\u00e9lex valide car un caract\u00e8re %s \u00e0 la position %d n'est pas une cha\u00eene de caract\u00e8res imprimable valide
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR_187=La valeur indiqu\u00e9e "%s" ne contient pas un num\u00e9ro de t\u00e9lex valide car un caract\u00e8re %s \u00e0 la position %d n'est ni une cha\u00eene de caract\u00e8res imprimable valide, ni le signe du dollar pour s\u00e9parer les composants du num\u00e9ro de t\u00e9lex
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED_188=La valeur indiqu\u00e9e "%s" ne contient pas un num\u00e9ro de t\u00e9lex valide car la fin de la valeur a \u00e9t\u00e9 atteinte avant que trois cha\u00eenes imprimables d\u00e9limit\u00e9s par des dollars puissent \u00eatre lues
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY_189=Impossible d'analyser la valeur indiqu\u00e9e en tant que num\u00e9ro de t\u00e9l\u00e9copie valide car elle est vide
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE_190=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que num\u00e9ro de t\u00e9l\u00e9copie valide car le caract\u00e8re %s \u00e0 la position %d n'est pas une cha\u00eene de caract\u00e8res imprimable valide
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR_191=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que num\u00e9ro de t\u00e9l\u00e9copie valide car elle termine par un signe dollar, mais ce signe devrait \u00eatre suivi d'un param\u00e8tre de fax
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER_192=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que num\u00e9ro de t\u00e9l\u00e9copie valide car la cha\u00eene "%s" entre les positions %d et %d n'est pas un param\u00e8tre de fax valide
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN_193=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom et valeur UID facultative valides car une erreur s'est produite lors de la tentative d'analyse de la partie DN\u00a0:  %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT_194=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom et valeur UID facultative valides car la partie UID contient un chiffre binaire ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY_195=Impossible d'analyser la valeur indiqu\u00e9e en tant qu'identifiant de r\u00e9cepteur de teletexte valide car elle est vide
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE_196=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'identifiant de r\u00e9cepteur de teletexte valide car le caract\u00e8re %s \u00e0 la position %d n'est pas une cha\u00eene de caract\u00e8res imprimable valide
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR_197=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'identifiant de r\u00e9cepteur de teletexte valide car elle se termine par le symbole dollar, mais ce symbole devrait \u00eatre suivi d'un param\u00e8tre TTX
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON_198=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'identifiant de r\u00e9cepteur de teletexte valide car la cha\u00eene de param\u00e8tres ne contient pas deux-points pour s\u00e9parer le nom de la valeur
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER_199=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'identifiant de r\u00e9cepteur de teletexte valide car "%s" n'est pas un nom de param\u00e8tre TTX valide
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE_200=Impossible d'analyser la valeur indiqu\u00e9e en tant qu'autre valeur de bo\u00eete aux lettres car elle est vide 
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE_201=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'autre valeur de bo\u00eete aux lettres car il n'y a pas de type de bo\u00eete aux lettres avant le symbole dollar
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR_202=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'autre valeur de bo\u00eete aux lettres car le type de bo\u00eete aux lettres contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX_203=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'autre valeur de bo\u00eete aux lettres car il n'y a pas de bo\u00eete aux lettres apr\u00e8s le symbole dollar
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR_204=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'autre valeur de bo\u00eete aux lettres car la bo\u00eete aux lettres contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC_205=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car elle ne contient pas de nom de classe d'objet ni d'OID avant le caract\u00e8re di\u00e8se (#)
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR_206=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car la partie crit\u00e8res %s contient un caract\u00e8re ill\u00e9gal %c \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN_207=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car la partie crit\u00e8res %s ne contient pas de parenth\u00e8se ferm\u00e9e correspondant \u00e0 la parenth\u00e8se ouverte initiale
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK_208=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car la partie crit\u00e8res %s commence par une interrogation mais n'est pas suivie de la cha\u00eene "true" ou "false" 
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR_209=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car la partie crit\u00e8res %s ne contient pas de signe dollar pour s\u00e9parer le type d'attribut du type de correspondance
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR_210=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car la partie crit\u00e8res %s ne sp\u00e9cifiait pas de type d'attribut avant le signe dollar
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE_211=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car la partie crit\u00e8res  %s ne sp\u00e9cifie pas de type de correspondance apr\u00e8s le symbole dollar
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE_212=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide car la partie crit\u00e8res %s a un type de correspondance ill\u00e9gal commen\u00e7ant \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP_213=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car elle ne contient pas de caract\u00e8re di\u00e8se (#) pour s\u00e9parer la classe d'objet des crit\u00e8res
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC_214=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car elle ne contient pas de nom de classe d'objet ou d'OID avant le caract\u00e8re di\u00e8se (#)
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID_215=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car l'OID num\u00e9rique %s sp\u00e9cifiant la classe d'objet contient deux points cons\u00e9cutifs \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID_216=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car l'OID num\u00e9rique %s sp\u00e9cifiant la classe d'objet contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME_217=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car le nom de classe d'objet %s contient un caract\u00e8re ill\u00e9gal %s \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP_218=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car elle n'a pas de caract\u00e8re di\u00e8se (#) pour s\u00e9parer les crit\u00e8res du domaine
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE_219=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car aucun domaine n'est indiqu\u00e9 apr\u00e8s le caract\u00e8re di\u00e8se (#) final 
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE_220=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car le domaine sp\u00e9cifi\u00e9 %s n'est pas valide
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA_221=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que valeur guide optimis\u00e9e car elle ne sp\u00e9cifie pas de crit\u00e8res entre les catact\u00e8res di\u00e8se (#)
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE_222=Impossible d'analyser la valeur indiqu\u00e9e %s en tant qu'OID valide\u00a0:  %s
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE_223=An unexpected \
+### error occurred while trying to normalize value %s as a generalized time \
+### value:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE_224=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseExactOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE_225=An error occurred while \
+### attempting to compare two objects using the caseExactOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE_226=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE_227=An error occurred while \
+### attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE_228=An error \
+### occurred while attempting to compare two AttributeValue objects using the \
+### generalizedTimeOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE_229=An error occurred \
+### while attempting to compare two objects using the \
+### generalizedTimeOrderingMatch matching rule because the objects were of an \
+### unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+### value objects may be compared
+###SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE_230=An error occurred while \
+### attempting to compare two AttributeValue objects using the \
+### integerOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE_231=An error occurred while \
+### attempting to compare two objects using the integerOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE_232=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### numericStringOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE_233=An error occurred \
+### while attempting to compare two objects using the numericStringOrderingMatch \
+### matching rule because the objects were of an unsupported type %s.  Only byte \
+### arrays, ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE_234=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### octetStringOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE_235=An error occurred while \
+### attempting to compare two objects using the octetStringOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH_236=The provided value "%s" has \
+### an invalid length for a UUID.  All UUID values must have a length of exactly \
+### 36 bytes, but the provided value had a length of %d bytes
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH_237=The provided value "%s" should \
+### have had a dash at position %d, but the character '%s' was found instead
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX_238=The provided value "%s" should \
+### have had a hexadecimal digit at position %d, but the character '%s' was found \
+### instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH_239=Indique si les attributs avec la syntaxe de cha\u00eene d'annuaires sont autoris\u00e9s \u00e0 avoir des valeurs de longueur null.  Cette option n'est pas techniquement autoris\u00e9e par les sp\u00e9cifications LDAP, mais elle pourrait \u00eatre utile pour la compatibilit\u00e9 ascendante avec les versions pr\u00e9c\u00e9dentes de Directory Server 
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH_240=An \
+### error occurred while trying to determine the value of the %s configuration \
+### attribute, which indicates whether directory string attributes should be \
+### allowed to have zero-length values:  %s
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE_241=The \
+### operation attempted to assign a zero-length value to an attribute with the \
+### directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH_242=L'attribut %s dans l'entr\u00e9e de configuration %s a \u00e9t\u00e9 mis \u00e0 jour avec une nouvelle valeur de %s
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR_243=The provided \
+### authPassword value had an invalid scheme character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_244=The provided authPassword value \
+### had a zero-length scheme element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR_245=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the scheme and authInfo elements
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR_246=The provided \
+### authPassword value had an invalid authInfo character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_247=The provided authPassword \
+### value had a zero-length authInfo element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR_248=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the authInfo and authValue elements
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS_249=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### it did not start with a parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE_250=The provided value "%s" could not \
+### be parsed by the integer first component matching rule because it did not \
+### have any non-space characters after the opening parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT_251=The provided value "%s" \
+### could not be parsed by the integer first component matching rule because it \
+### did not have any space characters after the first component
+###SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT_252=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### the first component does not appear to be an integer value
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE_253=No value was given to decode by \
+### the user password attribute syntax
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE_254=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not start with the opening curly brace ("{") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE_255=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not contain a closing curly brace ("}") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME_256=Unable to decode the provided \
+### value according to the user password syntax because the value does not \
+### contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID_257=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que sp\u00e9cification de sous-arborescence RFC 3672 valide
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID_258=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que sp\u00e9cification de sous-arborescence absolue valide
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID_259=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que sp\u00e9cification de sous-arborescence relative valide
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER_260=The provided value %s is not \
+### allowed for attributes with a Integer syntax
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR_261=The provided \
+### authPassword value had an invalid authValue character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE_262=The provided authPassword \
+### value had a zero-length authValue element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR_263=The provided \
+### authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER_264=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant qu'extension de syntaxe d'attribut car un caract\u00e8re invalide se trouve \u00e0 la position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION_265=Impossible d'analyser la syntaxe d'attribut \u00e0 cause d'une extension invalide.%s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE_266=The definition \
+### for objectclass %s is invalid because it has an objectclass type of %s but \
+### this is incompatible with the objectclass type %s for the superior class %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP_267=The \
+### definition for objectclass %s is invalid because it is defined as a \
+### structural class but its superior chain does not include the "top" \
+### objectclass
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
+### for attribute type %s is invalid because its attribute usage %s is not the \
+### same as the usage for its superior type %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \
+### definition for attribute type %s is invalid because it is defined as a \
+### collective type but the superior type %s is not collective
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
+### definition for attribute type %s is invalid because it is not defined as a \
+### collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=La r\u00e8gle de contenu DIT "%s" n'est pas valide car elle interdit l'utilisation du type d'attribut %s requis par la classe d'objet structurelle associ\u00e9e %s
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=La r\u00e8gle de contenu DIT "%s" n'est pas valide car elle interdit l'utilisation du type d'attribut %s requis par la classe d'objet structurelle auxiliaire %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \
+### for attribute type %s is invalid because it is declared COLLECTIVE but does \
+### not have a usage of userApplications
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \
+### definition for attribute type %s is invalid because it is declared \
+### NO-USER-MODIFICATION but does not have an operational usage
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR_275=The \
+### provided value %s is not a valid generalized time value because it contains \
+### illegal character %s in the fraction component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION_276=The provided \
+### value %s is not a valid generalized time value because it does not contain at \
+### least one digit after the period to use as the fractional component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO_277=The provided \
+### value %s is not a valid generalized time value because it does not end with \
+### 'Z' or a time zone offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME_278=The provided value \
+### %s is not a valid generalized time value because it represents an invalid \
+### time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED_279=Un \u00e9l\u00e9ment de sch\u00e9ma ne peut \u00eatre import\u00e9\u00a0: %s, %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE_280=La r\u00e8gle de classement %s sous la r\u00e8gle de correspondance %s est invalide car la variable locale %s n'est pas prise en charge par la JVM
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT_281=La r\u00e8gle de classement fournie %s ne contient pas de format valide de OID LOCALE
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=Impossible d'analyser la valeur fournie "%s" en tant que nom valide distinctif car la valeur de l'attribut commence avec un caract\u00e8re en position %d qui doit \u00eatre \u00e9vit\u00e9
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR_283=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le caract\u00e8re '%c' \u00e0 la position %d n'est pas autoris\u00e9 dans un nom de type d'attribut
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_284=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le trait de soulignement n'est pas autoris\u00e9 dans un nom de type d'attribut, sauf si l'option de configuration %s est activ\u00e9e 
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_285=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que nom distinctif valide car le trait d'union n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom de type d'attribut
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_286=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que d\u00e9finition de type d'attribut car le tiret de soulignement n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom de type d'attribut, m\u00eame si l'option de configuration %s est activ\u00e9e 
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_287=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que d\u00e9finition de type d'attribut car le chiffre '%c' n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom d'attribut, sauf si le nom est sp\u00e9cifi\u00e9 comme un OID ou que l'option de configuration %s est activ\u00e9e 
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR_288=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que d\u00e9finition de classe d'objet car le caract\u00e8re '%c' \u00e0 la position %d n'est pas autoris\u00e9 dans un nom de classe d'objet
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_289=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que d\u00e9finition de classe d'objet car le trait de soulignement n'est pas autoris\u00e9 dans un nom de classe d'objet, sauf si l'option de configuration %s est activ\u00e9e 
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_290=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que d\u00e9finition de classe d'objet car le trait d'union n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom de classe d'objet
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_291=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que d\u00e9finition de classe d'objet car le tiret de soulignement n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'un nom de classe d'objet, m\u00eame si l'option de configuration %s est activ\u00e9e 
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_292=Impossible d'analyser la valeur indiqu\u00e9e "%s" en tant que d\u00e9finition de classe d'objet car le chiffre '%c' n'est pas autoris\u00e9 en tant que premier caract\u00e8re d'une classe d'objet, sauf si le nom est sp\u00e9cifi\u00e9 comme un OID ou que l'option de configuration %s est activ\u00e9e 
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ja.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ja.properties
new file mode 100755
index 0000000..5ef2ca8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ja.properties
@@ -0,0 +1,531 @@
+# 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
+#
+#      Copyright 2009 Sun Microsystems, Inc.
+#
+# Global directives
+#
+global.ordinal=-1
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE_1=Unable to retrieve \
+### approximate matching rule %s used as the default for the %s attribute syntax. \
+### Approximate matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE_2=Unable to retrieve \
+### equality matching rule %s used as the default for the %s attribute syntax. \
+### Equality matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE_3=Unable to retrieve \
+### ordering matching rule %s used as the default for the %s attribute syntax. \
+### Ordering matches will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE_4=Unable to retrieve \
+### substring matching rule %s used as the default for the %s attribute syntax. \
+### Substring matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN_5=The provided value "%s" is not \
+### allowed for attributes with a Boolean syntax.  The only allowed values are \
+### 'TRUE' and 'FALSE'
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT_6=The provided value "%s" is too \
+### short to be a valid bit string.  A bit string must be a series of binary \
+### digits surrounded by single quotes and followed by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED_7=The provided value "%s" is not \
+### a valid bit string because it is not surrounded by single quotes and followed \
+### by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT_8=The provided value "%s" is \
+### not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u3001\u9577\u3055\u304c\u6b63\u78ba\u306b 2 \u6587\u5b57\u3067\u306f\u306a\u3044\u305f\u3081\u3001\u6709\u52b9\u306a\u56fd\u6587\u5b57\u5217\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE_10=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u3001\u30d7\u30ea\u30f3\u30c8\u4e0d\u53ef\u80fd\u306a\u6587\u5b57\u304c 1 \u3064\u4ee5\u4e0a\u542b\u307e\u308c\u308b\u305f\u3081\u3001\u6709\u52b9\u306a\u56fd\u6587\u5b57\u5217\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u3001\u8981\u7d20\u304c\u4e00\u5207\u542b\u307e\u308c\u3066\u3044\u306a\u3044\u305f\u3081\u3001\u6709\u52b9\u306a\u5b9f\u65bd\u30e1\u30bd\u30c3\u30c9\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT_12="%2$s" \u306f\u6709\u52b9\u306a\u30e1\u30bd\u30c3\u30c9\u3067\u306f\u306a\u3044\u305f\u3081\u3001\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u306f\u6709\u52b9\u306a\u5b9f\u65bd\u30e1\u30bd\u30c3\u30c9\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT_13=The provided value "%s" \
+### is too short to be a valid generalized time value
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR_14=The provided value \
+### "%s" is not a valid generalized time value because the '%s' character is not \
+### allowed in the century or year specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH_15=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid month \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY_16=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid day \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR_17=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid hour \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE_18=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid minute \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND_19=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid second \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND_20=The provided \
+### value "%s" is not a valid generalized time value because the sub-second \
+### component is not valid (between 1 and 3 numeric digits)
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND_21=The provided value \
+### "%s" is not a valid generalized time value because the sub-second value may \
+### not contain more than three digits
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET_22=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+### offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR_23=The provided value \
+### "%s" is not a valid generalized time value because it contains an invalid \
+### character '%s' at position %d
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE_24=The provided value \
+### "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_25=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f:  %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA_26=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6700\u5f8c\u306e\u7a7a\u767d\u3067\u306a\u3044\u6587\u5b57\u304c\u30b3\u30f3\u30de\u307e\u305f\u306f\u30bb\u30df\u30b3\u30ed\u30f3\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT_27=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5b57 '%s' \u3092\u5c5e\u6027\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR_28=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 '%2$c' \u3092\u5c5e\u6027\u540d\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR_29=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002%s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u3067\u306a\u3044\u304b\u304e\u308a\u3001\u5c5e\u6027\u540d\u306b\u4e0b\u7dda\u6587\u5b57\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH_30=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30cf\u30a4\u30d5\u30f3\u6587\u5b57\u3092\u5c5e\u6027\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE_31=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002%s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u306a\u5834\u5408\u3067\u3082\u3001\u4e0b\u7dda\u6587\u5b57\u3092\u5c5e\u6027\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT_32=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u540d\u524d\u304c OID \u3068\u3057\u3066\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u304b\u3001%3$s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u3067\u306a\u3044\u304b\u304e\u308a\u3001\u6570\u5b57 '%2$c' \u3092\u5c5e\u6027\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME_33=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306b\u306f\u7a7a\u306e\u5c5e\u6027\u540d\u3092\u542b\u3080 RDN \u304c\u5b58\u5728\u3057\u3066\u3044\u305f\u305f\u3081\u3001\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD_34=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u89e3\u6790\u3055\u308c\u305f\u5c5e\u6027\u540d %s \u306b\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u3053\u306e\u540d\u524d\u306f\u6709\u52b9\u306a OID \u3067\u306f\u306a\u3044\u3088\u3046\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME_35=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6700\u5f8c\u306e\u7a7a\u767d\u4ee5\u5916\u306e\u6587\u5b57\u304c\u5c5e\u6027\u540d '%s' \u306e\u4e00\u90e8\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL_36=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u5c5e\u6027\u540d "%s" \u306e\u6b21\u306e\u7a7a\u767d\u4ee5\u5916\u306e\u6587\u5b57\u306f\u7b49\u53f7\u3067\u3042\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%c' \u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR_37=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 '%2$c' \u304c\u6709\u52b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT_38=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u5c5e\u6027\u5024\u306f\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u3067\u59cb\u307e\u3063\u3066\u3044\u307e\u3059\u304c\u3001\u7d9a\u304f\u6587\u5b57\u304c 2 \u6841\u306e 16 \u9032\u6570\u306e\u8907\u6570\u306e\u7d44\u307f\u5408\u308f\u305b\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT_39=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u5c5e\u6027\u5024\u306f\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u3067\u59cb\u307e\u3063\u3066\u3044\u307e\u3059\u304c\u3001\u6709\u52b9\u306a 16 \u9032\u6570\u3067\u306a\u3044\u6587\u5b57 %c \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE_40=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u3044\u305a\u308c\u304b\u306e RDN \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304b\u3089\u306e\u5c5e\u6027\u5024\u3092\u89e3\u6790\u4e2d\u306b\u4e88\u671f\u3057\u306a\u3044\u969c\u5bb3\u304c\u767a\u751f\u3057\u307e\u3057\u305f:  "%s"
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE_41=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u3044\u305a\u308c\u304b\u306e RDN \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3067\u3001\u5bfe\u5fdc\u3059\u308b\u9589\u3058\u5f15\u7528\u7b26\u3092\u6301\u305f\u306a\u3044\u5f15\u7528\u7b26\u4ed8\u304d\u306e\u5024\u304c\u3042\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID_42=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u3044\u305a\u308c\u304b\u306e RDN \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u5024\u3067\u3001\u30a8\u30b9\u30b1\u30fc\u30d7\u3055\u308c\u305f 16 \u9032\u6570\u306e\u3042\u3068\u306b 2 \u756a\u76ee\u306e 16 \u9032\u6570\u304c\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO_43=The provided value "%s" could \
+### not be parsed as a valid integer because the first digit may not be zero \
+### unless it is the only digit
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH_44=The provided value "%s" \
+### could not be parsed as a valid integer because the dash may only appear if it \
+### is the first character of the value followed by one or more digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER_45=The provided value "%s" \
+### could not be parsed as a valid integer because character '%c' at position %d \
+### is not allowed in an integer value
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE_46=The provided value "%s" could \
+### not be parsed as a valid integer because it did not contain any digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE_47=The provided value "%s" \
+### could not be parsed as a valid integer because it contained only a dash not \
+### followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE_48=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306b\u306f\u6587\u5b57\u304c\u4e00\u5207\u542b\u307e\u308c\u3066\u3044\u306a\u3044\u305f\u3081\u3001\u6709\u52b9\u306a OID \u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER_49=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u3001\u4f4d\u7f6e %d \u306b\u4e0d\u6b63\u306a\u6587\u5b57\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a OID \u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS_50=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u3001\u4f4d\u7f6e %d \u307e\u305f\u306f\u305d\u306e\u4ed8\u8fd1\u306b 2 \u3064\u306e\u9023\u7d9a\u3057\u305f\u30d4\u30ea\u30aa\u30c9\u304c\u5b58\u5728\u3059\u308b\u305f\u3081\u306b\u6709\u52b9\u306a OID \u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD_51=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u3001\u672b\u5c3e\u306b\u30d4\u30ea\u30aa\u30c9\u304c\u5b58\u5728\u3059\u308b\u305f\u3081\u306b\u6709\u52b9\u306a OID \u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE_52=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u306e\u307f\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS_53=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE_54=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID_55=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID_56=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID_57=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_58=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS_59=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_60=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u578b\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c8\u30fc\u30af\u30f3 %s \u306b\u7d9a\u304f\u6700\u521d\u306e\u975e\u7a7a\u767d\u6587\u5b57\u3068\u3057\u3066\u5358\u4e00\u5f15\u7528\u7b26\u304c\u8a18\u8ff0\u3055\u308c\u308b\u3079\u304d\u3067\u3059\u304c\u3001\u6587\u5b57 %s \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE_61=The definition for \
+### the attribute type with OID %s declared a superior type with an OID of %s. \
+### No attribute type with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR_62=The definition for \
+### the attribute type with OID %s declared that approximate matching should be \
+### performed using the matching rule "%s".  No such approximate matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR_63=The definition for \
+### the attribute type with OID %s declared that equality matching should be \
+### performed using the matching rule "%s".  No such equality matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR_64=The definition for \
+### the attribute type with OID %s declared that ordering matching should be \
+### performed using the matching rule "%s".  No such ordering matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR_65=The definition for \
+### the attribute type with OID %s declared that substring matching should be \
+### performed using the matching rule "%s".  No such substring matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX_66=The definition for the \
+### attribute type with OID %s declared that it should have a syntax with OID %s. \
+### No such syntax is configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE_67=The definition \
+### for the attribute type with OID %s declared that it should have an attribute \
+### usage of %s.  This is an invalid usage
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS_68=The provided value \
+### "%s" could not be parsed as an attribute type description because a single \
+### quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE_69=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u3060\u3051\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS_70=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE_71=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID_72=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID_73=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID_74=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_75=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS_76=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_77=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c8\u30fc\u30af\u30f3 %s \u306b\u7d9a\u304f\u6700\u521d\u306e\u975e\u7a7a\u767d\u6587\u5b57\u3068\u3057\u3066\u5358\u4e00\u5f15\u7528\u7b26\u304c\u8a18\u8ff0\u3055\u308c\u308b\u3079\u304d\u3067\u3059\u304c\u3001\u6587\u5b57 %s \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS_78=The definition \
+### for the objectclass with OID %s declared a superior objectclass with an OID \
+### of %s.  No objectclass with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS_79=The provided \
+### value "%s" could not be parsed as an objectclass description because a single \
+### quote was expected at position %d but the character %s was found instead
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR_80=The definition \
+### for the objectclass with OID %s declared that it should include required \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR_81=The definition \
+### for the objectclass with OID %s declared that it should include optional \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER_82=The provided value "%s" \
+### cannot be parsed as a valid IA5 string because it contains an illegal \
+### character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE_83=\u3053\u308c\u306f\u3001\u96fb\u8a71\u756a\u53f7\u306e\u5c5e\u6027\u306e\u69cb\u6587\u306b ITU-T E.123 \u5f62\u5f0f\u306e\u5024\u306e\u307f\u3092\u53d7\u3051\u5165\u308c\u308b\u53b3\u683c\u306a\u30e2\u30fc\u30c9\u3092\u4f7f\u7528\u3059\u3079\u304d\u304b\u3069\u3046\u304b\u3092\u793a\u3057\u307e\u3059\u3002  \u3053\u308c\u304c\u6709\u52b9\u306a\u5834\u5408\u3001\u3053\u306e\u5f62\u5f0f\u4ee5\u5916\u306e\u5024\u306f\u3059\u3079\u3066\u62d2\u5426\u3055\u308c\u307e\u3059\u3002  \u3053\u308c\u304c\u7121\u52b9\u306a\u5834\u5408\u3001\u3059\u3079\u3066\u306e\u5024\u304c\u53d7\u3051\u5165\u308c\u3089\u308c\u307e\u3059\u304c\u3001\u30de\u30c3\u30c1\u30f3\u30b0\u306e\u5b9f\u884c\u6642\u306b\u6570\u5b57\u306e\u307f\u304c\u8003\u616e\u3055\u308c\u307e\u3059
+###SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE_84=An error \
+### occurred while trying to retrieve attribute \
+### ds-cfg-strict-format from configuration entry %s:  %s.  The \
+### Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+### for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY_85=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u7a7a\u307e\u305f\u306f NULL \u3067\u3042\u308b\u305f\u3081\u3001\u6709\u52b9\u306a\u96fb\u8a71\u756a\u53f7\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS_86=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u6709\u52b9\u306a\u96fb\u8a71\u756a\u53f7\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u53b3\u683c\u306a\u96fb\u8a71\u756a\u53f7\u30c1\u30a7\u30c3\u30af\u304c\u6709\u52b9\u306b\u306a\u3063\u3066\u304a\u308a\u3001\u5024\u306e\u5148\u982d\u304c ITU-T E.123 \u4ed5\u69d8\u306b\u6e96\u62e0\u3057\u305f\u30d7\u30e9\u30b9\u8a18\u53f7\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR_87=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u306f\u6709\u52b9\u306a\u96fb\u8a71\u756a\u53f7\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u53b3\u683c\u306a\u96fb\u8a71\u756a\u53f7\u30c1\u30a7\u30c3\u30af\u304c\u6709\u52b9\u306b\u306a\u3063\u3066\u304a\u308a\u3001\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 %2$s \u306f ITU-T E.123 \u4ed5\u69d8\u3067\u306f\u8a31\u53ef\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS_88=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u3001\u6570\u5b57\u304c\u4e00\u5207\u542b\u307e\u308c\u3066\u3044\u306a\u3044\u305f\u3081\u6709\u52b9\u306a\u96fb\u8a71\u756a\u53f7\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE_89=\u53b3\u683c\u306a\u96fb\u8a71\u756a\u53f7\u306e\u69cb\u6587\u30c1\u30a7\u30c3\u30af\u3092\u4f7f\u7528\u3059\u308b\u304b\u3069\u3046\u304b\u3092\u793a\u3059\u8a2d\u5b9a\u5c5e\u6027 ds-cfg-strict-format \u306e\u5024\u304c\u3001\u69cb\u6210\u30a8\u30f3\u30c8\u30ea %2$s \u5185\u3067 %1$s \u306b\u66f4\u65b0\u3055\u308c\u307e\u3057\u305f
+###SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR_90=The provided value \
+### "%s" is not a valid numeric string because it contained character %s at \
+### position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE_91=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u6587\u5b57\u304c\u4e00\u5207\u542b\u307e\u308c\u3066\u3044\u306a\u3044\u305f\u3081\u306b\u6709\u52b9\u306a\u6570\u5024\u6587\u5b57\u5217\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002  \u6570\u5b57\u6587\u5b57\u5217\u306e\u5024\u306b\u306f\u30011 \u3064\u4ee5\u4e0a\u306e\u6570\u5b57\u307e\u305f\u306f\u7a7a\u767d\u3092\u542b\u3081\u3066\u304f\u3060\u3055\u3044
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE_92=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u306e\u307f\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS_93=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE_94=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID_95=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID_96=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID_97=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS_98=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN_99=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u307e\u305f\u306f\u305d\u306e\u4ed8\u8fd1\u306e\u6587\u5b57\u5217\u304b\u3089 "DESC" \u30c8\u30fc\u30af\u30f3\u3092\u8aad\u307f\u53d6\u308a\u4e2d\u306b\u3001\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC_100=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002"DESC" \u30c8\u30fc\u30af\u30f3\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001\u6587\u5b57\u5217 "%s" \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE_101=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u307e\u305f\u306f\u305d\u306e\u4ed8\u8fd1\u306e\u6587\u5b57\u5217\u304b\u3089 "DESC" \u30c8\u30fc\u30af\u30f3\u306e\u5024\u3092\u8aad\u307f\u53d6\u308a\u4e2d\u306b\u3001\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f:  %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS_102=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u9589\u3058\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE_103=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5c5e\u6027\u69cb\u6587\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u9589\u3058\u62ec\u5f27\u306e\u3042\u3068\u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+###SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS_104=The provided \
+### value "%s" could not be parsed as an attribute syntax description because a \
+### single quote was expected at position %d but the character %s was found \
+### instead
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE_105=The provided value \
+### could not be parsed as a printable string because it was null or empty.  A \
+### printable string must contain at least one character
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER_106=The provided \
+### value "%s" could not be parsed as a printable string because it contained an \
+### invalid character %s at position %d
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD_107=The provided value "*" \
+### could not be parsed as a substring assertion because it consists only of a \
+### wildcard character and zero-length substrings are not allowed
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS_108=The provided \
+### value "%s" could not be parsed as a substring assertion because it contains \
+### consecutive wildcard characters at position %d and zero-length substrings are \
+### not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT_109=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u77ed\u3059\u304e\u308b\u305f\u3081\u3001\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR_110=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002%s \u6587\u5b57\u3092\u4e16\u7d00\u3084\u5e74\u306e\u6307\u5b9a\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH_111=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002%s \u3092\u6708\u306e\u6307\u5b9a\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY_112=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002%s \u3092\u65e5\u306e\u6307\u5b9a\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR_113=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002%s \u3092\u6642\u9593\u306e\u6307\u5b9a\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE_114=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002%s \u3092\u5206\u306e\u6307\u5b9a\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR_115=\u6307\u5b9a\u3055\u308c\u305f\u5024 %1$s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u4f4d\u7f6e %3$d \u306b\u7121\u52b9\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND_116=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002%s \u3092\u79d2\u306e\u6307\u5b9a\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET_117=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u306f\u6709\u52b9\u306a UTC \u6642\u9593\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002%s \u306f\u6709\u52b9\u306a GMT \u30aa\u30d5\u30bb\u30c3\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE_118=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u3092\u6709\u52b9\u306a UTC \u6642\u9593\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f:  %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE_119=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u306e\u307f\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS_120=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE_121=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID_122=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID_123=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092 DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID_124=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092 DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS_125=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_126=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092 DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS_127=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u69cb\u9020\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9 %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL_128=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%s" \u306f\u3001OID %s (%s) \u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059\u3002  \u3053\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306f\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u306b\u5b58\u5728\u3057\u307e\u3059\u304c\u3001\u69cb\u9020\u3068\u3057\u3066\u3067\u306f\u306a\u304f %s \u3068\u3057\u3066\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS_129=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u88dc\u52a9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9 %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY_130=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%s" \u306f\u88dc\u52a9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9 %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059\u3002\u3053\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306f\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u306b\u5b58\u5728\u3057\u307e\u3059\u304c\u3001\u88dc\u52a9\u3067\u306f\u306a\u304f %s \u3068\u3057\u3066\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR_131=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u5fc5\u9808\u5c5e\u6027\u578b %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR_132=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30aa\u30d7\u30b7\u30e7\u30f3\u5c5e\u6027\u578b %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR_133=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u7981\u6b62\u5c5e\u6027\u578b %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS_134=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u5358\u4e00\u5f15\u7528\u7b26\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001%s \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE_135=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u306e\u307f\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS_136=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%c' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE_137=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID_138=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID_139=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$c \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID_140=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$c \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS_141=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_142=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$c \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS_143=\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u69cb\u9020\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9 %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL_144=\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e "%s" \u306f\u3001OID %s (%s) \u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059\u3002 \u3053\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u306f\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u306b\u5b58\u5728\u3057\u307e\u3059\u304c\u3001\u69cb\u9020\u3068\u3057\u3066\u3067\u306f\u306a\u304f %s \u3068\u3057\u3066\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR_145=OID %s \u306e\u540d\u524d\u66f8\u5f0f\u306e\u5b9a\u7fa9\u3067\u306f\u3001\u5fc5\u9808\u5c5e\u6027 "%s" \u3092\u542b\u3081\u308b\u3079\u304d\u3067\u3042\u308b\u3068\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u3057\u305f\u3002  \u3053\u306e\u540d\u524d\u307e\u305f\u306f OID \u306b\u4e00\u81f4\u3059\u308b\u5c5e\u6027\u578b\u304c\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u306b\u5b58\u5728\u3057\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR_146=OID %s \u306e\u540d\u524d\u66f8\u5f0f\u306e\u5b9a\u7fa9\u3067\u306f\u3001\u30aa\u30d7\u30b7\u30e7\u30f3\u5c5e\u6027 "%s" \u3092\u542b\u3081\u308b\u3079\u304d\u3067\u3042\u308b\u3068\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u3057\u305f\u3002  \u3053\u306e\u540d\u524d\u307e\u305f\u306f OID \u306b\u4e00\u81f4\u3059\u308b\u5c5e\u6027\u578b\u304c\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u306b\u5b58\u5728\u3057\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS_147=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u69cb\u9020\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS_148=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u540d\u524d\u66f8\u5f0f\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u5358\u4e00\u5f15\u7528\u7b26\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001%c \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE_149=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u306e\u307f\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS_150=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE_151=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID_152=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID_153=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID_154=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS_155=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_156=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX_157=\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u5c5e\u6027\u69cb\u6587 %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX_158=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u5c5e\u6027\u69cb\u6587\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS_159=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u5358\u4e00\u5f15\u7528\u7b26\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001%s \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE_160=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u306e\u307f\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS_161=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE_162=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID_163=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID_164=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID_165=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE_166=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6307\u5b9a\u3055\u308c\u305f\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb %s \u306f\u4e0d\u660e\u3067\u3059
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS_167=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_168=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR_169=\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e "%s" \u306f\u3001\u30b5\u30fc\u30d0\u30fc\u30b9\u30ad\u30fc\u30de\u5185\u3067\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u5c5e\u6027\u578b %s \u306b\u95a2\u9023\u4ed8\u3051\u3089\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR_170=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f OID \u3067\u4f7f\u7528\u53ef\u80fd\u306a\u5c5e\u6027\u578b\u306e\u30bb\u30c3\u30c8\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS_171=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u306e\u4f7f\u7528\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u5358\u4e00\u5f15\u7528\u7b26\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001%s \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE_172=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u304b\u7a7a\u767d\u306e\u307f\u304c\u542b\u307e\u308c\u308b\u305f\u3081\u306b\u6709\u52b9\u306a DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS_173=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u958b\u304d\u62ec\u5f27\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001'%s' \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE_174=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306f\u3088\u308a\u591a\u304f\u306e\u30c7\u30fc\u30bf\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u5024\u306e\u672b\u5c3e\u306b\u9054\u3057\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID_175=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u898f\u5247 ID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS_176=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u4e88\u671f\u3057\u306a\u3044\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_177=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM_178=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4e0d\u660e\u306a\u540d\u524d\u66f8\u5f0f %s \u304c\u53c2\u7167\u3055\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID_179=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4e0a\u4f4d\u306e DIT \u69cb\u9020\u898f\u5247\u3068\u3057\u3066\u4e0d\u660e\u306a\u898f\u5247 ID %d \u304c\u53c2\u7167\u3055\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM_180=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u898f\u5247\u306e\u540d\u524d\u66f8\u5f0f\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS_181=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u306f\u5358\u4e00\u5f15\u7528\u7b26\u304c\u5b58\u5728\u3059\u308b\u3079\u304d\u3067\u3059\u304c\u3001%s \u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID_182=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID_183=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID_184=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092 DIT \u69cb\u9020\u898f\u5247\u306e\u8aac\u660e\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u975e\u6570\u5024 OID \u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT_185=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306f\u77ed\u3059\u304e\u308b\u305f\u3081\u3001\u6709\u52b9\u306a\u30c6\u30ec\u30c3\u30af\u30b9\u756a\u53f7\u5024\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE_186=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u306b\u306f\u6709\u52b9\u306a\u30c6\u30ec\u30c3\u30af\u30b9\u756a\u53f7\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 %2$s \u306f\u6709\u52b9\u306a\u30d7\u30ea\u30f3\u30c8\u53ef\u80fd\u6587\u5b57\u5217\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR_187=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u306b\u306f\u6709\u52b9\u306a\u30c6\u30ec\u30c3\u30af\u30b9\u756a\u53f7\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 %2$s \u306f\u3001\u6709\u52b9\u306a\u30d7\u30ea\u30f3\u30c8\u53ef\u80fd\u6587\u5b57\u5217\u3067\u3082\u3001\u30c6\u30ec\u30c3\u30af\u30b9\u756a\u53f7\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u533a\u5207\u308b\u305f\u3081\u306e\u30c9\u30eb\u8a18\u53f7\u3067\u3082\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED_188=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u306b\u306f\u6709\u52b9\u306a\u30c6\u30ec\u30c3\u30af\u30b9\u756a\u53f7\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u30c9\u30eb\u8a18\u53f7\u3067\u533a\u5207\u3089\u308c\u305f 3 \u3064\u306e\u30d7\u30ea\u30f3\u30c8\u53ef\u80fd\u6587\u5b57\u5217\u3092\u8aad\u307f\u53d6\u308b\u524d\u306b\u3001\u5024\u306e\u672b\u5c3e\u304c\u691c\u51fa\u3055\u308c\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY_189=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u305f\u3081\u306b\u6709\u52b9\u306a FAX \u756a\u53f7\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE_190=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a FAX \u756a\u53f7\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 %2$s \u306f\u6709\u52b9\u306a\u30d7\u30ea\u30f3\u30c8\u53ef\u80fd\u6587\u5b57\u5217\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR_191=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a FAX \u756a\u53f7\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u672b\u5c3e\u304c\u30c9\u30eb\u8a18\u53f7\u3067\u3057\u305f\u304c\u3001\u30c9\u30eb\u8a18\u53f7\u306e\u3042\u3068\u306b FAX \u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u8a18\u8ff0\u3055\u308c\u3066\u3044\u308b\u3079\u304d\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER_192=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a FAX \u756a\u53f7\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u3068 %4$d \u306e\u9593\u306e\u6587\u5b57\u5217 "%2$s" \u306f\u6709\u52b9\u306a FAX \u30d1\u30e9\u30e1\u30fc\u30bf\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN_193=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u540d\u524d\u304a\u3088\u3073\u30aa\u30d7\u30b7\u30e7\u30f3 UID \u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002DN \u90e8\u3092\u89e3\u6790\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f:  %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT_194=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u540d\u524d\u304a\u3088\u3073\u30aa\u30d7\u30b7\u30e7\u30f3 UID \u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002UID \u90e8\u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a 2 \u9032\u6570 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY_195=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u305f\u3081\u306b\u6709\u52b9\u306a\u30c6\u30ec\u30c6\u30c3\u30af\u30b9\u7aef\u672b\u8b58\u5225\u5b50\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE_196=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u30c6\u30ec\u30c6\u30c3\u30af\u30b9\u7aef\u672b\u8b58\u5225\u5b50\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 %2$s \u306f\u6709\u52b9\u306a\u30d7\u30ea\u30f3\u30c8\u53ef\u80fd\u6587\u5b57\u5217\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR_197=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u30c6\u30ec\u30c6\u30c3\u30af\u30b9\u7aef\u672b\u8b58\u5225\u5b50\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u672b\u5c3e\u304c\u30c9\u30eb\u8a18\u53f7\u3067\u3057\u305f\u304c\u3001\u30c9\u30eb\u8a18\u53f7\u306e\u3042\u3068\u306b TTX \u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u8a18\u8ff0\u3055\u308c\u3066\u3044\u308b\u3079\u304d\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON_198=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u30c6\u30ec\u30c6\u30c3\u30af\u30b9\u7aef\u672b\u8b58\u5225\u5b50\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30d1\u30e9\u30e1\u30fc\u30bf\u6587\u5b57\u5217\u306b\u540d\u524d\u3068\u5024\u3092\u533a\u5207\u308b\u30b3\u30ed\u30f3\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER_199=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u30c6\u30ec\u30c6\u30c3\u30af\u30b9\u7aef\u672b\u8b58\u5225\u5b50\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6587\u5b57\u5217 "%s" \u306f\u6709\u52b9\u306a TTX \u30d1\u30e9\u30e1\u30fc\u30bf\u540d\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE_200=\u6307\u5b9a\u3055\u308c\u305f\u5024\u306f\u3001\u7a7a\u3067\u3042\u308b\u305f\u3081\u306b\u5225\u306e\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE_201=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5225\u306e\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c9\u30eb\u8a18\u53f7\u306e\u524d\u306b\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u578b\u304c\u8a18\u8ff0\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR_202=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5225\u306e\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u578b\u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX_203=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5225\u306e\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30c9\u30eb\u8a18\u53f7\u306e\u3042\u3068\u306b\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u304c\u8a18\u8ff0\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR_204=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u5225\u306e\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30e1\u30fc\u30eb\u30dc\u30c3\u30af\u30b9\u306e\u4f4d\u7f6e %3$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %2$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC_205=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u306e\u524d\u306b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d\u3082 OID \u3082\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR_206=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u90e8 %2$s \u306e\u4f4d\u7f6e %4$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %3$c \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN_207=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u90e8 %s \u306b\u3001\u6700\u521d\u306e\u958b\u304d\u62ec\u5f27\u306b\u5bfe\u5fdc\u3059\u308b\u9589\u3058\u62ec\u5f27\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK_208=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u90e8 %s \u306e\u5148\u982d\u306f\u7591\u554f\u7b26\u3067\u3057\u305f\u304c\u3001\u305d\u306e\u3042\u3068\u306b\u6587\u5b57\u5217 "true" \u307e\u305f\u306f "false" \u304c\u7d9a\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR_209=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u90e8 %s \u306b\u3001\u5c5e\u6027\u578b\u3068\u4e00\u81f4\u578b\u3092\u533a\u5207\u308b\u30c9\u30eb\u8a18\u53f7\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR_210=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u90e8 %s \u3067\u30c9\u30eb\u8a18\u53f7\u306e\u524d\u306b\u5c5e\u6027\u578b\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE_211=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u90e8 %s \u3067\u30c9\u30eb\u8a18\u53f7\u306e\u3042\u3068\u306b\u4e00\u81f4\u578b\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE_212=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u90e8 %s \u306b\u3001\u4f4d\u7f6e %d \u304b\u3089\u59cb\u307e\u308b\u7121\u52b9\u306a\u4e00\u81f4\u578b\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP_213=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u3068\u6761\u4ef6\u3092\u533a\u5207\u308b\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC_214=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u306e\u524d\u306b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d\u3082 OID \u3082\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID_215=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u3092\u6307\u5b9a\u3059\u308b\u6570\u5024 OID %s \u306e\u4f4d\u7f6e %d \u306b\u9023\u7d9a\u3059\u308b 2 \u3064\u306e\u30d4\u30ea\u30aa\u30c9\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID_216=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u3092\u6307\u5b9a\u3059\u308b\u6570\u5024 OID %2$s \u306e\u4f4d\u7f6e %4$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %3$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME_217=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d %2$s \u306e\u4f4d\u7f6e %4$d \u306b\u4e0d\u6b63\u306a\u6587\u5b57 %3$s \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP_218=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6761\u4ef6\u3068\u6709\u52b9\u7bc4\u56f2\u3092\u533a\u5207\u308b\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE_219=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6700\u5f8c\u306e\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u306e\u3042\u3068\u306b\u6709\u52b9\u7bc4\u56f2\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE_220=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u6307\u5b9a\u3055\u308c\u305f\u6709\u52b9\u7bc4\u56f2 %s \u304c\u7121\u52b9\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA_221=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u62e1\u5f35\u30ac\u30a4\u30c9\u5024\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30b7\u30e3\u30fc\u30d7\u8a18\u53f7 (#) \u306e\u9593\u306b\u6761\u4ef6\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE_222=\u6307\u5b9a\u3055\u308c\u305f\u5024 %s \u3092\u6709\u52b9\u306a OID \u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f:  %s
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE_223=An unexpected \
+### error occurred while trying to normalize value %s as a generalized time \
+### value:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE_224=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseExactOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE_225=An error occurred while \
+### attempting to compare two objects using the caseExactOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE_226=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE_227=An error occurred while \
+### attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE_228=An error \
+### occurred while attempting to compare two AttributeValue objects using the \
+### generalizedTimeOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE_229=An error occurred \
+### while attempting to compare two objects using the \
+### generalizedTimeOrderingMatch matching rule because the objects were of an \
+### unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+### value objects may be compared
+###SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE_230=An error occurred while \
+### attempting to compare two AttributeValue objects using the \
+### integerOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE_231=An error occurred while \
+### attempting to compare two objects using the integerOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE_232=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### numericStringOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE_233=An error occurred \
+### while attempting to compare two objects using the numericStringOrderingMatch \
+### matching rule because the objects were of an unsupported type %s.  Only byte \
+### arrays, ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE_234=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### octetStringOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE_235=An error occurred while \
+### attempting to compare two objects using the octetStringOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH_236=The provided value "%s" has \
+### an invalid length for a UUID.  All UUID values must have a length of exactly \
+### 36 bytes, but the provided value had a length of %d bytes
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH_237=The provided value "%s" should \
+### have had a dash at position %d, but the character '%s' was found instead
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX_238=The provided value "%s" should \
+### have had a hexadecimal digit at position %d, but the character '%s' was found \
+### instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH_239=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u6587\u5b57\u5217\u69cb\u6587\u3092\u542b\u3080\u5c5e\u6027\u306b\u9577\u3055\u304c 0 \u306e\u5024\u3092\u6307\u5b9a\u3067\u304d\u308b\u304b\u3069\u3046\u304b\u3092\u793a\u3057\u307e\u3059\u3002  \u3053\u308c\u306f\u3001\u53b3\u5bc6\u306b\u306f LDAP \u4ed5\u69d8\u3067\u306f\u8a31\u53ef\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u304c\u3001\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u30fc\u306e\u4ee5\u524d\u306e\u30ea\u30ea\u30fc\u30b9\u3068\u306e\u4e0b\u4f4d\u4e92\u63db\u6027\u3092\u7dad\u6301\u3059\u308b\u305f\u3081\u306b\u6709\u7528\u3067\u3042\u308b\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH_240=An \
+### error occurred while trying to determine the value of the %s configuration \
+### attribute, which indicates whether directory string attributes should be \
+### allowed to have zero-length values:  %s
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE_241=The \
+### operation attempted to assign a zero-length value to an attribute with the \
+### directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH_242=\u69cb\u6210\u30a8\u30f3\u30c8\u30ea %2$s \u5185\u306e %1$s \u5c5e\u6027\u304c\u65b0\u3057\u3044\u5024 %3$s \u3067\u66f4\u65b0\u3055\u308c\u307e\u3057\u305f
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR_243=The provided \
+### authPassword value had an invalid scheme character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_244=The provided authPassword value \
+### had a zero-length scheme element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR_245=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the scheme and authInfo elements
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR_246=The provided \
+### authPassword value had an invalid authInfo character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_247=The provided authPassword \
+### value had a zero-length authInfo element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR_248=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the authInfo and authValue elements
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS_249=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### it did not start with a parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE_250=The provided value "%s" could not \
+### be parsed by the integer first component matching rule because it did not \
+### have any non-space characters after the opening parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT_251=The provided value "%s" \
+### could not be parsed by the integer first component matching rule because it \
+### did not have any space characters after the first component
+###SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT_252=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### the first component does not appear to be an integer value
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE_253=No value was given to decode by \
+### the user password attribute syntax
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE_254=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not start with the opening curly brace ("{") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE_255=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not contain a closing curly brace ("}") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME_256=Unable to decode the provided \
+### value according to the user password syntax because the value does not \
+### contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID_257=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a RFC 3672 \u30b5\u30d6\u30c4\u30ea\u30fc\u4ed5\u69d8\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID_258=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u7d76\u5bfe\u30b5\u30d6\u30c4\u30ea\u30fc\u4ed5\u69d8\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID_259=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u76f8\u5bfe\u30b5\u30d6\u30c4\u30ea\u30fc\u4ed5\u69d8\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER_260=The provided value %s is not \
+### allowed for attributes with a Integer syntax
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR_261=The provided \
+### authPassword value had an invalid authValue character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE_262=The provided authPassword \
+### value had a zero-length authValue element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR_263=The provided \
+### authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER_264=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u5c5e\u6027\u69cb\u6587\u62e1\u5f35\u6a5f\u80fd\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %d \u306b\u7121\u52b9\u306a\u6587\u5b57\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION_265=\u62e1\u5f35\u6a5f\u80fd\u304c\u7121\u52b9\u3067\u3042\u308b\u305f\u3081\u3001\u5c5e\u6027\u69cb\u6587\u3092\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002%s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE_266=The definition \
+### for objectclass %s is invalid because it has an objectclass type of %s but \
+### this is incompatible with the objectclass type %s for the superior class %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP_267=The \
+### definition for objectclass %s is invalid because it is defined as a \
+### structural class but its superior chain does not include the "top" \
+### objectclass
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
+### for attribute type %s is invalid because its attribute usage %s is not the \
+### same as the usage for its superior type %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \
+### definition for attribute type %s is invalid because it is defined as a \
+### collective type but the superior type %s is not collective
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
+### definition for attribute type %s is invalid because it is not defined as a \
+### collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%1$s" \u306f\u6709\u52b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u69cb\u9020\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9 %3$s \u3067\u5fc5\u8981\u3068\u3055\u308c\u308b\u5c5e\u6027\u578b %2$s \u306e\u4f7f\u7528\u304c\u7981\u6b62\u3055\u308c\u3066\u3044\u307e\u3059
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=DIT \u30b3\u30f3\u30c6\u30f3\u30c4\u898f\u5247 "%1$s" \u306f\u6709\u52b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f\u88dc\u52a9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9 %3$s \u3067\u5fc5\u8981\u3068\u3055\u308c\u308b\u5c5e\u6027\u578b %2$s \u306e\u4f7f\u7528\u304c\u7981\u6b62\u3055\u308c\u3066\u3044\u307e\u3059
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \
+### for attribute type %s is invalid because it is declared COLLECTIVE but does \
+### not have a usage of userApplications
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \
+### definition for attribute type %s is invalid because it is declared \
+### NO-USER-MODIFICATION but does not have an operational usage
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR_275=The \
+### provided value %s is not a valid generalized time value because it contains \
+### illegal character %s in the fraction component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION_276=The provided \
+### value %s is not a valid generalized time value because it does not contain at \
+### least one digit after the period to use as the fractional component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO_277=The provided \
+### value %s is not a valid generalized time value because it does not end with \
+### 'Z' or a time zone offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME_278=The provided value \
+### %s is not a valid generalized time value because it represents an invalid \
+### time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED_279=\u30b9\u30ad\u30fc\u30de\u8981\u7d20\u3092\u30a4\u30f3\u30dd\u30fc\u30c8\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f: %s\u3001%s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE_280=\u30ed\u30b1\u30fc\u30eb %s \u306f JVM \u3067\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u306a\u3044\u305f\u3081\u3001\u30de\u30c3\u30c1\u30f3\u30b0\u30eb\u30fc\u30eb\u30a8\u30f3\u30c8\u30ea %s \u306e\u7167\u5408\u30eb\u30fc\u30eb %s \u306f\u7121\u52b9\u3067\u3059
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT_281=\u6307\u5b9a\u3055\u308c\u305f\u7167\u5408\u30eb\u30fc\u30eb %s \u306b\u3001\u6709\u52b9\u306a\u5f62\u5f0f\u306e OID:LOCALE \u304c\u542b\u307e\u308c\u3066\u3044\u307e\u305b\u3093
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u8b58\u5225\u540d\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u5c5e\u6027\u5024\u306e\u5148\u982d\u6587\u5b57 (\u4f4d\u7f6e %d) \u306f\u30a8\u30b9\u30b1\u30fc\u30d7\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u305f\u3081\u3067\u3059
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR_283=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u5c5e\u6027\u578b\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 '%2$c' \u3092\u5c5e\u6027\u578b\u540d\u306b\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_284=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u5c5e\u6027\u578b\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002%s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u3067\u306a\u3044\u304b\u304e\u308a\u3001\u5c5e\u6027\u578b\u540d\u306b\u4e0b\u7dda\u6587\u5b57\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_285=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u5c5e\u6027\u578b\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30cf\u30a4\u30d5\u30f3\u6587\u5b57\u3092\u5c5e\u6027\u578b\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_286=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u5c5e\u6027\u578b\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002%s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u306a\u5834\u5408\u3067\u3082\u3001\u4e0b\u7dda\u6587\u5b57\u3092\u5c5e\u6027\u578b\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_287=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u5c5e\u6027\u578b\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u540d\u524d\u304c OID \u3068\u3057\u3066\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u304b\u3001%3$s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u3067\u306a\u3044\u304b\u304e\u308a\u3001\u6570\u5b57 '%2$c' \u3092\u5c5e\u6027\u578b\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR_288=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4f4d\u7f6e %3$d \u306e\u6587\u5b57 '%2$c' \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d\u306b\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_289=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002%s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u3067\u306a\u3044\u304b\u304e\u308a\u3001\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d\u306b\u4e0b\u7dda\u6587\u5b57\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_290=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30cf\u30a4\u30d5\u30f3\u6587\u5b57\u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_291=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%s" \u3092\u6709\u52b9\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002%s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u306a\u5834\u5408\u3067\u3082\u3001\u4e0b\u7dda\u6587\u5b57\u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_292=\u6307\u5b9a\u3055\u308c\u305f\u5024 "%1$s" \u3092\u6709\u52b9\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u5b9a\u7fa9\u3068\u3057\u3066\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u540d\u524d\u304c OID \u3068\u3057\u3066\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u304b\u3001%3$s \u69cb\u6210\u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6709\u52b9\u3067\u306a\u3044\u304b\u304e\u308a\u3001\u6570\u5b57 '%2$c' \u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u30af\u30e9\u30b9\u540d\u306e\u6700\u521d\u306e\u6587\u5b57\u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u306a\u3044\u305f\u3081\u3067\u3059
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ko.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ko.properties
new file mode 100755
index 0000000..a29b8bd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_ko.properties
@@ -0,0 +1,531 @@
+# 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
+#
+#      Copyright 2009 Sun Microsystems, Inc.
+#
+# Global directives
+#
+global.ordinal=-1
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE_1=Unable to retrieve \
+### approximate matching rule %s used as the default for the %s attribute syntax. \
+### Approximate matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE_2=Unable to retrieve \
+### equality matching rule %s used as the default for the %s attribute syntax. \
+### Equality matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE_3=Unable to retrieve \
+### ordering matching rule %s used as the default for the %s attribute syntax. \
+### Ordering matches will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE_4=Unable to retrieve \
+### substring matching rule %s used as the default for the %s attribute syntax. \
+### Substring matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN_5=The provided value "%s" is not \
+### allowed for attributes with a Boolean syntax.  The only allowed values are \
+### 'TRUE' and 'FALSE'
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT_6=The provided value "%s" is too \
+### short to be a valid bit string.  A bit string must be a series of binary \
+### digits surrounded by single quotes and followed by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED_7=The provided value "%s" is not \
+### a valid bit string because it is not surrounded by single quotes and followed \
+### by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT_8=The provided value "%s" is \
+### not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=\uae38\uc774\uac00 \uc815\ud655\ud788 \ub450 \ubb38\uc790\uac00 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \uad6d\uac00 \ubb38\uc790\uc5f4\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE_10=\ud558\ub098 \uc774\uc0c1\uc758 \uc778\uc1c4\ud560 \uc218 \uc5c6\ub294 \ubb38\uc790\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \uad6d\uac00 \ubb38\uc790\uc5f4\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=\uc694\uc18c\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \uc804\ub2ec \ubc29\ubc95\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT_12=\"%2$s\"\uc774(\uac00) \uc720\ud6a8\ud55c \ubc29\ubc95\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc740(\ub294) \uc720\ud6a8\ud55c \uc804\ub2ec \ubc29\ubc95\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT_13=The provided value "%s" \
+### is too short to be a valid generalized time value
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR_14=The provided value \
+### "%s" is not a valid generalized time value because the '%s' character is not \
+### allowed in the century or year specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH_15=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid month \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY_16=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid day \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR_17=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid hour \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE_18=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid minute \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND_19=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid second \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND_20=The provided \
+### value "%s" is not a valid generalized time value because the sub-second \
+### component is not valid (between 1 and 3 numeric digits)
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND_21=The provided value \
+### "%s" is not a valid generalized time value because the sub-second value may \
+### not contain more than three digits
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET_22=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+### offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR_23=The provided value \
+### "%s" is not a valid generalized time value because it contains an invalid \
+### character '%s' at position %d
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE_24=The provided value \
+### "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_25=\uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA_26=\uacf5\ubc31\uc774 \uc544\ub2cc \ub9c8\uc9c0\ub9c9 \ubb38\uc790\uac00 \uc27c\ud45c\ub098 \uc138\ubbf8\ucf5c\ub860\uc774\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT_27=\uc22b\uc790 '%2$s'\uc774(\uac00) \uc18d\uc131 \uc774\ub984\uc758 \uccab \ubc88\uc9f8 \ubb38\uc790\ub85c \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR_28=\uc704\uce58 %3$d\uc5d0 \uc788\ub294 \ubb38\uc790 '%2$c'\uc774(\uac00) \uc18d\uc131 \uc774\ub984\uc5d0 \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR_29=%2$s \uad6c\uc131 \uc635\uc158\uc774 \ud65c\uc131\ud654\ub418\uc5b4 \uc788\uc9c0 \uc54a\uc73c\uba74 \ubc11\uc904\uc774 \uc18d\uc131 \uc774\ub984\uc5d0 \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH_30=\ud558\uc774\ud508\uc774 \uc18d\uc131 \uc774\ub984\uc758 \uccab \ubc88\uc9f8 \ubb38\uc790\ub85c \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE_31=%2$s \uad6c\uc131 \uc635\uc158\uc774 \ud65c\uc131\ud654\ub418\uc5b4 \uc788\ub354\ub77c\ub3c4 \ubc11\uc904\uc774 \uc18d\uc131 \uc774\ub984\uc758 \uccab \ubc88\uc9f8 \ubb38\uc790\ub85c \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT_32=The provided value "%s" could not be parsed as a valid distinguished name because the digit '%c' is not allowed as the first character of an attribute name unless the name is specified as an OID or the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME_33=\ube48 \uc18d\uc131 \uc774\ub984\uc744 \uac00\uc9c4 RDN\uc774 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD_34=\uad6c\ubb38 \ubd84\uc11d\ub41c \uc18d\uc131 \uc774\ub984 %2$s\uc5d0 \ub9c8\uce68\ud45c\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0\ub9cc \ud574\ub2f9 \uc774\ub984\uc774 \uc720\ud6a8\ud55c OID\uac00 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME_35=\uacf5\ubc31\uc774 \uc544\ub2cc \ub9c8\uc9c0\ub9c9 \ubb38\uc790\uac00 \uc18d\uc131 \uc774\ub984 '%2$s'\uc758 \uc77c\ubd80\uc774\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL_36=\uc18d\uc131 \uc774\ub984 \"%2$s\" \ub4a4\uc5d0 \uacf5\ubc31\uc774 \uc544\ub2cc \ub2e4\uc74c \ubb38\uc790\uac00 \ub4f1\ud638 \uae30\ud638\uc5ec\uc57c \ud558\ub294\ub370 '%3$c'\uc774\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR_37=\uc704\uce58 %3$d\uc5d0 \uc788\ub294 \ubb38\uc790 '%2$c'\uc774(\uac00) \uc798\ubabb\ub418\uc5c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT_38=\uc18d\uc131 \uac12\uc774 # \uae30\ud638\ub85c \uc2dc\uc791\ud558\uc9c0\ub9cc \ub4a4\uc5d0 \ub450 16\uc9c4\uc218 \uc22b\uc790\uc758 \uc591\uc758 \ubc30\uc218\uac00 \uc624\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT_39=\uc18d\uc131 \uac12\uc774 # \uae30\ud638\ub85c \uc2dc\uc791\ud558\uc9c0\ub9cc \uc720\ud6a8\ud558\uc9c0 \uc54a\uc740 16\uc9c4\uc218 \uc22b\uc790\uc778 %2$c \ubb38\uc790\ub97c \ud3ec\ud568\ud558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\" \uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE_40=RDN \uad6c\uc131\uc694\uc18c \uc911 \ud558\ub098\uc5d0\uc11c \uc18d\uc131 \uac12\uc744 \uad6c\ubb38 \ubd84\uc11d\ud558\ub294 \ub3d9\uc548 \uc608\uae30\uce58 \uc54a\uc740 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: "%s"
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE_41=RDN \uad6c\uc131\uc694\uc18c \uc911 \ud558\ub098\uac00 \ud574\ub2f9\ud558\ub294 \ub2eb\ub294 \uc778\uc6a9 \ubd80\ud638\uac00 \uc5c6\ub294 \uc778\uc6a9 \uac12\uc744 \ud3ec\ud568\ud558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID_42=RDN \uad6c\uc131\uc694\uc18c \uc911 \ud558\ub098\uac00 \uc774\uc2a4\ucf00\uc774\ud504 \ucc98\ub9ac\ub41c 16\uc9c4\uc218 \uc22b\uc790\uac00 \uc788\ub294 \uac12\uc744 \ud3ec\ud568\ud558\uc9c0\ub9cc \ub4a4\uc5d0 \ub450 \ubc88\uc9f8 16\uc9c4\uc218 \uc22b\uc790\uac00 \uc624\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uace0\uc720 \uc774\ub984\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO_43=The provided value "%s" could \
+### not be parsed as a valid integer because the first digit may not be zero \
+### unless it is the only digit
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH_44=The provided value "%s" \
+### could not be parsed as a valid integer because the dash may only appear if it \
+### is the first character of the value followed by one or more digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER_45=The provided value "%s" \
+### could not be parsed as a valid integer because character '%c' at position %d \
+### is not allowed in an integer value
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE_46=The provided value "%s" could \
+### not be parsed as a valid integer because it did not contain any digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE_47=The provided value "%s" \
+### could not be parsed as a valid integer because it contained only a dash not \
+### followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE_48=\ubb38\uc790\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c OID\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER_49=\uc704\uce58 %2$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c OID\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS_50=\uc704\uce58 %2$d \ub610\ub294 \uadf8 \uadfc\ucc98\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450 \uac1c \uc5f0\uc18d\ud574\uc11c \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c OID\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD_51=\ub9c8\uce68\ud45c\ub85c \ub05d\ub098\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c OID\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE_52=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS_53=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE_54=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID_55=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450 \uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID_56=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID_57=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_58=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS_59=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_60=\ud1a0\ud070 %2$s \ub4a4\uc758 \uacf5\ubc31\uc774 \uc544\ub2cc \uccab \ubc88\uc9f8 \ubb38\uc790\ub85c \uc791\uc740 \ub530\uc634\ud45c\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 %3$s \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uc720\ud615 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE_61=The definition for \
+### the attribute type with OID %s declared a superior type with an OID of %s. \
+### No attribute type with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR_62=The definition for \
+### the attribute type with OID %s declared that approximate matching should be \
+### performed using the matching rule "%s".  No such approximate matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR_63=The definition for \
+### the attribute type with OID %s declared that equality matching should be \
+### performed using the matching rule "%s".  No such equality matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR_64=The definition for \
+### the attribute type with OID %s declared that ordering matching should be \
+### performed using the matching rule "%s".  No such ordering matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR_65=The definition for \
+### the attribute type with OID %s declared that substring matching should be \
+### performed using the matching rule "%s".  No such substring matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX_66=The definition for the \
+### attribute type with OID %s declared that it should have a syntax with OID %s. \
+### No such syntax is configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE_67=The definition \
+### for the attribute type with OID %s declared that it should have an attribute \
+### usage of %s.  This is an invalid usage
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS_68=The provided value \
+### "%s" could not be parsed as an attribute type description because a single \
+### quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE_69=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS_70=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE_71=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID_72=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450 \uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID_73=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID_74=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_75=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS_76=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_77=\ud1a0\ud070 %2$s \ub4a4\uc758 \uacf5\ubc31\uc774 \uc544\ub2cc \uccab \ubc88\uc9f8 \ubb38\uc790\ub85c \uc791\uc740 \ub530\uc634\ud45c\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 %3$s \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac1d\uccb4 \ud074\ub798\uc2a4 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS_78=The definition \
+### for the objectclass with OID %s declared a superior objectclass with an OID \
+### of %s.  No objectclass with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS_79=The provided \
+### value "%s" could not be parsed as an objectclass description because a single \
+### quote was expected at position %d but the character %s was found instead
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR_80=The definition \
+### for the objectclass with OID %s declared that it should include required \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR_81=The definition \
+### for the objectclass with OID %s declared that it should include optional \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER_82=The provided value "%s" \
+### cannot be parsed as a valid IA5 string because it contains an illegal \
+### character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE_83=\uc774\ub294 \uc804\ud654 \ubc88\ud638 \uc18d\uc131 \uad6c\ubb38\uc5d0\uc11c ITU-T E.123 \ud615\uc2dd\uc758 \uac12\ub9cc \ud5c8\uc6a9\ud558\ub294 \uc5c4\uaca9\ud55c \ubaa8\ub4dc\ub97c \uc0ac\uc6a9\ud560\uc9c0 \uc5ec\ubd80\ub97c \ub098\ud0c0\ub0c5\ub2c8\ub2e4.  \uc774 \ubaa8\ub4dc\ub97c \ud65c\uc131\ud654\ud558\uba74 \uc774 \ud615\uc2dd\uc5d0 \uc5c6\ub294 \uac12\uc740 \ubaa8\ub450 \uac70\ubd80\ub429\ub2c8\ub2e4.  \uc774 \ubaa8\ub4dc\ub97c \ube44\ud65c\uc131\ud654\ud558\uba74 \ubaa8\ub4e0 \uac12\uc774 \ud5c8\uc6a9\ub418\uc9c0\ub9cc \uc77c\uce58\ub97c \uc218\ud589\ud560 \ub54c \uc22b\uc790\ub9cc \uace0\ub824\ud569\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE_84=An error \
+### occurred while trying to retrieve attribute \
+### ds-cfg-strict-format from configuration entry %s:  %s.  The \
+### Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+### for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY_85=\ube44\uc5b4 \uc788\uac70\ub098 null\uc774\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc740 \uc720\ud6a8\ud55c \uc804\ud654 \ubc88\ud638\uac00 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS_86=\uc5c4\uaca9\ud55c \uc804\ud654 \ubc88\ud638 \ud655\uc778\uc774 \ud65c\uc131\ud654\ub418\uc5b4 \uc788\uace0 \uac12\uc774 ITU-T E.123 \uc0ac\uc591\uc5d0 \ub9de\uac8c \ub354\ud558\uae30 \uae30\ud638\ub85c \uc2dc\uc791\ud558\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \uc804\ud654 \ubc88\ud638\uac00 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR_87=\uc5c4\uaca9\ud55c \uc804\ud654 \ubc88\ud638 \ud655\uc778\uc774 \ud65c\uc131\ud654\ub418\uc5b4 \uc788\uace0 \uc704\uce58 %3$d\uc5d0 \uc788\ub294 \ubb38\uc790 %2$s\uc774(\uac00) ITU-T E.123 \uc0ac\uc591\uc5d0 \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc740(\ub294) \uc720\ud6a8\ud55c \uc804\ud654 \ubc88\ud638\uac00 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS_88=\uc22b\uc790\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \uc804\ud654 \ubc88\ud638\uac00 \uc544\ub2d9\ub2c8\ub2e4.
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE_89=\uad6c\uc131 \ud56d\ubaa9 %2$s\uc5d0\uc11c \uc5c4\uaca9\ud55c \uc804\ud654 \ubc88\ud638 \uad6c\ubb38 \ud655\uc778\uc744 \uc0ac\uc6a9\ud560\uc9c0 \uc5ec\ubd80\ub97c \ub098\ud0c0\ub0b4\ub294 ds-cfg-strict-format \uad6c\uc131 \uc18d\uc131 \uac12\uc774 %1$s(\uc73c)\ub85c \uc5c5\ub370\uc774\ud2b8\ub418\uc5c8\uc2b5\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR_90=The provided value \
+### "%s" is not a valid numeric string because it contained character %s at \
+### position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE_91=\ubb38\uc790\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc740 \uc720\ud6a8\ud55c \uc22b\uc790 \ubb38\uc790\uc5f4\uc774 \uc544\ub2d9\ub2c8\ub2e4.  \uc22b\uc790 \ubb38\uc790\uc5f4 \uac12\uc740 \ud558\ub098 \uc774\uc0c1\uc758 \uc22b\uc790\ub098 \uacf5\ubc31\uc744 \ud3ec\ud568\ud574\uc57c \ud569\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE_92=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS_93=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE_94=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID_95=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450 \uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID_96=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID_97=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS_98=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN_99=\uc704\uce58 %2$d \ub610\ub294 \uadf8 \uadfc\ucc98\uc5d0\uc11c "DESC" \ud1a0\ud070\uc744 \uc77d\ub294 \ub3d9\uc548 \uc608\uae30\uce58 \uc54a\uc740 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: %3$s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC_100="DESC" \ud1a0\ud070\uc774 \uc788\uc5b4\uc57c \ud558\ub294\ub370 \"%2$s\" \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE_101=\uc704\uce58 %2$d \ub610\ub294 \uadf8 \uadfc\ucc98\uc5d0\uc11c "DESC" \ud1a0\ud070 \uac12\uc744 \uc77d\ub294 \ub3d9\uc548 \uc608\uae30\uce58 \uc54a\uc740 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: %3$s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS_102=\uc704\uce58 %2$d\uc5d0 \ub2eb\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE_103=\uc704\uce58 %3$d\uc758 \ub2eb\ub294 \uad04\ud638 \ub4a4\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS_104=The provided \
+### value "%s" could not be parsed as an attribute syntax description because a \
+### single quote was expected at position %d but the character %s was found \
+### instead
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE_105=The provided value \
+### could not be parsed as a printable string because it was null or empty.  A \
+### printable string must contain at least one character
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER_106=The provided \
+### value "%s" could not be parsed as a printable string because it contained an \
+### invalid character %s at position %d
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD_107=The provided value "*" \
+### could not be parsed as a substring assertion because it consists only of a \
+### wildcard character and zero-length substrings are not allowed
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS_108=The provided \
+### value "%s" could not be parsed as a substring assertion because it contains \
+### consecutive wildcard characters at position %d and zero-length substrings are \
+### not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT_109=\uc81c\uacf5\ub41c \uac12 %s\uc740(\ub294) \ub108\ubb34 \uc9e7\uc544 \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \ub420 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR_110=\uc138\uae30 \ub610\ub294 \uc5f0\ub3c4 \uc0ac\uc591\uc5d0 '%2$s' \ubb38\uc790\uac00 \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH_111=%2$s\uc774(\uac00) \uc720\ud6a8\ud55c \uc6d4 \uc0ac\uc591\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY_112=%2$s\uc774(\uac00) \uc720\ud6a8\ud55c \uc77c \uc0ac\uc591\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR_113=%2$s\uc774(\uac00) \uc720\ud6a8\ud55c \uc2dc\uac04 \uc0ac\uc591\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE_114=%2$s\uc774(\uac00) \uc720\ud6a8\ud55c \ubd84 \uc0ac\uc591\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR_115=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND_116=%2$s\uc774(\uac00) \uc720\ud6a8\ud55c \ucd08\u00b7\uc0ac\uc591\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET_117=%2$s\uc774(\uac00) \uc720\ud6a8\ud55c GMT \uc624\ud504\uc14b\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 %1$s\uc740(\ub294) \uc720\ud6a8\ud55c UTC \uc2dc\uac04 \uac12\uc774 \uc544\ub2d9\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE_118=\uc81c\uacf5\ub41c \uac12 %s\uc744(\ub97c) \uc720\ud6a8\ud55c UTC \uc2dc\uac04\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE_119=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c DIT \ucee8\ud150\ud2b8 \uaddc\uce59\u00b7\uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS_120=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE_121=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID_122=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450 \uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID_123=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID_124=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS_125=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_126=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS_127=DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \uad6c\uc870\uc801 \uac1d\uccb4 \ud074\ub798\uc2a4 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL_128=DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) OID\uac00 %s(%s)\uc778 \uac1d\uccb4 \ud074\ub798\uc2a4\uc640 \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.  \uc774 \uac1d\uccb4 \ud074\ub798\uc2a4\ub294 \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc788\uc9c0\ub9cc \uad6c\uc870\uc801\uc774 \uc544\ub2cc %s(\uc73c)\ub85c \uc815\uc758\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS_129=DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \ubcf4\uc870 \uac1d\uccb4 \ud074\ub798\uc2a4 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY_130=DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \ubcf4\uc870 \uac1d\uccb4 \ud074\ub798\uc2a4 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \uac1d\uccb4 \ud074\ub798\uc2a4\ub294 \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc788\uc9c0\ub9cc \ubcf4\uc870\uac00 \uc544\ub2cc %s(\uc73c)\ub85c \uc815\uc758\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR_131=DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \ud544\uc218 \uc18d\uc131 \uc720\ud615 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR_132=DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \uc120\ud0dd \uc18d\uc131 \uc720\ud615 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR_133=DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \uae08\uc9c0\ub41c \uc18d\uc131 \uc720\ud615 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS_134=\uc704\uce58 %2$d\uc5d0 \uc791\uc740 \ub530\uc634\ud45c\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 %3$s \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE_135=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS_136=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$c' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE_137=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID_138=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450 \uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID_139=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$c\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID_140=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$c\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS_141=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_142=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$c\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS_143=\uc774\ub984 \ud615\uc2dd \uc124\uba85 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \uad6c\uc870\uc801 \uac1d\uccb4 \ud074\ub798\uc2a4 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL_144=\uc774\ub984 \ud615\uc2dd \uc124\uba85 \"%s\"\uc774(\uac00) OID\uac00 %s(%s)\uc778 \uac1d\uccb4 \ud074\ub798\uc2a4\uc640 \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \uac1d\uccb4 \ud074\ub798\uc2a4\ub294 \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc788\uc9c0\ub9cc \uad6c\uc870\uc801\uc774 \uc544\ub2cc %s(\uc73c)\ub85c \uc815\uc758\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR_145=OID\uac00 %s\uc778 \uc774\ub984 \ud615\uc2dd\uc5d0 \ub300\ud55c \uc815\uc758\uc5d0\uc11c \ud544\uc218 \uc18d\uc131 \"%s\"\uc744(\ub97c) \ud3ec\ud568\ud574\uc57c \ud55c\ub2e4\uace0 \uc120\uc5b8\ud588\uc2b5\ub2c8\ub2e4.  \uc774 \uc774\ub984 \ub610\ub294 OID\uc640 \uc77c\uce58\ud558\ub294 \uc18d\uc131 \uc720\ud615\uc774 \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc5c6\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR_146=OID\uac00 %s\uc778 \uc774\ub984 \ud615\uc2dd\uc5d0 \ub300\ud55c \uc815\uc758\uc5d0\uc11c \uc120\ud0dd \uc18d\uc131 \"%s\"\uc744(\ub97c) \ud3ec\ud568\ud574\uc57c \ud55c\ub2e4\uace0 \uc120\uc5b8\ud588\uc2b5\ub2c8\ub2e4.  \uc774 \uc774\ub984 \ub610\ub294 OID\uc640 \uc77c\uce58\ud558\ub294 \uc18d\uc131 \uc720\ud615\uc774 \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc5c6\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS_147=\uc5f0\uacb0\ub418\ub294 \uad6c\uc870\uc801 \uac1d\uccb4 \ud074\ub798\uc2a4\ub97c \uc9c0\uc815\ud558\uc9c0 \uc54a\uc558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS_148=\uc704\uce58 %2$d\uc5d0 \uc791\uc740 \ub530\uc634\ud45c\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 %3$c \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc774\ub984 \ud615\uc2dd \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE_149=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS_150=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE_151=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID_152=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450\uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID_153=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID_154=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS_155=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_156=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX_157=\uc77c\uce58 \uaddc\uce59 \uc124\uba85 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \uc18d\uc131 \uad6c\ubb38 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX_158=\uc5f0\uacb0\ub418\ub294 \uc18d\uc131 \uad6c\ubb38\uc744 \uc9c0\uc815\ud558\uc9c0 \uc54a\uc558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS_159=\uc704\uce58 %2$d\uc5d0 \uc791\uc740 \ub530\uc634\ud45c\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 %3$s \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE_160=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS_161=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE_162=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID_163=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450\uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID_164=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID_165=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE_166=\uc9c0\uc815\ub41c \uc77c\uce58 \uaddc\uce59 %2$s\uc744(\ub97c) \uc54c \uc218 \uc5c6\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS_167=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_168=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR_169=\uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85 \"%s\"\uc774(\uac00) \uc11c\ubc84 \uc2a4\ud0a4\ub9c8\uc5d0 \uc815\uc758\ub418\uc9c0 \uc54a\uc740 \uc18d\uc131 \uc720\ud615 %s\uacfc(\uc640) \uc5f0\uacb0\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR_170=\uc5f0\uacb0\ub41c OID\uc5d0\uc11c \uc0ac\uc6a9\ud560 \uc218 \uc788\ub294 \uc18d\uc131 \uc720\ud615 \uc9d1\ud569\uc744 \uc9c0\uc815\ud558\uc9c0 \uc54a\uc558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS_171=\uc704\uce58 %2$d\uc5d0 \uc791\uc740 \ub530\uc634\ud45c\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 %3$s \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc77c\uce58 \uaddc\uce59 \uc0ac\uc6a9 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE_172=\ube44\uc5b4 \uc788\uac70\ub098 \uacf5\ubc31\ub9cc \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c DIT \uad6c\uc870 \uaddc\uce59\u00b7\uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS_173=\uc704\uce58 %2$d\uc5d0 \uc5ec\ub294 \uad04\ud638\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 '%3$s' \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE_174=\ub514\ub809\ud1a0\ub9ac \uc11c\ubc84\uc5d0 \ucd94\uac00 \ub370\uc774\ud130\ub97c \uc81c\uacf5\ud574\uc57c \ud558\ub294\ub370 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID_175=\uc704\uce58 %3$d\uc5d0\uc11c \uaddc\uce59 \uc544\uc774\ub514\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS_176=\uc704\uce58 %2$d\uc5d0 \uc608\uae30\uce58 \uc54a\uc740 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_177=\uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM_178=\uc54c \uc218 \uc5c6\ub294 \uc774\ub984 \ud615\uc2dd %2$s\uc744(\ub97c) \ucc38\uc870\ud558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID_179=\uc0c1\uc704 DIT \uad6c\uc870 \uaddc\uce59\uc5d0 \ub300\ud574 \uc54c \uc218 \uc5c6\ub294 \uaddc\uce59 \uc544\uc774\ub514 %2$d\uc744(\ub97c) \ucc38\uc870\ud558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM_180=\uaddc\uce59\uc758 \uc774\ub984 \ud615\uc2dd\uc744 \uc9c0\uc815\ud558\uc9c0 \uc54a\uc558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS_181=\uc704\uce58 %2$d\uc5d0 \uc791\uc740 \ub530\uc634\ud45c\uac00 \uc788\uc5b4\uc57c \ud558\ub294\ub370 %3$s \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID_182=\uc22b\uc790 OID\uc758 \uc704\uce58 %2$d\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450\uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID_183=\uc22b\uc790 OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID_184=\uc22b\uc790\uac00 \uc544\ub2cc OID\uc758 \uc704\uce58 %3$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) DIT \uad6c\uc870 \uaddc\uce59 \uc124\uba85\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT_185=\uc81c\uacf5\ub41c \uac12 "\%s\"\uc740(\ub294) \ub108\ubb34 \uc9e7\uc544 \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ubc88\ud638 \uac12\uc774 \ub420 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE_186=\uc704\uce58 %3$d\uc5d0 \uc788\ub294 \ubb38\uc790 %2$s\uc774(\uac00) \uc778\uc1c4\ud560 \uc218 \uc788\ub294 \uc720\ud6a8\ud55c \ubb38\uc790\uc5f4\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ubc88\ud638\ub97c \ud3ec\ud568\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR_187=\uc704\uce58 %3$d\uc5d0 \uc788\ub294 \ubb38\uc790 %2$s\uc774(\uac00) \uc778\uc1c4\ud560 \uc218 \uc788\ub294 \uc720\ud6a8\ud55c \ubb38\uc790\uc5f4\ub3c4 \uc544\ub2c8\uace0 \ud154\ub809\uc2a4 \ubc88\ud638 \uad6c\uc131\uc694\uc18c\ub97c \uad6c\ubd84\ud558\ub294 \ub2ec\ub7ec \uae30\ud638\ub3c4 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ubc88\ud638\ub97c \ud3ec\ud568\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED_188=\ub2ec\ub7ec\ub85c \uad6c\ubd84\ub41c \uc138 \uac1c\uc758 \uc778\uc1c4\ud560 \uc218 \uc788\ub294 \ubb38\uc790\uc5f4\uc744 \uc77d\uae30 \uc804\uc5d0 \uac12\uc758 \ub05d\uc5d0 \ub3c4\ub2ec\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc740(\ub294) \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ubc88\ud638\ub97c \ud3ec\ud568\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY_189=\ube44\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \ud329\uc2a4 \ubc88\ud638\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE_190=\uc704\uce58 %3$d\uc5d0 \uc788\ub294 \ubb38\uc790 %2$s\uc774(\uac00) \uc778\uc1c4\ud560 \uc218 \uc788\ub294 \uc720\ud6a8\ud55c \ubb38\uc790\uc5f4\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \ud329\uc2a4 \ubc88\ud638\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR_191=\ub2ec\ub7ec \uae30\ud638\ub85c \ub05d\ub098\uc9c0\ub9cc \ub2ec\ub7ec \uae30\ud638 \ub4a4\uc5d0 \ud329\uc2a4 \ub9e4\uac1c \ubcc0\uc218\uac00 \uc640\uc57c \ud558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \ud329\uc2a4 \ubc88\ud638\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER_192=\uc704\uce58 %3$d \ubc0f %4$d \uc0ac\uc774\uc5d0 \uc788\ub294 \ubb38\uc790\uc5f4 \"%2$s\"\uc774(\uac00) \uc720\ud6a8\ud55c \ud329\uc2a4 \ub9e4\uac1c \ubcc0\uc218\uac00 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \ud329\uc2a4 \ubc88\ud638\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN_193=DN \ubd80\ubd84\uc744 \uad6c\ubb38 \ubd84\uc11d\ud558\ub294 \ub3d9\uc548 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uc774\ub984 \ubc0f \uc120\ud0dd\uc801 UID \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT_194=\uc704\uce58 %3$d\uc5d0\uc11c UID \ubd80\ubd84\uc5d0 \uc798\ubabb\ub41c \uc774\uc9c4 \uc22b\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 "%s"\uc744(\ub97c) \uc720\ud6a8\ud55c \uc774\ub984 \ubc0f \uc120\ud0dd\uc801 UID \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY_195=\ube44\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ud130\ubbf8\ub110 \uc2dd\ubcc4\uc790\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE_196=\uc704\uce58 %3$d\uc5d0 \uc788\ub294 \ubb38\uc790 %2$s\uc774(\uac00) \uc778\uc1c4\ud560 \uc218 \uc788\ub294 \uc720\ud6a8\ud55c \ubb38\uc790\uc5f4\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ud130\ubbf8\ub110 \uc2dd\ubcc4\uc790\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR_197=\ub2ec\ub7ec \uae30\ud638\ub85c \ub05d\ub098\uc9c0\ub9cc \ud574\ub2f9 \ub2ec\ub7ec \uae30\ud638 \ub4a4\uc5d0 TTX \ub9e4\uac1c \ubcc0\uc218\uac00 \uc640\uc57c \ud558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ud130\ubbf8\ub110 \uc2dd\ubcc4\uc790\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON_198=\ub9e4\uac1c \ubcc0\uc218 \ubb38\uc790\uc5f4\uc5d0 \uc774\ub984\uacfc \uac12\uc744 \uad6c\ubd84\ud558\ub294 \ucf5c\ub860\uc774 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ud130\ubbf8\ub110 \uc2dd\ubcc4\uc790\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER_199=\ubb38\uc790\uc5f4 \"%2$s\"\uc774(\uac00) \uc720\ud6a8\ud55c TTX \ub9e4\uac1c \ubcc0\uc218 \uc774\ub984\uc774 \uc544\ub2c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \ud154\ub809\uc2a4 \ud130\ubbf8\ub110 \uc2dd\ubcc4\uc790\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE_200=\ube44\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12\uc744 \ub2e4\ub978 \uba54\uc77c\ud568 \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE_201=\ub2ec\ub7ec \uae30\ud638 \uc55e\uc5d0 \uba54\uc77c\ud568 \uc720\ud615\uc774 \uc5c6\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ub2e4\ub978 \uba54\uc77c\ud568 \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR_202=\uc704\uce58 %3$d\uc5d0\uc11c \uba54\uc77c\ud568 \uc720\ud615\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \ub2e4\ub978 \uba54\uc77c\ud568 \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX_203=\ub2ec\ub7ec \uae30\ud638 \ub4a4\uc5d0 \uba54\uc77c\ud568\uc774 \uc5c6\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ub2e4\ub978 \uba54\uc77c\ud568 \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR_204=\uc704\uce58 %3$d\uc5d0\uc11c \uba54\uc77c\ud568\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \ub2e4\ub978 \uba54\uc77c\ud568 \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC_205=# \ubb38\uc790 \uc55e\uc5d0 \uac1d\uccb4 \ud074\ub798\uc2a4 \uc774\ub984 \ub610\ub294 OID\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR_206=\uc704\uce58 %4$d\uc5d0\uc11c \uae30\uc900 \ubd80\ubd84 %2$s\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %2$c\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN_207=\uae30\uc900 \ubd80\ubd84 %2$s\uc5d0 \uccab \ubc88\uc9f8 \uc5ec\ub294 \uad04\ud638\uc5d0 \ud574\ub2f9\ud558\ub294 \ub2eb\ub294 \uad04\ud638\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK_208=\uae30\uc900 \ubd80\ubd84 %2$s\uc774(\uac00) \ubb3c\uc74c\ud45c\ub85c \uc2dc\uc791\ub418\ub294\ub370 \ub4a4\uc5d0 \ubb38\uc790\uc5f4 "true" \ub610\ub294 "false"\uac00 \uc5c6\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR_209=\uae30\uc900 \ubd80\ubd84 %2$s\uc774(\uac00) \uc18d\uc131 \uc720\ud615\uacfc \uc77c\uce58 \uc720\ud615\uc744 \uad6c\ubd84\ud558\ub294 \ub2ec\ub7ec \uae30\ud638\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR_210=\uae30\uc900 \ubd80\ubd84 %2$s\uc774(\uac00) \ub2ec\ub7ec \uae30\ud638 \uc55e\uc5d0 \uc18d\uc131 \uc720\ud615\uc744 \uc9c0\uc815\ud558\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE_211=\uae30\uc900 \ubd80\ubd84 %2$s\uc774(\uac00) \ub2ec\ub7ec \uae30\ud638 \ub4a4\uc5d0 \uc77c\uce58 \uc720\ud615\uc744 \uc9c0\uc815\ud558\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE_212=\uae30\uc900 \ubd80\ubd84 %2$s\uc5d0 \uc704\uce58 %3$d\uc5d0\uc11c \uc2dc\uc791\ub418\ub294 \uc798\ubabb\ub41c \uc77c\uce58 \uc720\ud615\uc774 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP_213=\uac1d\uccb4 \ud074\ub798\uc2a4\uc640 \uae30\uc900\uc744 \uad6c\ubd84\ud558\ub294 # \ubb38\uc790\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC_214=# \ubb38\uc790 \uc55e\uc5d0 \uac1d\uccb4 \ud074\ub798\uc2a4 \uc774\ub984 \ub610\ub294 OID\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID_215=\uc704\uce58 %3$d\uc5d0\uc11c \uac1d\uccb4 \ud074\ub798\uc2a4\ub97c \uc9c0\uc815\ud558\ub294 \uc22b\uc790 OID %2$s\uc5d0 \ub9c8\uce68\ud45c\uac00 \ub450 \uac1c \uc5f0\uc18d\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID_216=\uc704\uce58 %4$d\uc5d0\uc11c \uac1d\uccb4 \ud074\ub798\uc2a4\ub97c \uc9c0\uc815\ud558\ub294 \uc22b\uc790 OID %2$s\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %3$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME_217=\uc704\uce58 %4$d\uc5d0\uc11c \uac1d\uccb4 \ud074\ub798\uc2a4 \uc774\ub984 %2$s\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790 %3$s\uc774(\uac00) \ud3ec\ud568\ub418\uc5b4 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP_218=\uae30\uc900\uacfc \ubc94\uc704\ub97c \uad6c\ubd84\ud558\ub294 # \ubb38\uc790\uac00 \ud3ec\ud568\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE_219=\ub9c8\uc9c0\ub9c9 # \ubb38\uc790 \ub4a4\uc5d0 \ubc94\uc704\uac00 \uc81c\uacf5\ub418\uc5b4 \uc788\uc9c0 \uc54a\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE_220=\uc9c0\uc815\ub41c \ubc94\uc704 %2$s\uc774(\uac00) \uc798\ubabb\ub418\uc5c8\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA_221=# \ubb38\uc790 \uc0ac\uc774\uc5d0 \uae30\uc900\uc744 \uc9c0\uc815\ud558\uc9c0 \uc54a\uc558\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \ud5a5\uc0c1\ub41c \uac00\uc774\ub4dc \uac12\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE_222=\uc81c\uacf5\ub41c \uac12 %s\uc744(\ub97c) \uc720\ud6a8\ud55c OID\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: %s
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE_223=An unexpected \
+### error occurred while trying to normalize value %s as a generalized time \
+### value:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE_224=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseExactOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE_225=An error occurred while \
+### attempting to compare two objects using the caseExactOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE_226=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE_227=An error occurred while \
+### attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE_228=An error \
+### occurred while attempting to compare two AttributeValue objects using the \
+### generalizedTimeOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE_229=An error occurred \
+### while attempting to compare two objects using the \
+### generalizedTimeOrderingMatch matching rule because the objects were of an \
+### unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+### value objects may be compared
+###SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE_230=An error occurred while \
+### attempting to compare two AttributeValue objects using the \
+### integerOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE_231=An error occurred while \
+### attempting to compare two objects using the integerOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE_232=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### numericStringOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE_233=An error occurred \
+### while attempting to compare two objects using the numericStringOrderingMatch \
+### matching rule because the objects were of an unsupported type %s.  Only byte \
+### arrays, ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE_234=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### octetStringOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE_235=An error occurred while \
+### attempting to compare two objects using the octetStringOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH_236=The provided value "%s" has \
+### an invalid length for a UUID.  All UUID values must have a length of exactly \
+### 36 bytes, but the provided value had a length of %d bytes
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH_237=The provided value "%s" should \
+### have had a dash at position %d, but the character '%s' was found instead
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX_238=The provided value "%s" should \
+### have had a hexadecimal digit at position %d, but the character '%s' was found \
+### instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH_239=\ub514\ub809\ud1a0\ub9ac \ubb38\uc790\uc5f4 \uad6c\ubb38\uc774 \uc788\ub294 \uc18d\uc131\uc5d0 \uae38\uc774\uac00 0\uc778 \uac12\uc744 \ud3ec\ud568\ud560 \uc218 \uc788\ub294\uc9c0 \uc5ec\ubd80\ub97c \ub098\ud0c0\ub0c5\ub2c8\ub2e4.  \uc774 \uae30\ub2a5\uc740 LDAP \uc0ac\uc591\uc5d0\uc11c \uae30\uc220\uc801\uc73c\ub85c \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uc9c0\ub9cc \uc774\uc804 \ub514\ub809\ud1a0\ub9ac \uc11c\ubc84 \ub9b4\ub9ac\uc2a4\uc640\uc758 \uc5ed\ud638\ud658\uc131\uc5d0 \uc720\uc6a9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH_240=An \
+### error occurred while trying to determine the value of the %s configuration \
+### attribute, which indicates whether directory string attributes should be \
+### allowed to have zero-length values:  %s
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE_241=The \
+### operation attempted to assign a zero-length value to an attribute with the \
+### directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH_242=\uad6c\uc131 \ud56d\ubaa9 %2$s\uc758 %1$s \uc18d\uc131\uc774 \uc0c8 \uac12 %3$s(\uc73c)\ub85c \uc5c5\ub370\uc774\ud2b8\ub418\uc5c8\uc2b5\ub2c8\ub2e4.
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR_243=The provided \
+### authPassword value had an invalid scheme character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_244=The provided authPassword value \
+### had a zero-length scheme element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR_245=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the scheme and authInfo elements
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR_246=The provided \
+### authPassword value had an invalid authInfo character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_247=The provided authPassword \
+### value had a zero-length authInfo element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR_248=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the authInfo and authValue elements
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS_249=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### it did not start with a parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE_250=The provided value "%s" could not \
+### be parsed by the integer first component matching rule because it did not \
+### have any non-space characters after the opening parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT_251=The provided value "%s" \
+### could not be parsed by the integer first component matching rule because it \
+### did not have any space characters after the first component
+###SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT_252=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### the first component does not appear to be an integer value
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE_253=No value was given to decode by \
+### the user password attribute syntax
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE_254=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not start with the opening curly brace ("{") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE_255=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not contain a closing curly brace ("}") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME_256=Unable to decode the provided \
+### value according to the user password syntax because the value does not \
+### contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID_257=\uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c RFC 3672 \ud558\uc704 \ud2b8\ub9ac \uc0ac\uc591\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID_258=\uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uc808\ub300 \ud558\uc704 \ud2b8\ub9ac \uc0ac\uc591\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID_259=\uc81c\uacf5\ub41c \uac12 \"%s\"\uc744(\ub97c) \uc720\ud6a8\ud55c \uc0c1\ub300 \ud558\uc704 \ud2b8\ub9ac \uc0ac\uc591\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER_260=The provided value %s is not \
+### allowed for attributes with a Integer syntax
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR_261=The provided \
+### authPassword value had an invalid authValue character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE_262=The provided authPassword \
+### value had a zero-length authValue element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR_263=The provided \
+### authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER_264=\uc704\uce58 %2$d\uc5d0 \uc798\ubabb\ub41c \ubb38\uc790\uac00 \uc788\uae30 \ub54c\ubb38\uc5d0 \uc81c\uacf5\ub41c \uac12 \"%1$s\"\uc744(\ub97c) \uc18d\uc131 \uad6c\ubb38 \ud655\uc7a5\uc73c\ub85c \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION_265=\uc798\ubabb\ub41c \ud655\uc7a5 \ub54c\ubb38\uc5d0 \uc18d\uc131 \uad6c\ubb38\uc744 \uad6c\ubb38 \ubd84\uc11d\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4.%s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE_266=The definition \
+### for objectclass %s is invalid because it has an objectclass type of %s but \
+### this is incompatible with the objectclass type %s for the superior class %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP_267=The \
+### definition for objectclass %s is invalid because it is defined as a \
+### structural class but its superior chain does not include the "top" \
+### objectclass
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
+### for attribute type %s is invalid because its attribute usage %s is not the \
+### same as the usage for its superior type %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \
+### definition for attribute type %s is invalid because it is defined as a \
+### collective type but the superior type %s is not collective
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
+### definition for attribute type %s is invalid because it is not defined as a \
+### collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=\uc5f0\uacb0\ub41c \uad6c\uc870\uc801 \uac1d\uccb4 \ud074\ub798\uc2a4 %3$s\uc5d0 \ud544\uc694\ud55c \uc18d\uc131 \uc720\ud615 %2$s \uc0ac\uc6a9\uc744 \uae08\uc9c0\ud558\uae30 \ub54c\ubb38\uc5d0 DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4.
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=\uc5f0\uacb0\ub41c \ubcf4\uc870 \uac1d\uccb4 \ud074\ub798\uc2a4 %3$s\uc5d0 \ud544\uc694\ud55c \uc18d\uc131 \uc720\ud615 %2$s \uc0ac\uc6a9\uc744 \uae08\uc9c0\ud558\uae30 \ub54c\ubb38\uc5d0 DIT \ucee8\ud150\ud2b8 \uaddc\uce59 \"%s\"\uc774(\uac00) \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4.
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \
+### for attribute type %s is invalid because it is declared COLLECTIVE but does \
+### not have a usage of userApplications
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \
+### definition for attribute type %s is invalid because it is declared \
+### NO-USER-MODIFICATION but does not have an operational usage
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR_275=The \
+### provided value %s is not a valid generalized time value because it contains \
+### illegal character %s in the fraction component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION_276=The provided \
+### value %s is not a valid generalized time value because it does not contain at \
+### least one digit after the period to use as the fractional component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO_277=The provided \
+### value %s is not a valid generalized time value because it does not end with \
+### 'Z' or a time zone offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME_278=The provided value \
+### %s is not a valid generalized time value because it represents an invalid \
+### time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED_279=\uc2a4\ud0a4\ub9c8 \uc694\uc18c\ub97c \uac00\uc838\uc624\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4: %s, %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE_280=The collation rule %s under matching rule entry %s is invalid as the locale %s is not supported by JVM
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT_281=The provided collation rule %s does not contain a valid format of OID:LOCALE
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=The provided value "%s" could not be parsed as a valid distinguished name because an attribute value started with a character at position %d that needs to be escaped
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR_283=The provided value "%s" could not be parsed as a valid attribute type definition because character '%c' at position %d is not allowed in an attribute type name
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_284=The provided value "%s" could not be parsed as a valid attribute type definition because the underscore character is not allowed in an attribute type name unless the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_285=The provided value "%s" could not be parsed as a valid attribute type definition because the hyphen character is not allowed as the first character of an attribute type name
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_286=The provided value "%s" could not be parsed as a valid attribute type definition because the underscore character is not allowed as the first character of an attribute type name even if the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_287=The provided value "%s" could not be parsed as a valid attribute type definition because the digit '%c' is not allowed as the first character of an attribute type name unless the name is specified as an OID or the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR_288=The provided value "%s" could not be parsed as a valid object class definition because character '%c' at position %d is not allowed in an object class name
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_289=The provided value "%s" could not be parsed as a valid object class definition because the underscore character is not allowed in an object class name unless the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_290=The provided value "%s" could not be parsed as a valid object class definition because the hyphen character is not allowed as the first character of an object class name
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_291=The provided value "%s" could not be parsed as a valid object class definition because the underscore character is not allowed as the first character of an object class name even if the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_292=The provided value "%s" could not be parsed as a valid object class definition because the digit '%c' is not allowed as the first character of an object class name unless the name is specified as an OID or the %s configuration option is enabled
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_CN.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_CN.properties
new file mode 100755
index 0000000..05570f5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_CN.properties
@@ -0,0 +1,531 @@
+# 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
+#
+#      Copyright 2009 Sun Microsystems, Inc.
+#
+# Global directives
+#
+global.ordinal=-1
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE_1=Unable to retrieve \
+### approximate matching rule %s used as the default for the %s attribute syntax. \
+### Approximate matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE_2=Unable to retrieve \
+### equality matching rule %s used as the default for the %s attribute syntax. \
+### Equality matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE_3=Unable to retrieve \
+### ordering matching rule %s used as the default for the %s attribute syntax. \
+### Ordering matches will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE_4=Unable to retrieve \
+### substring matching rule %s used as the default for the %s attribute syntax. \
+### Substring matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN_5=The provided value "%s" is not \
+### allowed for attributes with a Boolean syntax.  The only allowed values are \
+### 'TRUE' and 'FALSE'
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT_6=The provided value "%s" is too \
+### short to be a valid bit string.  A bit string must be a series of binary \
+### digits surrounded by single quotes and followed by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED_7=The provided value "%s" is not \
+### a valid bit string because it is not surrounded by single quotes and followed \
+### by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT_8=The provided value "%s" is \
+### not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=\u63d0\u4f9b\u7684\u503c "%s" \u4e0d\u662f\u6709\u6548\u7684\u56fd\u5bb6/\u5730\u533a\u5b57\u7b26\u4e32\uff0c\u56e0\u4e3a\u957f\u5ea6\u5e76\u975e\u6070\u597d\u4e3a\u4e24\u4e2a\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE_10=\u63d0\u4f9b\u7684\u503c "%s" \u4e0d\u662f\u6709\u6548\u7684\u56fd\u5bb6/\u5730\u533a\u5b57\u7b26\u4e32\uff0c\u56e0\u4e3a\u5b83\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u4e0d\u53ef\u6253\u5370\u7684\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=\u63d0\u4f9b\u7684\u503c "%s" \u4e0d\u662f\u6709\u6548\u7684\u4f20\u9001\u65b9\u6cd5\u503c\uff0c\u56e0\u4e3a\u5b83\u4e0d\u5305\u542b\u4efb\u4f55\u5143\u7d20
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT_12=\u63d0\u4f9b\u7684\u503c "%s" \u4e0d\u662f\u6709\u6548\u7684\u4f20\u9001\u65b9\u6cd5\u503c\uff0c\u56e0\u4e3a "%s" \u4e0d\u662f\u6709\u6548\u7684\u65b9\u6cd5
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT_13=The provided value "%s" \
+### is too short to be a valid generalized time value
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR_14=The provided value \
+### "%s" is not a valid generalized time value because the '%s' character is not \
+### allowed in the century or year specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH_15=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid month \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY_16=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid day \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR_17=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid hour \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE_18=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid minute \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND_19=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid second \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND_20=The provided \
+### value "%s" is not a valid generalized time value because the sub-second \
+### component is not valid (between 1 and 3 numeric digits)
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND_21=The provided value \
+### "%s" is not a valid generalized time value because the sub-second value may \
+### not contain more than three digits
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET_22=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+### offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR_23=The provided value \
+### "%s" is not a valid generalized time value because it contains an invalid \
+### character '%s' at position %d
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE_24=The provided value \
+### "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_25=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d: %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA_26=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u6700\u540e\u4e00\u4e2a\u975e\u7a7a\u683c\u5b57\u7b26\u662f\u9017\u53f7\u6216\u5206\u53f7
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT_27=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u6570\u5b57 '%s' \u4f5c\u4e3a\u5c5e\u6027\u540d\u79f0\u4e2d\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR_28=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u5c5e\u6027\u540d\u79f0\u4e2d\u4e0d\u5141\u8bb8\u4f7f\u7528\u4f4d\u7f6e %3$d \u5904\u7684\u5b57\u7b26 '%2$c'
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR_29=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u5c5e\u6027\u540d\u79f0\u4e2d\u4e0d\u5141\u8bb8\u4f7f\u7528\u4e0b\u5212\u7ebf\u5b57\u7b26\uff0c\u9664\u975e\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH_30=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u8fde\u5b57\u7b26\u4f5c\u4e3a\u5c5e\u6027\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE_31=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u4e0b\u5212\u7ebf\u5b57\u7b26\u4f5c\u4e3a\u5c5e\u6027\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\uff0c\u5373\u4f7f\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT_32=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u6570\u5b57 '%c' \u4f5c\u4e3a\u5c5e\u6027\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\uff0c\u9664\u975e\u5c06\u540d\u79f0\u6307\u5b9a\u4e3a OID \u6216\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME_33=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u5b83\u5305\u542b\u7684 RDN \u5177\u6709\u7a7a\u5c5e\u6027\u540d\u79f0
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD_34=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u89e3\u6790\u7684\u5c5e\u6027\u540d\u79f0 %s \u5305\u542b\u4e00\u4e2a\u53e5\u70b9\uff0c\u4f46\u8be5\u540d\u79f0\u4f3c\u4e4e\u4e0d\u662f\u6709\u6548\u7684 OID
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME_35=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u6700\u540e\u4e00\u4e2a\u975e\u7a7a\u683c\u5b57\u7b26\u662f\u5c5e\u6027\u540d\u79f0 '%s' \u7684\u4e00\u90e8\u5206
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL_36=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u5c5e\u6027\u540d\u79f0 "%s" \u540e\u9762\u7684\u4e0b\u4e00\u4e2a\u975e\u7a7a\u683c\u5b57\u7b26\u5e94\u8be5\u4e3a\u7b49\u53f7\uff0c\u800c\u5b9e\u9645\u4e3a '%c'
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR_37=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u4f4d\u7f6e %3$d \u5904\u7684\u5b57\u7b26 '%2$c' \u65e0\u6548
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT_38=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u5c5e\u6027\u503c\u4ee5\u4e95\u53f7 (#) \u5f00\u5934\uff0c\u4f46\u6ca1\u6709\u540e\u8ddf\u4e24\u4e2a\u5341\u516d\u8fdb\u5236\u6570\u5b57\u7684\u6b63\u500d\u6570
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT_39=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u5c5e\u6027\u503c\u4ee5\u4e95\u53f7 (#) \u5f00\u5934\uff0c\u4f46\u5305\u542b\u7684\u5b57\u7b26 %c \u4e0d\u662f\u6709\u6548\u7684\u5341\u516d\u8fdb\u5236\u6570\u5b57
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE_40=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u5728\u5c1d\u8bd5\u89e3\u6790\u67d0\u4e2a RDN \u7ec4\u4ef6\u4e2d\u7684\u5c5e\u6027\u503c\u65f6\u51fa\u73b0\u610f\u5916\u5931\u8d25: "%s"
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE_41=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u67d0\u4e2a RDN \u7ec4\u4ef6\u5305\u542b\u4e00\u4e2a\u7528\u5f15\u53f7\u5f15\u8d77\u6765\u7684\u503c\uff0c\u4f46\u8be5\u503c\u6ca1\u6709\u76f8\u5e94\u7684\u53f3\u5f15\u53f7
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID_42=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u67d0\u4e2a RDN \u7ec4\u4ef6\u5305\u542b\u4e00\u4e2a\u5e26\u6709\u8f6c\u4e49\u5341\u516d\u8fdb\u5236\u6570\u5b57\u7684\u503c\uff0c\u4f46\u6ca1\u6709\u540e\u8ddf\u7b2c\u4e8c\u4e2a\u5341\u516d\u8fdb\u5236\u6570\u5b57
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO_43=The provided value "%s" could \
+### not be parsed as a valid integer because the first digit may not be zero \
+### unless it is the only digit
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH_44=The provided value "%s" \
+### could not be parsed as a valid integer because the dash may only appear if it \
+### is the first character of the value followed by one or more digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER_45=The provided value "%s" \
+### could not be parsed as a valid integer because character '%c' at position %d \
+### is not allowed in an integer value
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE_46=The provided value "%s" could \
+### not be parsed as a valid integer because it did not contain any digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE_47=The provided value "%s" \
+### could not be parsed as a valid integer because it contained only a dash not \
+### followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE_48=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684 OID\uff0c\u56e0\u4e3a\u5b83\u4e0d\u5305\u542b\u4efb\u4f55\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER_49=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684 OID\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS_50=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684 OID\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u6216\u9644\u8fd1\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD_51=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684 OID\uff0c\u56e0\u4e3a\u5b83\u4ee5\u53e5\u70b9\u7ed3\u5c3e
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE_52=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS_53=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE_54=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID_55=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID_56=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID_57=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_58=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS_59=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_60=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u7c7b\u578b\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5c06\u5355\u5f15\u53f7\u4f5c\u4e3a\u6807\u8bb0 %s \u540e\u7684\u7b2c\u4e00\u4e2a\u975e\u7a7a\u767d\u5b57\u7b26\u3002\u4f46\u662f\uff0c\u627e\u5230\u7684\u662f\u5b57\u7b26 %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE_61=The definition for \
+### the attribute type with OID %s declared a superior type with an OID of %s. \
+### No attribute type with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR_62=The definition for \
+### the attribute type with OID %s declared that approximate matching should be \
+### performed using the matching rule "%s".  No such approximate matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR_63=The definition for \
+### the attribute type with OID %s declared that equality matching should be \
+### performed using the matching rule "%s".  No such equality matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR_64=The definition for \
+### the attribute type with OID %s declared that ordering matching should be \
+### performed using the matching rule "%s".  No such ordering matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR_65=The definition for \
+### the attribute type with OID %s declared that substring matching should be \
+### performed using the matching rule "%s".  No such substring matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX_66=The definition for the \
+### attribute type with OID %s declared that it should have a syntax with OID %s. \
+### No such syntax is configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE_67=The definition \
+### for the attribute type with OID %s declared that it should have an attribute \
+### usage of %s.  This is an invalid usage
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS_68=The provided value \
+### "%s" could not be parsed as an attribute type description because a single \
+### quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE_69=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684 objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS_70=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE_71=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID_72=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID_73=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID_74=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_75=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS_76=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_77=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a objectclass \u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5c06\u5355\u5f15\u53f7\u4f5c\u4e3a\u6807\u8bb0 %s \u540e\u7684\u7b2c\u4e00\u4e2a\u975e\u7a7a\u767d\u5b57\u7b26\u3002\u4f46\u662f\uff0c\u627e\u5230\u7684\u662f\u5b57\u7b26 %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS_78=The definition \
+### for the objectclass with OID %s declared a superior objectclass with an OID \
+### of %s.  No objectclass with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS_79=The provided \
+### value "%s" could not be parsed as an objectclass description because a single \
+### quote was expected at position %d but the character %s was found instead
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR_80=The definition \
+### for the objectclass with OID %s declared that it should include required \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR_81=The definition \
+### for the objectclass with OID %s declared that it should include optional \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER_82=The provided value "%s" \
+### cannot be parsed as a valid IA5 string because it contains an illegal \
+### character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE_83=\u6b64\u5c5e\u6027\u6307\u793a\u7535\u8bdd\u53f7\u7801\u5c5e\u6027\u8bed\u6cd5\u662f\u5426\u5e94\u4f7f\u7528\u4e25\u683c\u6a21\u5f0f\uff0c\u8be5\u6a21\u5f0f\u4ec5\u63a5\u53d7 ITU-T E.123 \u683c\u5f0f\u7684\u503c\u3002\u5982\u679c\u542f\u7528\u6b64\u5c5e\u6027\uff0c\u5219\u4f1a\u62d2\u7edd\u4e0d\u4f7f\u7528\u8be5\u683c\u5f0f\u7684\u4efb\u4f55\u503c\u3002\u5982\u679c\u7981\u7528\u6b64\u5c5e\u6027\uff0c\u5219\u4f1a\u63a5\u53d7\u4efb\u4f55\u503c\uff0c\u4f46\u5728\u6267\u884c\u5339\u914d\u65f6\u4ec5\u8003\u8651\u6570\u5b57
+###SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE_84=An error \
+### occurred while trying to retrieve attribute \
+### ds-cfg-strict-format from configuration entry %s:  %s.  The \
+### Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+### for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY_85=\u63d0\u4f9b\u7684\u503c\u4e0d\u662f\u6709\u6548\u7684\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216 Null
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS_86=\u63d0\u4f9b\u7684\u503c "%s" \u4e0d\u662f\u6709\u6548\u7684\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u542f\u7528\u4e86\u4e25\u683c\u7535\u8bdd\u53f7\u7801\u68c0\u67e5\uff0c\u8be5\u503c\u6ca1\u6709\u6309\u7167 ITU-T E.123 \u89c4\u8303\u4ee5\u52a0\u53f7\u5f00\u5934
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR_87=\u63d0\u4f9b\u7684\u503c "%1$s" \u4e0d\u662f\u6709\u6548\u7684\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u542f\u7528\u4e86\u4e25\u683c\u7535\u8bdd\u53f7\u7801\u68c0\u67e5\uff0cITU-T E.123 \u89c4\u8303\u4e0d\u5141\u8bb8\u4f7f\u7528\u4f4d\u7f6e %3$d \u5904\u7684\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS_88=\u63d0\u4f9b\u7684\u503c "%s" \u4e0d\u662f\u6709\u6548\u7684\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u5b83\u4e0d\u5305\u542b\u4efb\u4f55\u6570\u5b57
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE_89=\u5df2\u5c06\u914d\u7f6e\u6761\u76ee %2$s \u4e2d\u7684\u914d\u7f6e\u5c5e\u6027 ds-cfg-strict-format \u503c\u66f4\u65b0\u4e3a %1$s\uff0c\u8be5\u5c5e\u6027\u7528\u4e8e\u6307\u793a\u662f\u5426\u4f7f\u7528\u4e25\u683c\u7535\u8bdd\u53f7\u7801\u8bed\u6cd5\u68c0\u67e5
+###SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR_90=The provided value \
+### "%s" is not a valid numeric string because it contained character %s at \
+### position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE_91=\u63d0\u4f9b\u7684\u503c\u4e0d\u662f\u6709\u6548\u7684\u6570\u5b57\u5b57\u7b26\u4e32\uff0c\u56e0\u4e3a\u5b83\u4e0d\u5305\u542b\u4efb\u4f55\u5b57\u7b26\u3002\u6570\u5b57\u5b57\u7b26\u4e32\u503c\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e00\u4e2a\u6570\u5b57\u6216\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE_92=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS_93=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE_94=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID_95=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID_96=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID_97=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS_98=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN_99=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u5c1d\u8bd5\u4ece\u4f4d\u7f6e %d \u5904\u6216\u9644\u8fd1\u7684\u5b57\u7b26\u4e32\u4e2d\u8bfb\u53d6 "DESC" \u6807\u8bb0\u65f6\u51fa\u73b0\u610f\u5916\u9519\u8bef: %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC_100=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u5e94\u8be5\u4e3a "DESC" \u6807\u8bb0\u7684\u4f4d\u7f6e\u627e\u5230\u4e86\u5b57\u7b26\u4e32 "%s"
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE_101=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u5c1d\u8bd5\u4ece\u4f4d\u7f6e %d \u5904\u6216\u9644\u8fd1\u7684\u5b57\u7b26\u4e32\u4e2d\u8bfb\u53d6 "DESC" \u6807\u8bb0\u503c\u65f6\u51fa\u73b0\u610f\u5916\u9519\u8bef: %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS_102=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u53f3\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE_103=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u53f3\u5706\u62ec\u53f7\u540e\u9762\u7684\u4f4d\u7f6e %3$d \u5904\u627e\u5230\u975e\u6cd5\u5b57\u7b26 %2$s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS_104=The provided \
+### value "%s" could not be parsed as an attribute syntax description because a \
+### single quote was expected at position %d but the character %s was found \
+### instead
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE_105=The provided value \
+### could not be parsed as a printable string because it was null or empty.  A \
+### printable string must contain at least one character
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER_106=The provided \
+### value "%s" could not be parsed as a printable string because it contained an \
+### invalid character %s at position %d
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD_107=The provided value "*" \
+### could not be parsed as a substring assertion because it consists only of a \
+### wildcard character and zero-length substrings are not allowed
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS_108=The provided \
+### value "%s" could not be parsed as a substring assertion because it contains \
+### consecutive wildcard characters at position %d and zero-length substrings are \
+### not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT_109=\u63d0\u4f9b\u7684\u503c %s \u592a\u77ed\u800c\u65e0\u6cd5\u4f5c\u4e3a\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR_110=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5728\u4e16\u7eaa\u6216\u5e74\u4efd\u89c4\u8303\u4e2d\u4f7f\u7528 %s \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH_111=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a %s \u4e0d\u662f\u6709\u6548\u7684\u6708\u4efd\u89c4\u8303
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY_112=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a %s \u4e0d\u662f\u6709\u6548\u7684\u65e5\u671f\u89c4\u8303
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR_113=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a %s \u4e0d\u662f\u6709\u6548\u7684\u5c0f\u65f6\u89c4\u8303
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE_114=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a %s \u4e0d\u662f\u6709\u6548\u7684\u5206\u949f\u89c4\u8303
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR_115=\u63d0\u4f9b\u7684\u503c %1$s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u65e0\u6548\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND_116=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a %s \u4e0d\u662f\u6709\u6548\u7684\u79d2\u949f\u89c4\u8303
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET_117=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u65f6\u95f4\u503c\uff0c\u56e0\u4e3a %s \u4e0d\u662f\u6709\u6548\u7684 GMT \u504f\u79fb
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE_118=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c %s \u89e3\u6790\u4e3a\u6709\u6548\u7684 UTC \u65f6\u95f4: %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE_119=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684 DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS_120=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE_121=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID_122=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID_123=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID_124=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS_125=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_126=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS_127=DIT \u5185\u5bb9\u89c4\u5219 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u7ed3\u6784\u5316 objectclass %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL_128=DIT \u5185\u5bb9\u89c4\u5219 "%s" \u4e0e OID \u4e3a %s (%s) \u7684 objectclass \u76f8\u5173\u8054\u3002\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u5b58\u5728\u6b64 objectclass\uff0c\u4f46\u5b9a\u4e49\u4e3a %s \u800c\u4e0d\u662f\u7ed3\u6784\u5316\u7c7b
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS_129=DIT \u5185\u5bb9\u89c4\u5219 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u8f85\u52a9 objectclass %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY_130=DIT \u5185\u5bb9\u89c4\u5219 "%s" \u4e0e\u8f85\u52a9 objectclass %s \u76f8\u5173\u8054\u3002\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u5b58\u5728\u6b64 objectclass\uff0c\u4f46\u5b9a\u4e49\u4e3a %s \u800c\u4e0d\u662f\u8f85\u52a9\u7c7b
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR_131=DIT \u5185\u5bb9\u89c4\u5219 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u5fc5\u9700\u5c5e\u6027\u7c7b\u578b %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR_132=DIT \u5185\u5bb9\u89c4\u5219 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u53ef\u9009\u5c5e\u6027\u7c7b\u578b %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR_133=DIT \u5185\u5bb9\u89c4\u5219 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u7981\u6b62\u5c5e\u6027\u7c7b\u578b %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS_134=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u5185\u5bb9\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5355\u5f15\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f\u5b57\u7b26 %s
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE_135=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS_136=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%c' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE_137=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID_138=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID_139=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID_140=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS_141=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_142=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS_143=\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u7ed3\u6784\u5316 objectclass %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL_144=\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0 "%s" \u4e0e OID \u4e3a %s (%s) \u7684 objectclass \u76f8\u5173\u8054\u3002\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u5b58\u5728\u6b64 objectclass\uff0c\u4f46\u5b9a\u4e49\u4e3a %s \u800c\u4e0d\u662f\u7ed3\u6784\u5316\u7c7b
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR_145=OID \u4e3a %s \u7684\u540d\u79f0\u683c\u5f0f\u5b9a\u4e49\u58f0\u660e\u5b83\u5e94\u8be5\u5305\u542b\u5fc5\u9700\u5c5e\u6027 "%s"\u3002\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u4e0d\u5b58\u5728\u4e0e\u6b64\u540d\u79f0\u6216 OID \u5339\u914d\u7684\u5c5e\u6027\u7c7b\u578b
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR_146=OID \u4e3a %s \u7684\u540d\u79f0\u683c\u5f0f\u5b9a\u4e49\u58f0\u660e\u5b83\u5e94\u8be5\u5305\u542b\u53ef\u9009\u5c5e\u6027 "%s"\u3002\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u4e0d\u5b58\u5728\u4e0e\u6b64\u540d\u79f0\u6216 OID \u5339\u914d\u7684\u5c5e\u6027\u7c7b\u578b
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS_147=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u672a\u6307\u5b9a\u5173\u8054\u7684\u7ed3\u6784\u5316 objectclass
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS_148=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u540d\u79f0\u683c\u5f0f\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5355\u5f15\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f\u5b57\u7b26 %c
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE_149=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS_150=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE_151=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID_152=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID_153=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID_154=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS_155=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_156=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX_157=\u5339\u914d\u89c4\u5219\u63cf\u8ff0 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u5c5e\u6027\u8bed\u6cd5 %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX_158=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u672a\u6307\u5b9a\u5173\u8054\u7684\u5c5e\u6027\u8bed\u6cd5
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS_159=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5355\u5f15\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f\u5b57\u7b26 %s
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE_160=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS_161=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE_162=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID_163=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID_164=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID_165=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE_166=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6307\u5b9a\u7684\u5339\u914d\u89c4\u5219 %s \u672a\u77e5
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS_167=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_168=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR_169=\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0 "%s" \u4e0e\u670d\u52a1\u5668\u6a21\u5f0f\u4e2d\u672a\u5b9a\u4e49\u7684\u5c5e\u6027\u7c7b\u578b %s \u76f8\u5173\u8054
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR_170=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u672a\u6307\u5b9a\u53ef\u7528\u4e8e\u5173\u8054 OID \u7684\u5c5e\u6027\u7c7b\u578b\u96c6
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS_171=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5339\u914d\u89c4\u5219\u7528\u6cd5\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5355\u5f15\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f\u5b57\u7b26 %s
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE_172=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684 DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a\u6216\u4ec5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS_173=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5de6\u5706\u62ec\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f '%s' \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE_174=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5728\u76ee\u5f55\u670d\u52a1\u5668\u8981\u6c42\u63d0\u4f9b\u66f4\u591a\u6570\u636e\u65f6\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID_175=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u89c4\u5219 ID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS_176=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u610f\u5916\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_177=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM_178=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5f15\u7528\u4e86\u672a\u77e5\u7684\u540d\u79f0\u683c\u5f0f %s
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID_179=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u5f15\u7528\u4e86\u4e0a\u7ea7 DIT \u7ed3\u6784\u89c4\u5219\u7684\u672a\u77e5\u89c4\u5219 ID %d
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM_180=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5b83\u672a\u6307\u5b9a\u89c4\u5219\u7684\u540d\u79f0\u683c\u5f0f
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS_181=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u5e94\u8be5\u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u5355\u5f15\u53f7\uff0c\u4f46\u627e\u5230\u7684\u662f\u5b57\u7b26 %s
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID_182=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID_183=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID_184=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a DIT \u7ed3\u6784\u89c4\u5219\u63cf\u8ff0\uff0c\u56e0\u4e3a\u975e\u6570\u5b57 OID \u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT_185=\u63d0\u4f9b\u7684\u503c "%s" \u592a\u77ed\u800c\u65e0\u6cd5\u4f5c\u4e3a\u6709\u6548\u7684\u7535\u62a5\u53f7\u7801\u503c
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE_186=\u63d0\u4f9b\u7684\u503c "%1$s" \u4e0d\u5305\u542b\u6709\u6548\u7684\u7535\u62a5\u53f7\u7801\uff0c\u56e0\u4e3a\u4f4d\u7f6e %3$d \u5904\u7684\u5b57\u7b26 %2$s \u4e0d\u662f\u6709\u6548\u7684\u53ef\u6253\u5370\u5b57\u7b26\u4e32\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR_187=\u63d0\u4f9b\u7684\u503c "%1$s" \u4e0d\u5305\u542b\u6709\u6548\u7684\u7535\u62a5\u53f7\u7801\uff0c\u56e0\u4e3a\u4f4d\u7f6e %3$d \u5904\u7684\u5b57\u7b26 %2$s \u65e2\u4e0d\u662f\u6709\u6548\u7684\u53ef\u6253\u5370\u5b57\u7b26\u4e32\u5b57\u7b26\uff0c\u4e5f\u4e0d\u662f\u7528\u4e8e\u5206\u9694\u7535\u62a5\u53f7\u7801\u7ec4\u6210\u90e8\u5206\u7684\u7f8e\u5143\u7b26\u53f7
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED_188=\u63d0\u4f9b\u7684\u503c "%s" \u4e0d\u5305\u542b\u6709\u6548\u7684\u7535\u62a5\u53f7\u7801\uff0c\u56e0\u4e3a\u5728\u8bfb\u53d6\u4e09\u4e2a\u4ee5\u7f8e\u5143\u7b26\u53f7\u5206\u9694\u7684\u53ef\u6253\u5370\u5b57\u7b26\u4e32\u4e4b\u524d\u5230\u8fbe\u503c\u672b\u5c3e
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY_189=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684\u4f20\u771f\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE_190=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u4f20\u771f\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u4f4d\u7f6e %3$d \u5904\u7684\u5b57\u7b26 %2$s \u4e0d\u662f\u6709\u6548\u7684\u53ef\u6253\u5370\u5b57\u7b26\u4e32\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR_191=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u4f20\u771f\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u5b83\u4ee5\u7f8e\u5143\u7b26\u53f7\u7ed3\u5c3e\uff0c\u4f46\u8be5\u7f8e\u5143\u7b26\u53f7\u5e94\u540e\u8ddf\u4f20\u771f\u53c2\u6570
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER_192=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u4f20\u771f\u7535\u8bdd\u53f7\u7801\uff0c\u56e0\u4e3a\u4f4d\u7f6e %3$d \u548c %4$d \u4e4b\u95f4\u7684\u5b57\u7b26\u4e32 "%2$s" \u4e0d\u662f\u6709\u6548\u7684\u4f20\u771f\u53c2\u6570
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN_193=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u540d\u79f0\u548c\u53ef\u9009 UID \u503c\uff0c\u56e0\u4e3a\u5728\u5c1d\u8bd5\u89e3\u6790 DN \u90e8\u5206\u65f6\u51fa\u73b0\u9519\u8bef: %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT_194=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u540d\u79f0\u548c\u53ef\u9009 UID \u503c\uff0c\u56e0\u4e3a UID \u90e8\u5206\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u4e8c\u8fdb\u5236\u6570\u5b57 %2$s
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY_195=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u6709\u6548\u7684\u667a\u80fd\u7528\u6237\u7535\u62a5\u7ec8\u7aef\u6807\u8bc6\u7b26\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE_196=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u667a\u80fd\u7528\u6237\u7535\u62a5\u7ec8\u7aef\u6807\u8bc6\u7b26\uff0c\u56e0\u4e3a\u4f4d\u7f6e %3$d \u5904\u7684\u5b57\u7b26 %2$s \u4e0d\u662f\u6709\u6548\u7684\u53ef\u6253\u5370\u5b57\u7b26\u4e32\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR_197=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u667a\u80fd\u7528\u6237\u7535\u62a5\u7ec8\u7aef\u6807\u8bc6\u7b26\uff0c\u56e0\u4e3a\u5b83\u4ee5\u7f8e\u5143\u7b26\u53f7\u7ed3\u5c3e\uff0c\u4f46\u8be5\u7f8e\u5143\u7b26\u53f7\u5e94\u540e\u8ddf TTX \u53c2\u6570
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON_198=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u667a\u80fd\u7528\u6237\u7535\u62a5\u7ec8\u7aef\u6807\u8bc6\u7b26\uff0c\u56e0\u4e3a\u53c2\u6570\u5b57\u7b26\u4e32\u4e0d\u5305\u542b\u5c06\u540d\u79f0\u4e0e\u503c\u9694\u5f00\u7684\u5192\u53f7
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER_199=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u667a\u80fd\u7528\u6237\u7535\u62a5\u7ec8\u7aef\u6807\u8bc6\u7b26\uff0c\u56e0\u4e3a\u5b57\u7b26\u4e32 "%s" \u4e0d\u662f\u6709\u6548\u7684 TTX \u53c2\u6570\u540d\u79f0
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE_200=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c\u89e3\u6790\u4e3a\u5176\u4ed6\u90ae\u7bb1\u503c\uff0c\u56e0\u4e3a\u5b83\u4e3a\u7a7a
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE_201=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5176\u4ed6\u90ae\u7bb1\u503c\uff0c\u56e0\u4e3a\u7f8e\u5143\u7b26\u53f7\u524d\u9762\u6ca1\u6709\u90ae\u7bb1\u7c7b\u578b
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR_202=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5176\u4ed6\u90ae\u7bb1\u503c\uff0c\u56e0\u4e3a\u90ae\u7bb1\u7c7b\u578b\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX_203=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5176\u4ed6\u90ae\u7bb1\u503c\uff0c\u56e0\u4e3a\u7f8e\u5143\u7b26\u53f7\u540e\u9762\u6ca1\u6709\u90ae\u7bb1
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR_204=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u5176\u4ed6\u90ae\u7bb1\u503c\uff0c\u56e0\u4e3a\u90ae\u7bb1\u5728\u4f4d\u7f6e %3$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %2$s
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC_205=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u5b83\u5728\u4e95\u53f7 (#) \u5b57\u7b26\u524d\u9762\u4e0d\u5305\u542b objectclass \u540d\u79f0\u6216 OID
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR_206=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6761\u4ef6\u90e8\u5206 %2$s \u5728\u4f4d\u7f6e %4$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %3$c
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN_207=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6761\u4ef6\u90e8\u5206 %s \u4e0d\u5305\u542b\u4e0e\u521d\u59cb\u5de6\u5706\u62ec\u53f7\u5bf9\u5e94\u7684\u53f3\u5706\u62ec\u53f7
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK_208=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6761\u4ef6\u90e8\u5206 %s \u4ee5\u95ee\u53f7\u5f00\u5934\uff0c\u4f46\u6ca1\u6709\u540e\u8ddf\u5b57\u7b26\u4e32\u201c\u771f\u201d\u6216\u201c\u5047\u201d
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR_209=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6761\u4ef6\u90e8\u5206 %s \u4e0d\u5305\u542b\u5c06\u5c5e\u6027\u7c7b\u578b\u4e0e\u5339\u914d\u7c7b\u578b\u9694\u5f00\u7684\u7f8e\u5143\u7b26\u53f7
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR_210=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6761\u4ef6\u90e8\u5206 %s \u672a\u5728\u7f8e\u5143\u7b26\u53f7\u524d\u9762\u6307\u5b9a\u5c5e\u6027\u7c7b\u578b
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE_211=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6761\u4ef6\u90e8\u5206 %s \u672a\u5728\u7f8e\u5143\u7b26\u53f7\u540e\u9762\u6307\u5b9a\u5339\u914d\u7c7b\u578b
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE_212=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6761\u4ef6\u90e8\u5206 %s \u5177\u6709\u65e0\u6548\u7684\u5339\u914d\u7c7b\u578b\uff08\u4ece\u4f4d\u7f6e %d \u5904\u5f00\u59cb\uff09
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP_213=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u5b83\u4e0d\u5305\u542b\u5c06 objectclass \u4e0e\u6761\u4ef6\u9694\u5f00\u7684\u4e95\u53f7 (#) \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC_214=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u5b83\u5728\u4e95\u53f7 (#) \u5b57\u7b26\u524d\u9762\u4e0d\u5305\u542b objectclass \u540d\u79f0\u6216 OID
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID_215=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6307\u5b9a objectclass \u7684\u6570\u5b57 OID %s \u5728\u4f4d\u7f6e %d \u5904\u5305\u542b\u4e24\u4e2a\u8fde\u7eed\u7684\u53e5\u70b9
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID_216=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6307\u5b9a objectclass \u7684\u6570\u5b57 OID %2$s \u5728\u4f4d\u7f6e %4$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %3$s
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME_217=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%1$s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a objectclass \u540d\u79f0 %2$s \u5728\u4f4d\u7f6e %4$d \u5904\u5305\u542b\u975e\u6cd5\u5b57\u7b26 %3$s
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP_218=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u5b83\u4e0d\u5305\u542b\u5c06\u6761\u4ef6\u4e0e\u8303\u56f4\u9694\u5f00\u7684\u4e95\u53f7 (#) \u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE_219=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u672a\u5728\u6700\u7ec8\u4e95\u53f7 (#) \u5b57\u7b26\u540e\u9762\u63d0\u4f9b\u4efb\u4f55\u8303\u56f4
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE_220=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u6307\u5b9a\u7684\u8303\u56f4 %s \u65e0\u6548
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA_221=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u589e\u5f3a\u7684\u6307\u5bfc\u503c\uff0c\u56e0\u4e3a\u5b83\u672a\u5728\u4e95\u53f7 (#) \u5b57\u7b26\u4e4b\u95f4\u6307\u5b9a\u4efb\u4f55\u6761\u4ef6
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE_222=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c %s \u89e3\u6790\u4e3a\u6709\u6548\u7684 OID: %s
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE_223=An unexpected \
+### error occurred while trying to normalize value %s as a generalized time \
+### value:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE_224=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseExactOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE_225=An error occurred while \
+### attempting to compare two objects using the caseExactOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE_226=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE_227=An error occurred while \
+### attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE_228=An error \
+### occurred while attempting to compare two AttributeValue objects using the \
+### generalizedTimeOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE_229=An error occurred \
+### while attempting to compare two objects using the \
+### generalizedTimeOrderingMatch matching rule because the objects were of an \
+### unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+### value objects may be compared
+###SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE_230=An error occurred while \
+### attempting to compare two AttributeValue objects using the \
+### integerOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE_231=An error occurred while \
+### attempting to compare two objects using the integerOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE_232=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### numericStringOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE_233=An error occurred \
+### while attempting to compare two objects using the numericStringOrderingMatch \
+### matching rule because the objects were of an unsupported type %s.  Only byte \
+### arrays, ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE_234=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### octetStringOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE_235=An error occurred while \
+### attempting to compare two objects using the octetStringOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH_236=The provided value "%s" has \
+### an invalid length for a UUID.  All UUID values must have a length of exactly \
+### 36 bytes, but the provided value had a length of %d bytes
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH_237=The provided value "%s" should \
+### have had a dash at position %d, but the character '%s' was found instead
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX_238=The provided value "%s" should \
+### have had a hexadecimal digit at position %d, but the character '%s' was found \
+### instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH_239=\u6307\u793a\u4f7f\u7528\u76ee\u5f55\u5b57\u7b26\u4e32\u8bed\u6cd5\u7684\u5c5e\u6027\u662f\u5426\u5141\u8bb8\u5177\u6709\u96f6\u957f\u5ea6\u503c\u3002\u4ece\u6280\u672f\u4e0a\u8bb2\uff0cLDAP \u89c4\u8303\u4e0d\u5141\u8bb8\u5b58\u5728\u8fd9\u79cd\u60c5\u51b5\uff0c\u4f46\u5bf9\u4e8e\u5411\u540e\u517c\u5bb9\u4ee5\u524d\u7684\u76ee\u5f55\u670d\u52a1\u5668\u53d1\u884c\u7248\u6765\u8bf4\uff0c\u8fd9\u53ef\u80fd\u975e\u5e38\u6709\u7528
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH_240=An \
+### error occurred while trying to determine the value of the %s configuration \
+### attribute, which indicates whether directory string attributes should be \
+### allowed to have zero-length values:  %s
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE_241=The \
+### operation attempted to assign a zero-length value to an attribute with the \
+### directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH_242=\u5df2\u5c06\u914d\u7f6e\u6761\u76ee %2$s \u4e2d\u7684 %1$s \u5c5e\u6027\u66f4\u65b0\u4e3a\u65b0\u7684\u503c %3$s
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR_243=The provided \
+### authPassword value had an invalid scheme character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_244=The provided authPassword value \
+### had a zero-length scheme element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR_245=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the scheme and authInfo elements
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR_246=The provided \
+### authPassword value had an invalid authInfo character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_247=The provided authPassword \
+### value had a zero-length authInfo element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR_248=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the authInfo and authValue elements
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS_249=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### it did not start with a parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE_250=The provided value "%s" could not \
+### be parsed by the integer first component matching rule because it did not \
+### have any non-space characters after the opening parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT_251=The provided value "%s" \
+### could not be parsed by the integer first component matching rule because it \
+### did not have any space characters after the first component
+###SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT_252=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### the first component does not appear to be an integer value
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE_253=No value was given to decode by \
+### the user password attribute syntax
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE_254=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not start with the opening curly brace ("{") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE_255=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not contain a closing curly brace ("}") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME_256=Unable to decode the provided \
+### value according to the user password syntax because the value does not \
+### contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID_257=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684 RFC 3672 \u5b50\u6811\u89c4\u8303
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID_258=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u7edd\u5bf9\u5b50\u6811\u89c4\u8303
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID_259=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u76f8\u5bf9\u5b50\u6811\u89c4\u8303
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER_260=The provided value %s is not \
+### allowed for attributes with a Integer syntax
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR_261=The provided \
+### authPassword value had an invalid authValue character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE_262=The provided authPassword \
+### value had a zero-length authValue element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR_263=The provided \
+### authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER_264=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u5c5e\u6027\u8bed\u6cd5\u6269\u5c55\uff0c\u56e0\u4e3a\u5728\u4f4d\u7f6e %d \u5904\u627e\u5230\u65e0\u6548\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION_265=\u7531\u4e8e\u6269\u5c55\u65e0\u6548\u800c\u65e0\u6cd5\u89e3\u6790\u5c5e\u6027\u8bed\u6cd5\u3002%s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE_266=The definition \
+### for objectclass %s is invalid because it has an objectclass type of %s but \
+### this is incompatible with the objectclass type %s for the superior class %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP_267=The \
+### definition for objectclass %s is invalid because it is defined as a \
+### structural class but its superior chain does not include the "top" \
+### objectclass
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
+### for attribute type %s is invalid because its attribute usage %s is not the \
+### same as the usage for its superior type %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \
+### definition for attribute type %s is invalid because it is defined as a \
+### collective type but the superior type %s is not collective
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
+### definition for attribute type %s is invalid because it is not defined as a \
+### collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=DIT \u5185\u5bb9\u89c4\u5219 "%1$s" \u65e0\u6548\uff0c\u56e0\u4e3a\u5b83\u7981\u6b62\u4f7f\u7528\u5173\u8054\u7ed3\u6784\u5316\u5bf9\u8c61\u7c7b %3$s \u6240\u9700\u7684\u5c5e\u6027\u7c7b\u578b %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=DIT \u5185\u5bb9\u89c4\u5219 "%1$s" \u65e0\u6548\uff0c\u56e0\u4e3a\u5b83\u7981\u6b62\u4f7f\u7528\u5173\u8054\u8f85\u52a9\u5bf9\u8c61\u7c7b %3$s \u6240\u9700\u7684\u5c5e\u6027\u7c7b\u578b %2$s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \
+### for attribute type %s is invalid because it is declared COLLECTIVE but does \
+### not have a usage of userApplications
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \
+### definition for attribute type %s is invalid because it is declared \
+### NO-USER-MODIFICATION but does not have an operational usage
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR_275=The \
+### provided value %s is not a valid generalized time value because it contains \
+### illegal character %s in the fraction component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION_276=The provided \
+### value %s is not a valid generalized time value because it does not contain at \
+### least one digit after the period to use as the fractional component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO_277=The provided \
+### value %s is not a valid generalized time value because it does not end with \
+### 'Z' or a time zone offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME_278=The provided value \
+### %s is not a valid generalized time value because it represents an invalid \
+### time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED_279=\u65e0\u6cd5\u5bfc\u5165\u6a21\u5f0f\u5143\u7d20: %s, %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE_280=\u5339\u914d\u89c4\u5219\u6761\u76ee %s \u4e0b\u7684\u5bf9\u7167\u89c4\u5219 %s \u65e0\u6548\uff0c\u56e0\u4e3a JVM \u4e0d\u652f\u6301\u8bed\u8a00\u73af\u5883 %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT_281=\u63d0\u4f9b\u7684\u5bf9\u7167\u89c4\u5219 %s \u4e0d\u5305\u542b\u6709\u6548\u7684 OID \u683c\u5f0f:LOCALE
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u6807\u8bc6\u540d\uff0c\u56e0\u4e3a\u4e00\u4e2a\u5c5e\u6027\u503c\u4ee5\u5728\u9700\u8981\u907f\u5f00\u7684\u4f4d\u7f6e %d \u5904\u7684\u4e00\u4e2a\u5b57\u7b26\u5f00\u59cb
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR_283=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5c5e\u6027\u7c7b\u578b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u5c5e\u6027\u7c7b\u578b\u540d\u79f0\u4e2d\u4e0d\u5141\u8bb8\u4f7f\u7528\u4f4d\u7f6e %d \u5904\u7684\u5b57\u7b26 '%c'
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_284=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5c5e\u6027\u7c7b\u578b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u5c5e\u6027\u7c7b\u578b\u540d\u79f0\u4e2d\u4e0d\u5141\u8bb8\u4f7f\u7528\u4e0b\u5212\u7ebf\u5b57\u7b26\uff0c\u9664\u975e\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_285=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5c5e\u6027\u7c7b\u578b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u8fde\u5b57\u7b26\u4f5c\u4e3a\u5c5e\u6027\u7c7b\u578b\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_286=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5c5e\u6027\u7c7b\u578b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u4e0b\u5212\u7ebf\u5b57\u7b26\u4f5c\u4e3a\u5c5e\u6027\u7c7b\u578b\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\uff0c\u5373\u4f7f\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_287=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5c5e\u6027\u7c7b\u578b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u6570\u5b57 '%c' \u4f5c\u4e3a\u5c5e\u6027\u7c7b\u578b\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\uff0c\u9664\u975e\u5c06\u540d\u79f0\u6307\u5b9a\u4e3a OID \u6216\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR_288=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5bf9\u8c61\u7c7b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u5bf9\u8c61\u7c7b\u540d\u79f0\u4e2d\u4e0d\u5141\u8bb8\u4f7f\u7528\u4f4d\u7f6e %d \u5904\u7684\u5b57\u7b26 '%c'
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_289=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5bf9\u8c61\u7c7b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u5bf9\u8c61\u7c7b\u540d\u79f0\u4e2d\u4e0d\u5141\u8bb8\u4f7f\u7528\u4e0b\u5212\u7ebf\u5b57\u7b26\uff0c\u9664\u975e\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_290=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5bf9\u8c61\u7c7b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u8fde\u5b57\u7b26\u4f5c\u4e3a\u5bf9\u8c61\u7c7b\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_291=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5bf9\u8c61\u7c7b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u4e0b\u5212\u7ebf\u5b57\u7b26\u4f5c\u4e3a\u5bf9\u8c61\u7c7b\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\uff0c\u5373\u4f7f\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_292=\u65e0\u6cd5\u5c06\u63d0\u4f9b\u7684\u503c "%s" \u89e3\u6790\u4e3a\u6709\u6548\u7684\u5bf9\u8c61\u7c7b\u5b9a\u4e49\uff0c\u56e0\u4e3a\u4e0d\u5141\u8bb8\u5c06\u6570\u5b57 '%c' \u4f5c\u4e3a\u5bf9\u8c61\u7c7b\u540d\u79f0\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\uff0c\u9664\u975e\u5c06\u540d\u79f0\u6307\u5b9a\u4e3a OID \u6216\u542f\u7528\u4e86 %s \u914d\u7f6e\u9009\u9879
diff --git a/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_TW.properties b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_TW.properties
new file mode 100755
index 0000000..990d8e8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/main/resources/com/sun/opends/sdk/messages/messages_zh_TW.properties
@@ -0,0 +1,531 @@
+# 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
+#
+#      Copyright 2009 Sun Microsystems, Inc.
+#
+# Global directives
+#
+global.ordinal=-1
+#
+# Format string definitions
+#
+# Keys must be formatted as follows:
+#
+# [DESCRIPTION]
+#
+# where:
+#
+# DESCRIPTION is an upper case string providing a hint as to the context of
+# the message in upper case with the underscore ('_') character serving as
+# word separator
+#
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_APPROXIMATE_MATCHING_RULE_1=Unable to retrieve \
+### approximate matching rule %s used as the default for the %s attribute syntax. \
+### Approximate matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE_2=Unable to retrieve \
+### equality matching rule %s used as the default for the %s attribute syntax. \
+### Equality matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE_3=Unable to retrieve \
+### ordering matching rule %s used as the default for the %s attribute syntax. \
+### Ordering matches will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE_4=Unable to retrieve \
+### substring matching rule %s used as the default for the %s attribute syntax. \
+### Substring matching will not be allowed by default for attributes with this \
+### syntax
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN_5=The provided value "%s" is not \
+### allowed for attributes with a Boolean syntax.  The only allowed values are \
+### 'TRUE' and 'FALSE'
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_TOO_SHORT_6=The provided value "%s" is too \
+### short to be a valid bit string.  A bit string must be a series of binary \
+### digits surrounded by single quotes and followed by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_NOT_QUOTED_7=The provided value "%s" is not \
+### a valid bit string because it is not surrounded by single quotes and followed \
+### by a capital letter B
+###SEVERE_WARN_ATTR_SYNTAX_BIT_STRING_INVALID_BIT_8=The provided value "%s" is \
+### not a valid bit string because '%s' is not a valid binary digit
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_INVALID_LENGTH_9=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684\u570b\u5bb6/\u5730\u5340\u5b57\u4e32\uff0c\u56e0\u70ba\u5176\u9577\u5ea6\u4e0d\u662f\u6b63\u597d\u5169\u500b\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_COUNTRY_STRING_NOT_PRINTABLE_10=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684\u570b\u5bb6/\u5730\u5340\u5b57\u4e32\uff0c\u56e0\u70ba\u5176\u4e2d\u5305\u542b\u4e00\u6216\u591a\u500b\u4e0d\u53ef\u5217\u5370\u7684\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_NO_ELEMENTS_11=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684\u50b3\u9001\u65b9\u6cd5\u503c\uff0c\u56e0\u70ba\u5176\u4e2d\u4e0d\u5305\u542b\u4efb\u4f55\u5143\u7d20
+MILD_ERR_ATTR_SYNTAX_DELIVERY_METHOD_INVALID_ELEMENT_12=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684\u50b3\u9001\u65b9\u6cd5\u503c\uff0c\u56e0\u70ba\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684\u65b9\u6cd5
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_TOO_SHORT_13=The provided value "%s" \
+### is too short to be a valid generalized time value
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_YEAR_14=The provided value \
+### "%s" is not a valid generalized time value because the '%s' character is not \
+### allowed in the century or year specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MONTH_15=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid month \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_DAY_16=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid day \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_HOUR_17=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid hour \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_MINUTE_18=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid minute \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SECOND_19=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid second \
+### specification
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_SUBSECOND_20=The provided \
+### value "%s" is not a valid generalized time value because the sub-second \
+### component is not valid (between 1 and 3 numeric digits)
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_LONG_SUBSECOND_21=The provided value \
+### "%s" is not a valid generalized time value because the sub-second value may \
+### not contain more than three digits
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_OFFSET_22=The provided value \
+### "%s" is not a valid generalized time value because "%s" is not a valid GMT \
+### offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_INVALID_CHAR_23=The provided value \
+### "%s" is not a valid generalized time value because it contains an invalid \
+### character '%s' at position %d
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_CANNOT_PARSE_24=The provided value \
+### "%s" could not be parsed as a valid generalized time:  %s
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_25=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31: %s
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_COMMA_26=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u6700\u5f8c\u4e00\u500b\u975e\u7a7a\u683c\u5b57\u5143\u70ba\u9017\u865f\u6216\u5206\u865f
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_START_WITH_DIGIT_27=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u6578\u5b57\u300c%s\u300d\u4e0d\u5f97\u505a\u70ba\u5c6c\u6027\u540d\u7a31\u4e2d\u7684\u7b2c\u4e00\u500b\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR_28=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5c6c\u6027\u540d\u7a31\u4e2d\u4e0d\u5f97\u6709\u4f4d\u7f6e %3$d \u7684\u5b57\u5143\u300c%2$c\u300d
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR_29=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5c6c\u6027\u540d\u7a31\u4e2d\u4e0d\u5f97\u6709\u5e95\u7dda\u5b57\u5143\uff0c\u9664\u975e\u5df2\u555f\u7528 %s \u914d\u7f6e\u9078\u9805
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH_30=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u9023\u5b57\u7b26\u5b57\u5143\u4e0d\u5f97\u505a\u70ba\u5c6c\u6027\u540d\u7a31\u7684\u7b2c\u4e00\u500b\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE_31=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5373\u4f7f\u5df2\u555f\u7528 %s \u914d\u7f6e\u9078\u9805\uff0c\u5e95\u7dda\u5b57\u5143\u4e5f\u4e0d\u5f97\u505a\u70ba\u5c6c\u6027\u540d\u7a31\u7684\u7b2c\u4e00\u500b\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT_32=The provided value "%s" could not be parsed as a valid distinguished name because the digit '%c' is not allowed as the first character of an attribute name unless the name is specified as an OID or the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME_33=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5176\u4e2d\u6240\u542b\u7684 RDN \u542b\u6709\u7a7a\u7684\u5c6c\u6027\u540d\u7a31
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD_34=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5256\u6790\u7684\u5c6c\u6027\u540d\u7a31 %s \u5305\u542b\u4e00\u500b\u5c0f\u6578\u9ede\u865f\uff0c\u4f46\u8a72\u540d\u7a31\u4f3c\u4e4e\u4e0d\u662f\u6709\u6548\u7684 OID
+MILD_ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME_35=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u6700\u5f8c\u4e00\u500b\u975e\u7a7a\u683c\u5b57\u5143\u662f\u5c6c\u6027\u540d\u7a31\u300c%s\u300d\u7684\u4e00\u90e8\u5206
+MILD_ERR_ATTR_SYNTAX_DN_NO_EQUAL_36=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5c6c\u6027\u540d\u7a31\u300c%s\u300d\u5f8c\u7684\u4e0b\u4e00\u500b\u975e\u7a7a\u683c\u5b57\u5143\u61c9\u70ba\u7b49\u865f\uff0c\u4f46\u5be6\u969b\u4e0a\u662f\u300c%c\u300d
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_CHAR_37=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u4f4d\u7f6e %3$d \u7684\u5b57\u5143\u300c%2$c\u300d\u7121\u6548
+MILD_ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT_38=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5c6c\u6027\u503c\u662f\u4ee5\u4e95\u5b57\u865f (#) \u958b\u982d\uff0c\u4f46\u4e26\u672a\u7dca\u63a5\u8457\u5169\u500b\u5341\u516d\u9032\u5236\u6578\u5b57\u7684\u6b63\u500d\u6578
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT_39=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5c6c\u6027\u503c\u662f\u4ee5\u4e95\u5b57\u865f (#) \u958b\u982d\uff0c\u4f46\u5176\u4e2d\u542b\u6709\u4e26\u975e\u6709\u6548\u5341\u516d\u9032\u5236\u6578\u5b57\u7684\u5b57\u5143 %c
+MILD_ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE_40=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5728\u5617\u8a66\u5f9e\u5176\u4e2d\u4e00\u500b RDN \u5143\u4ef6\u5256\u6790\u5c6c\u6027\u503c\u6642\uff0c\u767c\u751f\u672a\u9810\u671f\u7684\u5931\u6557:\u300c%s\u300d
+MILD_ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE_41=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5176\u4e2d\u4e00\u500b RDN \u5143\u4ef6\u6240\u542b\u4e4b\u52a0\u4e0a\u5f15\u865f\u7684\u503c\uff0c\u6c92\u6709\u5c0d\u61c9\u7684\u53f3\u96d9\u5f15\u865f
+MILD_ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID_42=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u8fa8\u5225\u540d\u7a31\uff0c\u56e0\u70ba\u5176\u4e2d\u4e00\u500b RDN \u5143\u4ef6\u6240\u5305\u542b\u7684\u503c\uff0c\u542b\u6709\u672a\u7dca\u63a5\u8457\u7b2c\u4e8c\u500b\u5341\u516d\u9032\u5236\u6578\u5b57\u7684\u9000\u51fa\u5341\u516d\u9032\u5236\u6578\u5b57
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INITIAL_ZERO_43=The provided value "%s" could \
+### not be parsed as a valid integer because the first digit may not be zero \
+### unless it is the only digit
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_MISPLACED_DASH_44=The provided value "%s" \
+### could not be parsed as a valid integer because the dash may only appear if it \
+### is the first character of the value followed by one or more digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_INVALID_CHARACTER_45=The provided value "%s" \
+### could not be parsed as a valid integer because character '%c' at position %d \
+### is not allowed in an integer value
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_EMPTY_VALUE_46=The provided value "%s" could \
+### not be parsed as a valid integer because it did not contain any digits
+###SEVERE_WARN_ATTR_SYNTAX_INTEGER_DASH_NEEDS_VALUE_47=The provided value "%s" \
+### could not be parsed as a valid integer because it contained only a dash not \
+### followed by an integer value
+MILD_ERR_ATTR_SYNTAX_OID_NO_VALUE_48=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 OID\uff0c\u56e0\u70ba\u5176\u4e2d\u4e0d\u5305\u542b\u4efb\u4f55\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_OID_ILLEGAL_CHARACTER_49=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 OID\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u6709\u975e\u6cd5\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_OID_CONSECUTIVE_PERIODS_50=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 OID\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u6216\u9644\u8fd1\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_OID_ENDS_WITH_PERIOD_51=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 OID\uff0c\u56e0\u70ba\u5176\u7d50\u5c3e\u70ba\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EMPTY_VALUE_52=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS_53=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_TRUNCATED_VALUE_54=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_DOUBLE_PERIOD_IN_NUMERIC_OID_55=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_NUMERIC_OID_56=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_IN_STRING_OID_57=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_ILLEGAL_CHAR_58=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_UNEXPECTED_CLOSE_PARENTHESIS_59=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_60=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u985e\u578b\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u8a18\u865f %s \u5f8c\u61c9\u4ee5\u55ae\u5f15\u865f\u505a\u70ba\u7b2c\u4e00\u500b\u975e\u7a7a\u767d\u5b57\u5143\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f %s \u5b57\u5143
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUPERIOR_TYPE_61=The definition for \
+### the attribute type with OID %s declared a superior type with an OID of %s. \
+### No attribute type with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_APPROXIMATE_MR_62=The definition for \
+### the attribute type with OID %s declared that approximate matching should be \
+### performed using the matching rule "%s".  No such approximate matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_EQUALITY_MR_63=The definition for \
+### the attribute type with OID %s declared that equality matching should be \
+### performed using the matching rule "%s".  No such equality matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_ORDERING_MR_64=The definition for \
+### the attribute type with OID %s declared that ordering matching should be \
+### performed using the matching rule "%s".  No such ordering matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SUBSTRING_MR_65=The definition for \
+### the attribute type with OID %s declared that substring matching should be \
+### performed using the matching rule "%s".  No such substring matching rule is \
+### configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_UNKNOWN_SYNTAX_66=The definition for the \
+### attribute type with OID %s declared that it should have a syntax with OID %s. \
+### No such syntax is configured for use in the Directory Server
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE_67=The definition \
+### for the attribute type with OID %s declared that it should have an attribute \
+### usage of %s.  This is an invalid usage
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_EXPECTED_QUOTE_AT_POS_68=The provided value \
+### "%s" could not be parsed as an attribute type description because a single \
+### quote was expected at position %d but the character %s was found instead
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EMPTY_VALUE_69=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS_70=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_TRUNCATED_VALUE_71=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_DOUBLE_PERIOD_IN_NUMERIC_OID_72=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_NUMERIC_OID_73=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_IN_STRING_OID_74=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_CHAR_75=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_UNEXPECTED_CLOSE_PARENTHESIS_76=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_77=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u7269\u4ef6\u985e\u5225\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u8a18\u865f %s \u5f8c\u61c9\u4ee5\u55ae\u5f15\u865f\u505a\u70ba\u7b2c\u4e00\u500b\u975e\u7a7a\u767d\u5b57\u5143\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f %s \u5b57\u5143
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_SUPERIOR_CLASS_78=The definition \
+### for the objectclass with OID %s declared a superior objectclass with an OID \
+### of %s.  No objectclass with this OID exists in the server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_QUOTE_AT_POS_79=The provided \
+### value "%s" could not be parsed as an objectclass description because a single \
+### quote was expected at position %d but the character %s was found instead
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_REQUIRED_ATTR_80=The definition \
+### for the objectclass with OID %s declared that it should include required \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_UNKNOWN_OPTIONAL_ATTR_81=The definition \
+### for the objectclass with OID %s declared that it should include optional \
+### attribute "%s".  No attribute type matching this name or OID exists in the \
+### server schema
+###SEVERE_WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER_82=The provided value "%s" \
+### cannot be parsed as a valid IA5 string because it contains an illegal \
+### character "%s" that is not allowed in the IA5 (ASCII) character set
+INFO_ATTR_SYNTAX_TELEPHONE_DESCRIPTION_STRICT_MODE_83=\u9019\u8868\u793a\u96fb\u8a71\u865f\u78bc\u5c6c\u6027\u8a9e\u6cd5\u662f\u5426\u61c9\u4f7f\u7528\u56b4\u683c\u6a21\u5f0f\uff0c\u800c\u50c5\u63a5\u53d7 ITU-T E.123 \u683c\u5f0f\u7684\u503c\u3002\u82e5\u555f\u7528\u6b64\u9805\u76ee\uff0c\u5c07\u6703\u62d2\u7d55\u4efb\u4f55\u672a\u4f7f\u7528\u6b64\u683c\u5f0f\u7684\u503c\u3002\u82e5\u505c\u7528\u6b64\u9805\u76ee\uff0c\u5247\u6703\u63a5\u53d7\u4efb\u4f55\u503c\uff0c\u4f46\u5728\u57f7\u884c\u76f8\u7b26\u4f5c\u696d\u6642\u53ea\u6703\u8003\u91cf\u6578\u5b57
+###SEVERE_WARN_ATTR_SYNTAX_TELEPHONE_CANNOT_DETERMINE_STRICT_MODE_84=An error \
+### occurred while trying to retrieve attribute \
+### ds-cfg-strict-format from configuration entry %s:  %s.  The \
+### Directory Server will not enforce strict compliance to the ITU-T E.123 format \
+### for telephone number values
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_EMPTY_85=\u63d0\u4f9b\u7684\u503c\u4e0d\u662f\u6709\u6548\u7684\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u7a7a\u503c
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_PLUS_86=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u5df2\u555f\u7528\u56b4\u683c\u7684\u96fb\u8a71\u865f\u78bc\u6aa2\u67e5\uff0c\u4e14\u8a72\u503c\u4e26\u975e\u4ee5\u52a0\u865f\u958b\u982d\uff0c\u800c\u4e0d\u7b26\u5408 ITU-T E.123 \u898f\u683c
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_ILLEGAL_CHAR_87=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u4e0d\u662f\u6709\u6548\u7684\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u5df2\u555f\u7528\u56b4\u683c\u7684\u96fb\u8a71\u865f\u78bc\u6aa2\u67e5\uff0c\u800c ITU-T E.123 \u898f\u683c\u4e0d\u5141\u8a31\u4f4d\u7f6e %3$d \u7684\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_TELEPHONE_NO_DIGITS_88=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u5176\u4e2d\u4e0d\u5305\u542b\u4efb\u4f55\u6578\u5b57
+INFO_ATTR_SYNTAX_TELEPHONE_UPDATED_STRICT_MODE_89=\u5728\u914d\u7f6e\u9805\u76ee %2$s \u4e2d\uff0c\u5df2\u5c07\u53ef\u8868\u793a\u662f\u5426\u4f7f\u7528\u56b4\u683c\u96fb\u8a71\u865f\u78bc\u8a9e\u6cd5\u6aa2\u67e5\u7684\u914d\u7f6e\u5c6c\u6027 ds-cfg-strict-format \u7684\u503c\u66f4\u65b0\u70ba %1$s
+###SEVERE_WARN_ATTR_SYNTAX_NUMERIC_STRING_ILLEGAL_CHAR_90=The provided value \
+### "%s" is not a valid numeric string because it contained character %s at \
+### position %d that was neither a digit nor a space
+MILD_ERR_ATTR_SYNTAX_NUMERIC_STRING_EMPTY_VALUE_91=\u63d0\u4f9b\u7684\u503c\u4e0d\u662f\u6709\u6548\u7684\u6578\u503c\u5b57\u4e32\uff0c\u56e0\u70ba\u5176\u4e2d\u4e0d\u5305\u542b\u4efb\u4f55\u5b57\u5143\u3002\u6578\u503c\u5b57\u4e32\u503c\u5fc5\u9808\u5305\u542b\u81f3\u5c11\u4e00\u500b\u6578\u5b57\u6216\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EMPTY_VALUE_92=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS_93=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TRUNCATED_VALUE_94=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID_95=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID_96=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_IN_STRING_OID_97=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_UNEXPECTED_CLOSE_PARENTHESIS_98=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_TOKEN_99=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u5617\u8a66\u5f9e\u4f4d\u7f6e %d \u6216\u9644\u8fd1\u7684\u5b57\u4e32\u8b80\u53d6\u300cDESC\u300d\u8a18\u865f\u6642\uff0c\u767c\u751f\u672a\u9810\u671f\u7684\u932f\u8aa4: %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_TOKEN_NOT_DESC_100=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u9810\u671f\u61c9\u70ba\u300cDESC\u300d\u8a18\u865f\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u5b57\u4e32\u300c%s\u300d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_CANNOT_READ_DESC_VALUE_101=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u5617\u8a66\u5f9e\u4f4d\u7f6e %d \u6216\u9644\u8fd1\u7684\u5b57\u4e32\u8b80\u53d6\u300cDESC\u300d\u8a18\u865f\u7684\u503c\u6642\uff0c\u767c\u751f\u672a\u9810\u671f\u7684\u932f\u8aa4: %s
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_CLOSE_PARENTHESIS_102=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u53f3\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_ILLEGAL_CHAR_AFTER_CLOSE_103=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u53f3\u62ec\u5f27\u5f8c\u7684\u4f4d\u7f6e %3$d \u627e\u5230\u975e\u6cd5\u5b57\u5143 %2$s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_QUOTE_AT_POS_104=The provided \
+### value "%s" could not be parsed as an attribute syntax description because a \
+### single quote was expected at position %d but the character %s was found \
+### instead
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_EMPTY_VALUE_105=The provided value \
+### could not be parsed as a printable string because it was null or empty.  A \
+### printable string must contain at least one character
+###SEVERE_WARN_ATTR_SYNTAX_PRINTABLE_STRING_ILLEGAL_CHARACTER_106=The provided \
+### value "%s" could not be parsed as a printable string because it contained an \
+### invalid character %s at position %d
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_ONLY_WILDCARD_107=The provided value "*" \
+### could not be parsed as a substring assertion because it consists only of a \
+### wildcard character and zero-length substrings are not allowed
+###SEVERE_WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS_108=The provided \
+### value "%s" could not be parsed as a substring assertion because it contains \
+### consecutive wildcard characters at position %d and zero-length substrings are \
+### not allowed
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_TOO_SHORT_109=\u63d0\u4f9b\u7684\u503c %s \u592a\u77ed\uff0c\u7121\u6cd5\u505a\u70ba\u6709\u6548\u7684 UTC \u6642\u9593\u503c
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_YEAR_110=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba\u4e16\u7d00\u6216\u5e74\u4efd\u898f\u683c\u4e2d\u4e0d\u5141\u8a31 %s \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MONTH_111=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba %s \u4e0d\u662f\u6709\u6548\u7684\u6708\u4efd\u898f\u683c
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_DAY_112=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba %s \u4e0d\u662f\u6709\u6548\u7684\u65e5\u671f\u898f\u683c
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_HOUR_113=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba %s \u4e0d\u662f\u6709\u6548\u7684\u5c0f\u6642\u898f\u683c
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_MINUTE_114=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba %s \u4e0d\u662f\u6709\u6548\u7684\u5206\u9418\u898f\u683c
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_CHAR_115=\u63d0\u4f9b\u7684\u503c %1$s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u7121\u6548\u7684\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_SECOND_116=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba %s \u4e0d\u662f\u6709\u6548\u7684\u79d2\u9418\u898f\u683c
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_INVALID_OFFSET_117=\u63d0\u4f9b\u7684\u503c %s \u4e0d\u662f\u6709\u6548\u7684 UTC \u6642\u9593\u503c\uff0c\u56e0\u70ba %s \u4e0d\u662f\u6709\u6548\u7684 GMT \u504f\u79fb\u91cf
+MILD_ERR_ATTR_SYNTAX_UTC_TIME_CANNOT_PARSE_118=\u63d0\u4f9b\u7684\u503c %s \u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 UTC \u6642\u9593: %s
+MILD_ERR_ATTR_SYNTAX_DCR_EMPTY_VALUE_119=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS_120=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DCR_TRUNCATED_VALUE_121=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_DCR_DOUBLE_PERIOD_IN_NUMERIC_OID_122=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_NUMERIC_OID_123=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_IN_STRING_OID_124=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_UNEXPECTED_CLOSE_PARENTHESIS_125=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_DCR_ILLEGAL_CHAR_126=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS_127=DIT \u5167\u5bb9\u898f\u5247\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u7d50\u69cb\u7269\u4ef6\u985e\u5225 %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL_128=DIT \u5167\u5bb9\u898f\u5247\u300c%s\u300d\u8207 OID \u70ba %s \u7684\u7269\u4ef6\u985e\u5225 (%s) \u76f8\u95dc\u806f\u3002\u6b64\u7269\u4ef6\u985e\u5225\u5b58\u5728\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\uff0c\u4f46\u5df2\u5b9a\u7fa9\u70ba %s \u800c\u975e\u7d50\u69cb
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS_129=DIT \u5167\u5bb9\u898f\u5247\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u8f14\u52a9\u7269\u4ef6\u985e\u5225 %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY_130=DIT \u5167\u5bb9\u898f\u5247\u300c%s\u300d\u8207\u8f14\u52a9\u7269\u4ef6\u985e\u5225 %s \u76f8\u95dc\u806f\u3002\u6b64\u7269\u4ef6\u985e\u5225\u5b58\u5728\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\uff0c\u4f46\u5df2\u5b9a\u7fa9\u70ba %s \u800c\u975e\u8f14\u52a9
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR_131=DIT \u5167\u5bb9\u898f\u5247\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u5fc5\u8981\u5c6c\u6027\u985e\u578b %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR_132=DIT \u5167\u5bb9\u898f\u5247\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u9078\u64c7\u6027\u5c6c\u6027\u985e\u578b %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR_133=DIT \u5167\u5bb9\u898f\u5247\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u7981\u6b62\u5c6c\u6027\u985e\u578b %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_DCR_EXPECTED_QUOTE_AT_POS_134=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u5167\u5bb9\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u55ae\u5f15\u865f\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f %s \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EMPTY_VALUE_135=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS_136=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%c\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_TRUNCATED_VALUE_137=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_DOUBLE_PERIOD_IN_NUMERIC_OID_138=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_NUMERIC_OID_139=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_IN_STRING_OID_140=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNEXPECTED_CLOSE_PARENTHESIS_141=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_CHAR_142=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$c
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS_143=\u540d\u7a31\u8868\u8aaa\u660e\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u7d50\u69cb\u7269\u4ef6\u985e\u5225 %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_STRUCTURAL_CLASS_NOT_STRUCTURAL_144=\u540d\u7a31\u8868\u8aaa\u660e\u300c%s\u300d\u8207 OID \u70ba %s \u7684\u7269\u4ef6\u985e\u5225 (%s) \u76f8\u95dc\u806f\u3002\u6b64\u7269\u4ef6\u985e\u5225\u5b58\u5728\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\uff0c\u4f46\u5df2\u5b9a\u7fa9\u70ba %s \u800c\u975e\u7d50\u69cb
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR_145=OID \u70ba %s \u7684\u540d\u7a31\u8868\u5b9a\u7fa9\u5ba3\u544a\u4e86\u5b83\u61c9\u5305\u542b\u5fc5\u8981\u5c6c\u6027\u300c%s\u300d\u3002\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u6c92\u6709\u7b26\u5408\u6b64\u540d\u7a31\u6216 OID \u7684\u5c6c\u6027\u985e\u578b\u5b58\u5728
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_OPTIONAL_ATTR_146=OID \u70ba %s \u7684\u540d\u7a31\u8868\u5b9a\u7fa9\u5ba3\u544a\u4e86\u5b83\u61c9\u5305\u542b\u9078\u64c7\u6027\u5c6c\u6027\u300c%s\u300d\u3002\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u6c92\u6709\u7b26\u5408\u6b64\u540d\u7a31\u6216 OID \u7684\u5c6c\u6027\u985e\u578b\u5b58\u5728
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS_147=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u672a\u6307\u5b9a\u5176\u76f8\u95dc\u806f\u7684\u7d50\u69cb\u7269\u4ef6\u985e\u5225
+MILD_ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_QUOTE_AT_POS_148=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u540d\u7a31\u8868\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u55ae\u5f15\u865f\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f %c \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_MR_EMPTY_VALUE_149=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS_150=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_MR_TRUNCATED_VALUE_151=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_MR_DOUBLE_PERIOD_IN_NUMERIC_OID_152=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_NUMERIC_OID_153=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_IN_STRING_OID_154=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_MR_UNEXPECTED_CLOSE_PARENTHESIS_155=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_MR_ILLEGAL_CHAR_156=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX_157=\u76f8\u7b26\u898f\u5247\u8aaa\u660e\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u5c6c\u6027\u8a9e\u6cd5 %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_MR_NO_SYNTAX_158=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u672a\u6307\u5b9a\u5176\u76f8\u95dc\u806f\u7684\u5c6c\u6027\u8a9e\u6cd5
+MILD_ERR_ATTR_SYNTAX_MR_EXPECTED_QUOTE_AT_POS_159=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u55ae\u5f15\u865f\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f %s \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_MRUSE_EMPTY_VALUE_160=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS_161=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_MRUSE_TRUNCATED_VALUE_162=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_MRUSE_DOUBLE_PERIOD_IN_NUMERIC_OID_163=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_NUMERIC_OID_164=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_IN_STRING_OID_165=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE_166=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u6307\u5b9a\u7684\u76f8\u7b26\u898f\u5247 %s \u4e0d\u660e
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNEXPECTED_CLOSE_PARENTHESIS_167=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_CHAR_168=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_ATTR_169=\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\u300c%s\u300d\u8207\u672a\u5b9a\u7fa9\u65bc\u4f3a\u670d\u5668\u6a21\u5f0f\u4e2d\u7684\u5c6c\u6027\u985e\u578b %s \u76f8\u95dc\u806f
+MILD_ERR_ATTR_SYNTAX_MRUSE_NO_ATTR_170=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u672a\u6307\u5b9a\u53ef\u8207\u76f8\u95dc OID \u4e00\u8d77\u4f7f\u7528\u7684\u5c6c\u6027\u985e\u578b\u96c6
+MILD_ERR_ATTR_SYNTAX_MRUSE_EXPECTED_QUOTE_AT_POS_171=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u76f8\u7b26\u898f\u5247\u4f7f\u7528\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u55ae\u5f15\u865f\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f %s \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DSR_EMPTY_VALUE_172=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684\u6216\u50c5\u5305\u542b\u7a7a\u683c
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS_173=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u5de6\u62ec\u5f27\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f\u300c%s\u300d\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DSR_TRUNCATED_VALUE_174=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5df2\u9054\u8a72\u503c\u7d50\u5c3e\uff0c\u4f46\u76ee\u9304\u4f3a\u670d\u5668\u9810\u671f\u61c9\u6709\u66f4\u591a\u63d0\u4f9b\u7684\u8cc7\u6599
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_RULE_ID_175=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u898f\u5247 OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_DSR_UNEXPECTED_CLOSE_PARENTHESIS_176=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %d \u542b\u6709\u672a\u9810\u671f\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_177=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM_178=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u53c3\u7167\u4e86\u4e0d\u660e\u7684\u540d\u7a31\u8868 %s
+MILD_ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID_179=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u53c3\u7167\u4e86\u4e0a\u5c64 DIT \u7d50\u69cb\u898f\u5247\u7684\u4e0d\u660e\u898f\u5247 ID %d
+MILD_ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM_180=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u8a72\u503c\u672a\u6307\u5b9a\u898f\u5247\u7684\u540d\u7a31\u8868
+MILD_ERR_ATTR_SYNTAX_DSR_EXPECTED_QUOTE_AT_POS_181=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u61c9\u6709\u55ae\u5f15\u865f\uff0c\u4f46\u627e\u5230\u7684\u537b\u662f %s \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_DSR_DOUBLE_PERIOD_IN_NUMERIC_OID_182=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_NUMERIC_OID_183=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_DSR_ILLEGAL_CHAR_IN_STRING_OID_184=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba DIT \u7d50\u69cb\u898f\u5247\u8aaa\u660e\uff0c\u56e0\u70ba\u975e\u6578\u503c OID \u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_TELEX_TOO_SHORT_185=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u592a\u77ed\uff0c\u7121\u6cd5\u505a\u70ba\u6709\u6548\u7684\u96fb\u5831\u865f\u78bc\u503c
+MILD_ERR_ATTR_SYNTAX_TELEX_NOT_PRINTABLE_186=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u4e0d\u542b\u6709\u6548\u7684\u96fb\u5831\u865f\u78bc\uff0c\u56e0\u70ba\u4f4d\u7f6e %3$d \u7684\u5b57\u5143 %2$s \u4e0d\u662f\u6709\u6548\u7684\u53ef\u5217\u5370\u5b57\u4e32\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_TELEX_ILLEGAL_CHAR_187=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u4e0d\u542b\u6709\u6548\u7684\u96fb\u5831\u865f\u78bc\uff0c\u56e0\u70ba\u4f4d\u7f6e %3$d \u7684\u5b57\u5143 %2$s \u4e0d\u662f\u6709\u6548\u7684\u53ef\u5217\u5370\u5b57\u4e32\u5b57\u5143\uff0c\u4e5f\u4e0d\u662f\u53ef\u5206\u9694\u96fb\u5831\u865f\u78bc\u5143\u4ef6\u7684\u8ca8\u5e63\u7b26\u865f
+MILD_ERR_ATTR_SYNTAX_TELEX_TRUNCATED_188=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u4e0d\u542b\u6709\u6548\u7684\u96fb\u5831\u865f\u78bc\uff0c\u56e0\u70ba\u5728\u53ef\u8b80\u53d6\u4e09\u500b\u4ee5\u8ca8\u5e63\u7b26\u865f\u5206\u9694\u7684\u53ef\u5217\u5370\u5b57\u4e32\u4e4b\u524d\uff0c\u767c\u73fe\u8a72\u503c\u7684\u7d50\u5c3e
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_EMPTY_189=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u50b3\u771f\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_NOT_PRINTABLE_190=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u50b3\u771f\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u4f4d\u7f6e %3$d \u7684\u5b57\u5143 %2$s \u4e0d\u662f\u6709\u6548\u7684\u53ef\u5217\u5370\u5b57\u4e32\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_END_WITH_DOLLAR_191=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u50b3\u771f\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u8a72\u503c\u7684\u7d50\u5c3e\u662f\u8ca8\u5e63\u7b26\u865f\uff0c\u4f46\u8a72\u8ca8\u5e63\u7b26\u865f\u539f\u61c9\u7dca\u63a5\u8457\u50b3\u771f\u53c3\u6578
+MILD_ERR_ATTR_SYNTAX_FAXNUMBER_ILLEGAL_PARAMETER_192=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u50b3\u771f\u96fb\u8a71\u865f\u78bc\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %3$d \u8207 %4$d \u4e4b\u9593\u7684\u5b57\u4e32\u300c%2$s\u300d\u4e0d\u662f\u6709\u6548\u7684\u50b3\u771f\u53c3\u6578
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_INVALID_DN_193=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u540d\u7a31\u8207\u9078\u64c7\u6027 UID \u503c\uff0c\u56e0\u70ba\u5728\u5617\u8a66\u5256\u6790 DN \u90e8\u5206\u6642\u767c\u751f\u932f\u8aa4: %s
+MILD_ERR_ATTR_SYNTAX_NAMEANDUID_ILLEGAL_BINARY_DIGIT_194=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u540d\u7a31\u8207\u9078\u64c7\u6027 UID \u503c\uff0c\u56e0\u70ba OID \u90e8\u5206\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u4e8c\u9032\u4f4d\u6578\u5b57 %2$s
+MILD_ERR_ATTR_SYNTAX_TELETEXID_EMPTY_195=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 teletex \u7d42\u7aef\u6a5f\u8b58\u5225\u78bc\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684
+MILD_ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE_196=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 teletex \u7d42\u7aef\u6a5f\u8b58\u5225\u78bc\uff0c\u56e0\u70ba\u4f4d\u7f6e %3$d \u7684\u5b57\u5143 %2$s \u4e0d\u662f\u6709\u6548\u7684\u53ef\u5217\u5370\u5b57\u4e32\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR_197=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 teletex \u7d42\u7aef\u6a5f\u8b58\u5225\u78bc\uff0c\u56e0\u70ba\u8a72\u503c\u7684\u7d50\u5c3e\u662f\u8ca8\u5e63\u7b26\u865f\uff0c\u4f46\u8a72\u8ca8\u5e63\u7b26\u865f\u539f\u61c9\u7dca\u63a5\u8457 TTX \u53c3\u6578
+MILD_ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON_198=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 teletex \u7d42\u7aef\u6a5f\u8b58\u5225\u78bc\uff0c\u56e0\u70ba\u53c3\u6578\u5b57\u4e32\u4e0d\u5305\u542b\u7528\u4ee5\u5340\u9694\u540d\u7a31\u8207\u503c\u7684\u5192\u865f
+MILD_ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER_199=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 teletex \u7d42\u7aef\u6a5f\u8b58\u5225\u78bc\uff0c\u56e0\u70ba\u5b57\u4e32\u300c%s\u300d\u4e0d\u662f\u6709\u6548\u7684 TTX \u53c3\u6578\u540d\u7a31
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_EMPTY_VALUE_200=\u63d0\u4f9b\u7684\u503c\u7121\u6cd5\u5256\u6790\u70ba\u5176\u4ed6\u96fb\u5b50\u4fe1\u7bb1\u503c\uff0c\u56e0\u70ba\u8a72\u503c\u662f\u7a7a\u7684
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MBTYPE_201=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5176\u4ed6\u96fb\u5b50\u4fe1\u7bb1\u503c\uff0c\u56e0\u70ba\u5728\u8ca8\u5e63\u7b26\u865f\u4e4b\u524d\u6c92\u6709\u4efb\u4f55\u96fb\u5b50\u4fe1\u7bb1\u985e\u578b
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MBTYPE_CHAR_202=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5176\u4ed6\u96fb\u5b50\u4fe1\u7bb1\u503c\uff0c\u56e0\u70ba\u96fb\u5b50\u4fe1\u7bb1\u985e\u578b\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_NO_MAILBOX_203=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5176\u4ed6\u96fb\u5b50\u4fe1\u7bb1\u503c\uff0c\u56e0\u70ba\u5728\u8ca8\u5e63\u7b26\u865f\u4e4b\u5f8c\u6c92\u6709\u4efb\u4f55\u96fb\u5b50\u4fe1\u7bb1
+MILD_ERR_ATTR_SYNTAX_OTHER_MAILBOX_ILLEGAL_MB_CHAR_204=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5176\u4ed6\u96fb\u5b50\u4fe1\u7bb1\u503c\uff0c\u56e0\u70ba\u96fb\u5b50\u4fe1\u7bb1\u5728\u4f4d\u7f6e %3$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %2$s
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_OC_205=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4e95\u5b57\u865f (#) \u5b57\u5143\u4e4b\u524d\u4e0d\u5305\u542b\u7269\u4ef6\u985e\u5225\u540d\u7a31\u6216 OID
+MILD_ERR_ATTR_SYNTAX_GUIDE_ILLEGAL_CHAR_206=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u689d\u4ef6\u90e8\u5206 %2$s \u5728\u4f4d\u7f6e %4$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %3$c
+MILD_ERR_ATTR_SYNTAX_GUIDE_MISSING_CLOSE_PAREN_207=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u689d\u4ef6\u90e8\u5206 %s \u4e0d\u5305\u542b\u8207\u521d\u59cb\u5de6\u62ec\u5f27\u5c0d\u61c9\u7684\u53f3\u62ec\u5f27
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_QUESTION_MARK_208=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u689d\u4ef6\u90e8\u5206 %s \u662f\u4ee5\u554f\u865f\u958b\u982d\uff0c\u4f46\u4e26\u672a\u7dca\u63a5\u8457\u5b57\u4e32\u300ctrue\u300d\u6216\u300cfalse\u300d
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_DOLLAR_209=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u689d\u4ef6\u90e8\u5206 %s \u4e0d\u5305\u542b\u7528\u4ee5\u5340\u9694\u5c6c\u6027\u985e\u578b\u8207\u76f8\u7b26\u985e\u578b\u7684\u8ca8\u5e63\u7b26\u865f
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_ATTR_210=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u689d\u4ef6\u90e8\u5206 %s \u672a\u5728\u8ca8\u5e63\u7b26\u865f\u4e4b\u524d\u6307\u5b9a\u5c6c\u6027\u985e\u578b
+MILD_ERR_ATTR_SYNTAX_GUIDE_NO_MATCH_TYPE_211=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u689d\u4ef6\u90e8\u5206 %s \u672a\u5728\u8ca8\u5e63\u7b26\u865f\u4e4b\u5f8c\u6307\u5b9a\u76f8\u7b26\u985e\u578b
+MILD_ERR_ATTR_SYNTAX_GUIDE_INVALID_MATCH_TYPE_212=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u689d\u4ef6\u90e8\u5206 %s \u5f9e\u4f4d\u7f6e %d \u8d77\u6709\u7121\u6548\u7684\u76f8\u7b26\u985e\u578b
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SHARP_213=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u8a72\u503c\u4e0d\u5305\u542b\u7528\u4ee5\u5340\u9694\u7269\u4ef6\u985e\u5225\u8207\u689d\u4ef6\u7684\u4e95\u5b57\u865f (#) \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_OC_214=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4e95\u5b57\u865f (#) \u5b57\u5143\u4e4b\u524d\u4e0d\u5305\u542b\u7269\u4ef6\u985e\u5225\u540d\u7a31\u6216 OID
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_DOUBLE_PERIOD_IN_OC_OID_215=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u7528\u4ee5\u6307\u5b9a\u7269\u4ef6\u985e\u5225\u7684\u6578\u503c OID %s \u5728\u4f4d\u7f6e %d \u542b\u6709\u5169\u500b\u9023\u7e8c\u7684\u5c0f\u6578\u9ede\u865f
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_OID_216=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u7528\u4ee5\u6307\u5b9a\u7269\u4ef6\u985e\u5225\u7684\u6578\u503c OID %2$s \u5728\u4f4d\u7f6e %4$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %3$s
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_ILLEGAL_CHAR_IN_OC_NAME_217=\u63d0\u4f9b\u7684\u503c\u300c%1$s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u7269\u4ef6\u985e\u5225\u540d\u7a31 %2$s \u5728\u4f4d\u7f6e %4$d \u542b\u6709\u975e\u6cd5\u5b57\u5143 %3$s
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_FINAL_SHARP_218=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u8a72\u503c\u6c92\u6709\u7528\u4ee5\u5340\u9694\u689d\u4ef6\u8207\u7bc4\u570d\u7684\u4e95\u5b57\u865f (#) \u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_SCOPE_219=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u5728\u6700\u7d42\u7684\u4e95\u5b57\u865f (#) \u5b57\u5143\u4e4b\u5f8c\u672a\u63d0\u4f9b\u7bc4\u570d
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_INVALID_SCOPE_220=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u6307\u5b9a\u7684\u7bc4\u570d %s \u7121\u6548
+MILD_ERR_ATTR_SYNTAX_ENHANCEDGUIDE_NO_CRITERIA_221=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u589e\u5f37\u5f15\u5c0e\u503c\uff0c\u56e0\u70ba\u8a72\u503c\u5728\u4e95\u5b57\u865f (#) \u5b57\u5143\u4e4b\u9593\u672a\u6307\u5b9a\u4efb\u4f55\u689d\u4ef6
+MILD_ERR_ATTR_SYNTAX_OID_INVALID_VALUE_222=\u63d0\u4f9b\u7684\u503c %s \u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 OID: %s
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NORMALIZE_FAILURE_223=An unexpected \
+### error occurred while trying to normalize value %s as a generalized time \
+### value:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_CANNOT_NORMALIZE_224=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseExactOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_EXACT_COMPARE_INVALID_TYPE_225=An error occurred while \
+### attempting to compare two objects using the caseExactOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_CANNOT_NORMALIZE_226=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### caseIgnoreOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_CASE_IGNORE_COMPARE_INVALID_TYPE_227=An error occurred while \
+### attempting to compare two objects using the caseIgnoreOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_CANNOT_NORMALIZE_228=An error \
+### occurred while attempting to compare two AttributeValue objects using the \
+### generalizedTimeOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_GENERALIZED_TIME_COMPARE_INVALID_TYPE_229=An error occurred \
+### while attempting to compare two objects using the \
+### generalizedTimeOrderingMatch matching rule because the objects were of an \
+### unsupported type %s.  Only byte arrays, ASN.1 octet strings, and attribute \
+### value objects may be compared
+###SEVERE_WARN_OMR_INTEGER_COMPARE_CANNOT_NORMALIZE_230=An error occurred while \
+### attempting to compare two AttributeValue objects using the \
+### integerOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_INTEGER_COMPARE_INVALID_TYPE_231=An error occurred while \
+### attempting to compare two objects using the integerOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_CANNOT_NORMALIZE_232=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### numericStringOrderingMatch matching rule because the normalized form of one \
+### of those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_NUMERIC_STRING_COMPARE_INVALID_TYPE_233=An error occurred \
+### while attempting to compare two objects using the numericStringOrderingMatch \
+### matching rule because the objects were of an unsupported type %s.  Only byte \
+### arrays, ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_CANNOT_NORMALIZE_234=An error occurred \
+### while attempting to compare two AttributeValue objects using the \
+### octetStringOrderingMatch matching rule because the normalized form of one of \
+### those values could not be retrieved:  %s
+###SEVERE_WARN_OMR_OCTET_STRING_COMPARE_INVALID_TYPE_235=An error occurred while \
+### attempting to compare two objects using the octetStringOrderingMatch matching \
+### rule because the objects were of an unsupported type %s.  Only byte arrays, \
+### ASN.1 octet strings, and attribute value objects may be compared
+###SEVERE_WARN_ATTR_SYNTAX_UUID_INVALID_LENGTH_236=The provided value "%s" has \
+### an invalid length for a UUID.  All UUID values must have a length of exactly \
+### 36 bytes, but the provided value had a length of %d bytes
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_DASH_237=The provided value "%s" should \
+### have had a dash at position %d, but the character '%s' was found instead
+###SEVERE_WARN_ATTR_SYNTAX_UUID_EXPECTED_HEX_238=The provided value "%s" should \
+### have had a hexadecimal digit at position %d, but the character '%s' was found \
+### instead
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_DESCRIPTION_ALLOW_ZEROLENGTH_239=\u8868\u793a\u4f7f\u7528\u76ee\u9304\u5b57\u4e32\u8a9e\u6cd5\u7684\u5c6c\u6027\u662f\u5426\u53ef\u6709\u96f6\u9577\u5ea6\u7684\u503c\u3002LDAP \u898f\u683c\u6280\u8853\u4e0a\u4e0d\u5141\u8a31\u6b64\u8a2d\u5b9a\uff0c\u4f46\u5728\u820a\u7248\u76ee\u9304\u4f3a\u670d\u5668\u7684\u5411\u4e0b\u76f8\u5bb9\u6027\u65b9\u9762\uff0c\u9019\u53ef\u80fd\u5f88\u6709\u7528
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_CANNOT_DETERMINE_ZEROLENGTH_240=An \
+### error occurred while trying to determine the value of the %s configuration \
+### attribute, which indicates whether directory string attributes should be \
+### allowed to have zero-length values:  %s
+###SEVERE_ERR_ATTR_SYNTAX_DIRECTORYSTRING_INVALID_ZEROLENGTH_VALUE_241=The \
+### operation attempted to assign a zero-length value to an attribute with the \
+### directory string syntax
+INFO_ATTR_SYNTAX_DIRECTORYSTRING_UPDATED_ALLOW_ZEROLENGTH_242=\u914d\u7f6e\u9805\u76ee %2$s \u4e2d\u7684 %1$s \u5c6c\u6027\u5df2\u4f7f\u7528\u65b0\u503c %3$s \u9032\u884c\u66f4\u65b0
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_SCHEME_CHAR_243=The provided \
+### authPassword value had an invalid scheme character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_244=The provided authPassword value \
+### had a zero-length scheme element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_SCHEME_SEPARATOR_245=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the scheme and authInfo elements
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_INFO_CHAR_246=The provided \
+### authPassword value had an invalid authInfo character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_247=The provided authPassword \
+### value had a zero-length authInfo element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_INFO_SEPARATOR_248=The provided \
+### authPassword value was missing the separator character or had an illegal \
+### character between the authInfo and authValue elements
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_INITIAL_PARENTHESIS_249=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### it did not start with a parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_NONSPACE_250=The provided value "%s" could not \
+### be parsed by the integer first component matching rule because it did not \
+### have any non-space characters after the opening parenthesis
+###SEVERE_ERR_EMR_INTFIRSTCOMP_NO_SPACE_AFTER_INT_251=The provided value "%s" \
+### could not be parsed by the integer first component matching rule because it \
+### did not have any space characters after the first component
+###SEVERE_ERR_EMR_INTFIRSTCOMP_FIRST_COMPONENT_NOT_INT_252=The provided value \
+### "%s" could not be parsed by the integer first component matching rule because \
+### the first component does not appear to be an integer value
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_VALUE_253=No value was given to decode by \
+### the user password attribute syntax
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE_254=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not start with the opening curly brace ("{") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE_255=Unable to decode the \
+### provided value according to the user password syntax because the value does \
+### not contain a closing curly brace ("}") character
+###SEVERE_ERR_ATTR_SYNTAX_USERPW_NO_SCHEME_256=Unable to decode the provided \
+### value according to the user password syntax because the value does not \
+### contain a storage scheme name
+MILD_ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID_257=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684 RFC 3672 \u5b50\u6a39\u72c0\u7d50\u69cb\u898f\u683c
+MILD_ERR_ATTR_SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_INVALID_258=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u7d55\u5c0d\u5b50\u6a39\u72c0\u7d50\u69cb\u898f\u683c
+MILD_ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID_259=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u6709\u6548\u7684\u76f8\u5c0d\u5b50\u6a39\u72c0\u7d50\u69cb\u898f\u683c
+###SEVERE_WARN_ATTR_SYNTAX_ILLEGAL_INTEGER_260=The provided value %s is not \
+### allowed for attributes with a Integer syntax
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_AUTH_VALUE_CHAR_261=The provided \
+### authPassword value had an invalid authValue character at position %d
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_NO_AUTH_VALUE_262=The provided authPassword \
+### value had a zero-length authValue element
+###SEVERE_ERR_ATTR_SYNTAX_AUTHPW_INVALID_TRAILING_CHAR_263=The provided \
+### authPassword value had an invalid trailing character at position %d
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_EXTENSION_INVALID_CHARACTER_264=\u63d0\u4f9b\u7684\u503c\u300c%s\u300d\u7121\u6cd5\u5256\u6790\u70ba\u5c6c\u6027\u8a9e\u6cd5\u5ef6\u4f38\uff0c\u56e0\u70ba\u5728\u4f4d\u7f6e %d \u627e\u5230\u7121\u6548\u7684\u5b57\u5143
+MILD_ERR_ATTR_SYNTAX_ATTRSYNTAX_INVALID_EXTENSION_265=\u5c6c\u6027\u8a9e\u6cd5\u56e0\u5ef6\u4f38\u7121\u6548\u800c\u7121\u6cd5\u5256\u6790\u3002%s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE_266=The definition \
+### for objectclass %s is invalid because it has an objectclass type of %s but \
+### this is incompatible with the objectclass type %s for the superior class %s
+###SEVERE_WARN_ATTR_SYNTAX_OBJECTCLASS_STRUCTURAL_SUPERIOR_NOT_TOP_267=The \
+### definition for objectclass %s is invalid because it is defined as a \
+### structural class but its superior chain does not include the "top" \
+### objectclass
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
+### for attribute type %s is invalid because its attribute usage %s is not the \
+### same as the usage for its superior type %s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \
+### definition for attribute type %s is invalid because it is defined as a \
+### collective type but the superior type %s is not collective
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
+### definition for attribute type %s is invalid because it is not defined as a \
+### collective type but the superior type %s is collective
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL_271=DIT \u5167\u5bb9\u898f\u5247\u300c%1$s\u300d\u7121\u6548\uff0c\u56e0\u70ba\u8a72\u898f\u5247\u7981\u6b62\u4f7f\u7528\u76f8\u95dc\u7d50\u69cb\u7269\u4ef6\u985e\u5225 %3$s \u6240\u9700\u7684\u5c6c\u6027\u985e\u578b %2$s
+MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=DIT \u5167\u5bb9\u898f\u5247\u300c%1$s\u300d\u7121\u6548\uff0c\u56e0\u70ba\u8a72\u898f\u5247\u7981\u6b62\u4f7f\u7528\u76f8\u95dc\u8f14\u52a9\u7269\u4ef6\u985e\u5225 %3$s \u6240\u9700\u7684\u5c6c\u6027\u985e\u578b %2$s
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \
+### for attribute type %s is invalid because it is declared COLLECTIVE but does \
+### not have a usage of userApplications
+###SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \
+### definition for attribute type %s is invalid because it is declared \
+### NO-USER-MODIFICATION but does not have an operational usage
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_FRACTION_CHAR_275=The \
+### provided value %s is not a valid generalized time value because it contains \
+### illegal character %s in the fraction component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_EMPTY_FRACTION_276=The provided \
+### value %s is not a valid generalized time value because it does not contain at \
+### least one digit after the period to use as the fractional component
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_NO_TIME_ZONE_INFO_277=The provided \
+### value %s is not a valid generalized time value because it does not end with \
+### 'Z' or a time zone offset
+###SEVERE_WARN_ATTR_SYNTAX_GENERALIZED_TIME_ILLEGAL_TIME_278=The provided value \
+### %s is not a valid generalized time value because it represents an invalid \
+### time (e.g., a date that does not exist):  %s
+NOTICE_SCHEMA_IMPORT_FAILED_279=\u7121\u6cd5\u532f\u5165\u6a21\u5f0f\u5143\u7d20: %s, %s
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_LOCALE_280=The collation rule %s under matching rule entry %s is invalid as the locale %s is not supported by JVM
+MILD_WARN_ATTR_INVALID_COLLATION_MATCHING_RULE_FORMAT_281=The provided collation rule %s does not contain a valid format of OID:LOCALE
+MILD_ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR_282=The provided value "%s" could not be parsed as a valid distinguished name because an attribute value started with a character at position %d that needs to be escaped
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_CHAR_283=The provided value "%s" could not be parsed as a valid attribute type definition because character '%c' at position %d is not allowed in an attribute type name
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_284=The provided value "%s" could not be parsed as a valid attribute type definition because the underscore character is not allowed in an attribute type name unless the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_285=The provided value "%s" could not be parsed as a valid attribute type definition because the hyphen character is not allowed as the first character of an attribute type name
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_286=The provided value "%s" could not be parsed as a valid attribute type definition because the underscore character is not allowed as the first character of an attribute type name even if the %s configuration option is enabled
+MILD_ERR_ATTR_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_287=The provided value "%s" could not be parsed as a valid attribute type definition because the digit '%c' is not allowed as the first character of an attribute type name unless the name is specified as an OID or the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_CHAR_288=The provided value "%s" could not be parsed as a valid object class definition because character '%c' at position %d is not allowed in an object class name
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_UNDERSCORE_CHAR_289=The provided value "%s" could not be parsed as a valid object class definition because the underscore character is not allowed in an object class name unless the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DASH_290=The provided value "%s" could not be parsed as a valid object class definition because the hyphen character is not allowed as the first character of an object class name
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_UNDERSCORE_291=The provided value "%s" could not be parsed as a valid object class definition because the underscore character is not allowed as the first character of an object class name even if the %s configuration option is enabled
+MILD_ERR_OC_SYNTAX_ATTR_ILLEGAL_INITIAL_DIGIT_292=The provided value "%s" could not be parsed as a valid object class definition because the digit '%c' is not allowed as the first character of an object class name unless the name is specified as an OID or the %s configuration option is enabled
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControlTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControlTestCase.java
new file mode 100644
index 0000000..739a446
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityRequestControlTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.controls;
+
+
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlsTestCase;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests the account usability request control.
+ */
+public class AccountUsabilityRequestControlTestCase extends ControlsTestCase
+{
+  @Test()
+  public void testControl() throws Exception
+  {
+    // Send this control with a search request and see that you get
+    // a valid response.
+    final SearchRequest req = Requests.newSearchRequest(DN
+        .valueOf("uid=user.1,ou=people,o=test"), SearchScope.BASE_OBJECT,
+        Filter.getObjectClassPresentFilter());
+    final AccountUsabilityRequestControl control = AccountUsabilityRequestControl
+        .newControl(false);
+    req.addControl(control);
+    final Connection con = TestCaseUtils.getInternalConnection();
+    final List<SearchResultEntry> entries = new ArrayList<SearchResultEntry>();
+    con.search(req, entries);
+    assertTrue(entries.size() > 0);
+    final SearchResultEntry entry = entries.get(0);
+    final Control ctrl = entry.getControls().get(0);
+    if (!ctrl.getOID().equals("1.3.6.1.4.1.42.2.27.9.5.8"))
+    {
+      throw new Exception("expected control response 1.3.6.1.4.1.42.2.27.9.5.8");
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControlTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControlTestCase.java
new file mode 100644
index 0000000..5b3d651
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/controls/AccountUsabilityResponseControlTestCase.java
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.controls;
+
+
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opends.sdk.*;
+import org.opends.sdk.controls.ControlsTestCase;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests the account usability response control.
+ */
+public class AccountUsabilityResponseControlTestCase extends ControlsTestCase
+{
+  @Test()
+  public void testInvalidResponseControl() throws Exception
+  {
+    // Don't send the request control and hence there
+    // shouldn't be response.
+    final SearchRequest req = Requests.newSearchRequest(DN
+        .valueOf("uid=user.1,ou=people,o=test"), SearchScope.BASE_OBJECT,
+        Filter.getObjectClassPresentFilter());
+    final Connection con = TestCaseUtils.getInternalConnection();
+    final List<SearchResultEntry> entries = new ArrayList<SearchResultEntry>();
+    con.search(req, entries);
+    assertTrue(entries.size() > 0);
+    final SearchResultEntry entry = entries.get(0);
+    final AccountUsabilityResponseControl aurctrl = entry.getControl(
+        AccountUsabilityResponseControl.DECODER, new DecodeOptions());
+    assertNull(aurctrl);
+  }
+
+
+
+  @Test()
+  public void testValidResponseControl() throws Exception
+  {
+    // Send this control with a search request and see that you get
+    // a valid response.
+    final SearchRequest req = Requests.newSearchRequest(DN
+        .valueOf("uid=user.1,ou=people,o=test"), SearchScope.BASE_OBJECT,
+        Filter.getObjectClassPresentFilter());
+    final AccountUsabilityRequestControl control = AccountUsabilityRequestControl
+        .newControl(false);
+    req.addControl(control);
+    final Connection con = TestCaseUtils.getInternalConnection();
+    final List<SearchResultEntry> entries = new ArrayList<SearchResultEntry>();
+    con.search(req, entries);
+    assertTrue(entries.size() > 0);
+    final SearchResultEntry entry = entries.get(0);
+    final AccountUsabilityResponseControl aurctrl = entry.getControl(
+        AccountUsabilityResponseControl.DECODER, new DecodeOptions());
+    assertFalse(aurctrl.isExpired());
+    assertFalse(aurctrl.isLocked());
+    assertFalse(aurctrl.isInactive());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferReaderTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferReaderTestCase.java
new file mode 100644
index 0000000..5c33709
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferReaderTestCase.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1ReaderTestCase;
+
+import org.glassfish.grizzly.TransportFactory;
+import org.glassfish.grizzly.memory.ByteBufferWrapper;
+
+
+
+/**
+ * This class provides testcases for ASN1BufferReader.
+ */
+public class ASN1BufferReaderTestCase extends ASN1ReaderTestCase
+{
+  @Override
+  protected ASN1Reader getReader(final byte[] b, final int maxElementSize)
+      throws IOException
+  {
+    final ByteBufferWrapper buffer = new ByteBufferWrapper(ByteBuffer.wrap(b));
+    final ASN1BufferReader reader = new ASN1BufferReader(maxElementSize,
+        TransportFactory.getInstance().getDefaultMemoryManager());
+    reader.appendBytesRead(buffer);
+    return reader;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferWriterTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferWriterTestCase.java
new file mode 100644
index 0000000..18125d4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/ASN1BufferWriterTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.asn1.ASN1Writer;
+import org.opends.sdk.asn1.ASN1WriterTestCase;
+
+import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.TransportFactory;
+import org.glassfish.grizzly.memory.ByteBufferWrapper;
+
+
+
+/**
+ * This class provides testcases for ASN1BufferWriter.
+ */
+public class ASN1BufferWriterTestCase extends ASN1WriterTestCase
+{
+
+  private final ASN1BufferWriter writer = ASN1BufferWriter.getWriter();
+
+
+
+  @Override
+  protected byte[] getEncodedBytes() throws IOException, DecodeException
+  {
+    final Buffer buffer = writer.getBuffer();
+    final byte[] byteArray = new byte[buffer.remaining()];
+    buffer.get(byteArray);
+    return byteArray;
+  }
+
+
+
+  @Override
+  protected ASN1Reader getReader(final byte[] encodedBytes)
+      throws DecodeException, IOException
+  {
+    final ByteBufferWrapper buffer = new ByteBufferWrapper(ByteBuffer.wrap(encodedBytes));
+    final ASN1BufferReader reader = new ASN1BufferReader(0, TransportFactory
+        .getInstance().getDefaultMemoryManager());
+    reader.appendBytesRead(buffer);
+    return reader;
+  }
+
+
+
+  @Override
+  protected ASN1Writer getWriter() throws IOException
+  {
+    writer.flush();
+    writer.recycle();
+    return writer;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransportTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransportTestCase.java
new file mode 100644
index 0000000..b7d5227
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPDefaultTCPNIOTransportTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import static org.testng.Assert.assertTrue;
+
+import java.net.Socket;
+import java.util.Random;
+
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests LDAPDefaultTCPNIOTransport class.
+ */
+public class LDAPDefaultTCPNIOTransportTestCase extends LDAPTestCase
+{
+  /**
+   * Tests the default transport.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test()
+  public void testGetInstance() throws Exception
+  {
+    // Create a transport.
+    final TCPNIOTransport transport = LDAPDefaultTCPNIOTransport.getInstance();
+    final Random r = new Random();
+    int port = r.nextInt(10000);
+    if (port < 1000)
+    {
+      port += 1000;
+    }
+    transport.bind(port);
+    // Establish a socket connection to see if the transport factory works.
+    final Socket socket = new Socket("localhost", port);
+    // Successfully connected if there is no exception.
+    assertTrue(socket.isConnected());
+    // Don't stop the transport because it is shared with the ldap server.
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPTestCase.java
new file mode 100644
index 0000000..7d2e509
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/ldap/LDAPTestCase.java
@@ -0,0 +1,45 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.ldap;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all ldap unit tests should extend. Ldap represents the
+ * classes found directly under the package com.sun.opends.sdk.ldap.
+ */
+
+@Test(groups = { "precommit", "ldap", "sdk" }, sequential = true)
+public abstract class LDAPTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/messages/MessagesTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/messages/MessagesTestCase.java
new file mode 100644
index 0000000..c6d4c57
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/messages/MessagesTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.messages;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+
+
+
+public class MessagesTestCase extends OpenDSTestCase
+{
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/ASCIICharPropTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/ASCIICharPropTestCase.java
new file mode 100644
index 0000000..d2f2a69
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/ASCIICharPropTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests various methods of ASCIICharProp class.
+ */
+public class ASCIICharPropTestCase extends UtilTestCase
+{
+  /**
+   * Invalid Ascii char data provider.
+   *
+   * @return Returns an array of data.
+   */
+  @DataProvider(name = "invalidasciidata")
+  public Object[][] createInValidASCIIData()
+  {
+    return new Object[][] {
+    // {null,/* uppercase*/ false,/*hex value*/0,/*decimal value*/0,/* is
+    // letter*/false,/*is digit*/false,/*is keychar*/false},
+    { '\u200A' } };
+  }
+
+
+
+  /**
+   * Valid Ascii char data provider.
+   *
+   * @return Returns an array of data.
+   */
+  @DataProvider(name = "validasciidata")
+  public Object[][] createValidASCIIData()
+  {
+    return new Object[][] {
+        { (char) 1,/* uppercase */false,/* hex value */0,/* decimal value */0,/*
+                                                                               * is
+                                                                               * letter
+                                                                               */
+        false,/* is digit */false,/* is keychar */false },
+        { '-',/* uppercase */false,/* hex value */-1,/* decimal value */-1,/*
+                                                                            * is
+                                                                            * letter
+                                                                            */
+        false,/* is digit */false,/* is keychar */true },
+        { 'a',/* uppercase */false,/* hex value */10,/* decimal value */-1,/*
+                                                                            * is
+                                                                            * letter
+                                                                            */
+        true,/* is digit */false,/* is keychar */true },
+        { 'A',/* uppercase */true,/* hex value */10,/* decimal value */-1,/*
+                                                                           * is
+                                                                           * letter
+                                                                           */
+        true,/* is digit */false,/* is keychar */true },
+        { '1',/* uppercase */false,/* hex value */1,/* decimal value */1,/*
+                                                                          * is
+                                                                          * letter
+                                                                          */
+        false,/* is digit */true,/* is keychar */true }, };
+  }
+
+
+
+  /**
+   * Tests whether a character is an invalid ascii character or not.
+   *
+   * @param myChar
+   *          The character that needs to be verified.
+   * @throws Exception
+   *           In case of any errors.
+   */
+  @Test(dataProvider = "invalidasciidata")
+  public void testEncode(final char myChar) throws Exception
+  {
+    assertEquals(ASCIICharProp.valueOf(myChar), null);
+  }
+
+
+
+  /**
+   * Tests whether a character is a valid ascii character or not.
+   *
+   * @param myChar
+   *          The character that needs to be verified.
+   * @param isUpper
+   *          Whether it is uppercase
+   * @param hexValue
+   *          The hexadecimal value
+   * @param decimalValue
+   *          The decimal value
+   * @param isLetter
+   *          Whether the character is a letter
+   * @param isDigit
+   *          Whether the character is a digit
+   * @param isKeyChar
+   *          Whether the character is a key char.
+   * @throws Exception
+   *           In case of any errors.
+   */
+  @Test(dataProvider = "validasciidata")
+  public void testEncode(final char myChar, final Boolean isUpper,
+      final Integer hexValue, final Integer decimalValue,
+      final Boolean isLetter, final Boolean isDigit, final Boolean isKeyChar)
+      throws Exception
+  {
+    final ASCIICharProp myProp = ASCIICharProp.valueOf(myChar);
+
+    // check letter.
+    if (isLetter)
+    {
+      assertTrue(myProp.isLetter());
+      // Check case.
+      if (isUpper)
+      {
+        assertTrue(myProp.isUpperCase());
+      }
+      else
+      {
+        assertTrue(myProp.isLowerCase());
+      }
+    }
+
+    // check digit.
+    if (isDigit)
+    {
+      assertTrue(myProp.isDigit());
+    }
+
+    if (isLetter || isDigit)
+    {
+      // Check hex.
+      final int hex = myProp.hexValue();
+      final int hex1 = hexValue.intValue();
+      assertEquals(myProp.hexValue(), hexValue.intValue());
+      // Decimal value.
+      assertEquals(myProp.decimalValue(), decimalValue.intValue());
+      // Check if it is equal to itself.
+      assertEquals(myProp.charValue(), myChar);
+      assertEquals(myProp.compareTo(ASCIICharProp.valueOf(myChar)), 0);
+    }
+
+    // keychar.
+    if (isKeyChar)
+    {
+      assertTrue(myProp.isKeyChar());
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/Base64TestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/Base64TestCase.java
new file mode 100644
index 0000000..4218ec1
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/Base64TestCase.java
@@ -0,0 +1,238 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.Arrays;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class defines a set of tests for the {@link org.opends.sdk.util.Base64}
+ * class.
+ */
+public final class Base64TestCase extends UtilTestCase
+{
+  // Look up table for converting hex chars to byte values.
+  private static final byte[] hexToByte = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10,
+      11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14,
+      15, -1, -1, -1, -1, -1, -1, -1, -1, -1 - 1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1 };
+
+
+
+  /**
+   * Base 64 invalid test data provider.
+   *
+   * @return Returns an array of invalid encoded base64 data.
+   */
+  @DataProvider(name = "invalidData")
+  public Object[][] createInvalidData()
+  {
+    // FIXME: fix cases ==== and ==x=
+
+    return new Object[][] { { "=" }, { "==" }, { "===" }, { "A" }, { "AA" },
+        { "AAA" }, { "AA`=" }, { "AA~=" }, { "AA!=" }, { "AA@=" }, { "AA#=" },
+        { "AA$=" }, { "AA%=" }, { "AA^=" }, { "AA*=" }, { "AA(=" }, { "AA)=" },
+        { "AA_=" }, { "AA-=" }, { "AA{=" }, { "AA}=" }, { "AA|=" }, { "AA[=" },
+        { "AA]=" }, { "AA\\=" }, { "AA;=" }, { "AA'=" }, { "AA\"=" },
+        { "AA:=" }, { "AA,=" }, { "AA.=" }, { "AA<=" }, { "AA>=" }, { "AA?=" },
+        { "AA;=" } };
+  }
+
+
+
+  /**
+   * Base 64 valid test data provider.
+   *
+   * @return Returns an array of decoded and valid encoded base64 data.
+   */
+  @DataProvider(name = "validData")
+  public Object[][] createValidData()
+  {
+    return new Object[][] {
+        { "", "" },
+        { "00", "AA==" },
+        { "01", "AQ==" },
+        { "02", "Ag==" },
+        { "03", "Aw==" },
+        { "04", "BA==" },
+        { "05", "BQ==" },
+        { "06", "Bg==" },
+        { "07", "Bw==" },
+        { "0000", "AAA=" },
+        { "000000", "AAAA" },
+        { "00000000", "AAAAAA==" },
+        {
+            "000102030405060708090a0b0c0d0e0f"
+                + "101112131415161718191a1b1c1d1e1f"
+                + "202122232425262728292a2b2c2d2e2f"
+                + "303132333435363738393a3b3c3d3e3f"
+                + "404142434445464748494a4b4c4d4e4f"
+                + "505152535455565758595a5b5c5d5e5f"
+                + "606162636465666768696a6b6c6d6e6f"
+                + "707172737475767778797a7b7c7d7e7f"
+                + "808182838485868788898a8b8c8d8e8f"
+                + "909192939495969798999a9b9c9d9e9f"
+                + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+                + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+                + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+                + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+                + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+                + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+            "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v"
+                + "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f"
+                + "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P"
+                + "kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/"
+                + "wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+                + "8PHy8/T19vf4+fr7/P3+/w==" }, };
+  }
+
+
+
+  /**
+   * Tests the decode method against invalid data.
+   *
+   * @param encodedData
+   *          The invalid encoded data.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "invalidData", expectedExceptions = { LocalizedIllegalArgumentException.class })
+  public void testDecodeInvalidData(final String encodedData) throws Exception
+  {
+    Assert.fail("Expected exception but got result: "
+        + Arrays.toString(new ByteString[] { Base64.decode(encodedData) }));
+  }
+
+
+
+  /**
+   * Tests the decode method against valid data.
+   *
+   * @param hexData
+   *          The decoded hex data.
+   * @param encodedData
+   *          The encoded data.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "validData")
+  public void testDecodeValidData(final String hexData, final String encodedData)
+      throws Exception
+  {
+    final byte[] data = getBytes(hexData);
+    final byte[] decodedData = Base64.decode(encodedData).toByteArray();
+    Assert.assertEquals(decodedData, data);
+  }
+
+
+
+  /**
+   * Tests the encode method.
+   *
+   * @param hexData
+   *          The decoded hex data.
+   * @param encodedData
+   *          The encoded data.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "validData")
+  public void testEncode(final String hexData, final String encodedData)
+      throws Exception
+  {
+    final byte[] data = getBytes(hexData);
+    final String base64 = Base64.encode(ByteString.wrap(data));
+    Assert.assertEquals(base64, encodedData);
+  }
+
+
+
+  /**
+   * Decode a hex string to a byte-array.
+   *
+   * @param hexData
+   *          The string of hex.
+   * @return Returns the decoded byte array.
+   */
+  private byte[] getBytes(final String hexData)
+  {
+    final int sz = hexData.length();
+
+    if ((sz % 2) != 0)
+    {
+      throw new IllegalArgumentException(
+          "Hex string does not contain an even number of hex digits");
+    }
+
+    final byte[] bytes = new byte[sz / 2];
+
+    for (int i = 0, j = 0; i < sz; i += 2, j++)
+    {
+      int c = hexData.codePointAt(i);
+      if ((c & 0x7f) != c)
+      {
+        throw new IllegalArgumentException("Hex string contains non-hex digits");
+      }
+
+      final byte b1 = hexToByte[c];
+      if (b1 < 0)
+      {
+        throw new IllegalArgumentException("Hex string contains non-hex digits");
+      }
+
+      c = hexData.codePointAt(i + 1);
+      if ((c & 0x7f) != c)
+      {
+        throw new IllegalArgumentException("Hex string contains non-hex digits");
+      }
+
+      final byte b2 = hexToByte[c];
+      if (b2 < 0)
+      {
+        throw new IllegalArgumentException("Hex string contains non-hex digits");
+      }
+
+      bytes[j] = (byte) ((b1 << 4) | b2);
+    }
+
+    return bytes;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StaticUtilsTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StaticUtilsTestCase.java
new file mode 100644
index 0000000..6a8b34a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StaticUtilsTestCase.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test {@code StaticUtils}.
+ */
+public final class StaticUtilsTestCase extends UtilTestCase
+{
+  /**
+   * Create data for format(...) tests.
+   *
+   * @return Returns test data.
+   */
+  @DataProvider(name = "createFormatData")
+  public Object[][] createFormatData()
+  {
+    return new Object[][] {
+        // Note that Calendar months run from 0-11,
+        // and that there was no such year as year 0 (1 BC -> 1 AD).
+        { 1, 0, 1, 0, 0, 0, 0, "00010101000000.000Z" },
+        { 9, 0, 1, 0, 0, 0, 0, "00090101000000.000Z" },
+        { 10, 0, 1, 0, 0, 0, 0, "00100101000000.000Z" },
+        { 99, 0, 1, 0, 0, 0, 0, "00990101000000.000Z" },
+        { 100, 0, 1, 0, 0, 0, 0, "01000101000000.000Z" },
+        { 999, 0, 1, 0, 0, 0, 0, "09990101000000.000Z" },
+        { 1000, 0, 1, 0, 0, 0, 0, "10000101000000.000Z" },
+        { 2000, 0, 1, 0, 0, 0, 0, "20000101000000.000Z" },
+        { 2099, 0, 1, 0, 0, 0, 0, "20990101000000.000Z" },
+        { 2000, 8, 1, 0, 0, 0, 0, "20000901000000.000Z" },
+        { 2000, 9, 1, 0, 0, 0, 0, "20001001000000.000Z" },
+        { 2000, 10, 1, 0, 0, 0, 0, "20001101000000.000Z" },
+        { 2000, 11, 1, 0, 0, 0, 0, "20001201000000.000Z" },
+        { 2000, 0, 9, 0, 0, 0, 0, "20000109000000.000Z" },
+        { 2000, 0, 10, 0, 0, 0, 0, "20000110000000.000Z" },
+        { 2000, 0, 19, 0, 0, 0, 0, "20000119000000.000Z" },
+        { 2000, 0, 20, 0, 0, 0, 0, "20000120000000.000Z" },
+        { 2000, 0, 29, 0, 0, 0, 0, "20000129000000.000Z" },
+        { 2000, 0, 30, 0, 0, 0, 0, "20000130000000.000Z" },
+        { 2000, 0, 31, 0, 0, 0, 0, "20000131000000.000Z" },
+        { 2000, 0, 1, 9, 0, 0, 0, "20000101090000.000Z" },
+        { 2000, 0, 1, 10, 0, 0, 0, "20000101100000.000Z" },
+        { 2000, 0, 1, 19, 0, 0, 0, "20000101190000.000Z" },
+        { 2000, 0, 1, 20, 0, 0, 0, "20000101200000.000Z" },
+        { 2000, 0, 1, 23, 0, 0, 0, "20000101230000.000Z" },
+        { 2000, 0, 1, 0, 9, 0, 0, "20000101000900.000Z" },
+        { 2000, 0, 1, 0, 10, 0, 0, "20000101001000.000Z" },
+        { 2000, 0, 1, 0, 59, 0, 0, "20000101005900.000Z" },
+        { 2000, 0, 1, 0, 0, 9, 0, "20000101000009.000Z" },
+        { 2000, 0, 1, 0, 0, 10, 0, "20000101000010.000Z" },
+        { 2000, 0, 1, 0, 0, 59, 0, "20000101000059.000Z" },
+        { 2000, 0, 1, 0, 0, 0, 9, "20000101000000.009Z" },
+        { 2000, 0, 1, 0, 0, 0, 10, "20000101000000.010Z" },
+        { 2000, 0, 1, 0, 0, 0, 99, "20000101000000.099Z" },
+        { 2000, 0, 1, 0, 0, 0, 100, "20000101000000.100Z" },
+        { 2000, 0, 1, 0, 0, 0, 999, "20000101000000.999Z" }, };
+  }
+
+
+
+  @DataProvider(name = "dataForToLowerCase")
+  public Object[][] dataForToLowerCase()
+  {
+    // Value, toLowerCase or null if identity
+    return new Object[][] {
+        { "", null },
+        { " ", null },
+        { "   ", null },
+        { "12345", null },
+        {
+            "abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()_-+={}|[]\\:\";'<>?,./",
+            null },
+        {
+            "Aabcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()_-+={}|[]\\:\";'<>?,./",
+            "aabcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()_-+={}|[]\\:\";'<>?,./" },
+        {
+            "abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()_-+={}|[]\\:\";'<>?,./A",
+            "abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()_-+={}|[]\\:\";'<>?,./a" },
+        { "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz" },
+        { "\u00c7edilla", "\u00e7edilla" }, { "ced\u00cdlla", "ced\u00edlla" }, };
+  }
+
+
+
+  /**
+   * Tests {@link GeneralizedTimeSyntax#format(java.util.Date)}.
+   *
+   * @param yyyy
+   *          The year.
+   * @param MM
+   *          The month.
+   * @param dd
+   *          The day.
+   * @param HH
+   *          The hour.
+   * @param mm
+   *          The minute.
+   * @param ss
+   *          The second.
+   * @param SSS
+   *          The milli-seconds.
+   * @param expected
+   *          The expected generalized time formatted string.
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test(dataProvider = "createFormatData")
+  public void testFormatDate(final int yyyy, final int MM, final int dd,
+      final int HH, final int mm, final int ss, final int SSS,
+      final String expected) throws Exception
+  {
+    final Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    calendar.set(yyyy, MM, dd, HH, mm, ss);
+    calendar.set(Calendar.MILLISECOND, SSS);
+    final Date time = new Date(calendar.getTimeInMillis());
+    final String actual = StaticUtils.formatAsGeneralizedTime(time);
+    Assert.assertEquals(actual, expected);
+  }
+
+
+
+  /**
+   * Tests {@link StaticUtils#formatAsGeneralizedTime(long)} .
+   *
+   * @param yyyy
+   *          The year.
+   * @param MM
+   *          The month.
+   * @param dd
+   *          The day.
+   * @param HH
+   *          The hour.
+   * @param mm
+   *          The minute.
+   * @param ss
+   *          The second.
+   * @param SSS
+   *          The milli-seconds.
+   * @param expected
+   *          The expected generalized time formatted string.
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test(dataProvider = "createFormatData")
+  public void testFormatLong(final int yyyy, final int MM, final int dd,
+      final int HH, final int mm, final int ss, final int SSS,
+      final String expected) throws Exception
+  {
+    final Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    calendar.set(yyyy, MM, dd, HH, mm, ss);
+    calendar.set(Calendar.MILLISECOND, SSS);
+    final long time = calendar.getTimeInMillis();
+    final String actual = StaticUtils.formatAsGeneralizedTime(time);
+    Assert.assertEquals(actual, expected);
+  }
+
+
+
+  @Test(dataProvider = "dataForToLowerCase")
+  public void testToLowerCaseString(final String s, final String expected)
+  {
+    final String actual = StaticUtils.toLowerCase(s);
+    if (expected == null)
+    {
+      Assert.assertSame(actual, s);
+    }
+    else
+    {
+      Assert.assertEquals(actual, expected);
+    }
+  }
+
+
+
+  @Test(dataProvider = "dataForToLowerCase")
+  public void testToLowerCaseStringBuilder(final String s, final String expected)
+  {
+    final StringBuilder builder = new StringBuilder();
+    final String actual = StaticUtils.toLowerCase(s, builder).toString();
+    if (expected == null)
+    {
+      Assert.assertEquals(actual, s);
+    }
+    else
+    {
+      Assert.assertEquals(actual, expected);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StringPrepProfileTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StringPrepProfileTestCase.java
new file mode 100644
index 0000000..702fedb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/StringPrepProfileTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import static org.testng.Assert.assertEquals;
+
+import org.opends.sdk.Assertion;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.schema.MatchingRule;
+import org.opends.sdk.schema.Schema;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This Test Class tests various matching rules for their compability against
+ * RFC 4517,4518 and 3454.
+ */
+public class StringPrepProfileTestCase extends UtilTestCase
+{
+  /**
+   * Tests the stringprep preparation sans any case folding. This is applicable
+   * to case exact matching rules only.
+   */
+  @Test(dataProvider = "exactRuleData")
+  public void testStringPrepNoCaseFold(final String value1,
+      final String value2, final ConditionResult result) throws Exception
+  {
+    // Take any caseExact matching rule.
+    final MatchingRule rule = Schema.getCoreSchema()
+        .getMatchingRule("2.5.13.5");
+    final Assertion assertion = rule.getAssertion(ByteString.valueOf(value1));
+    final ByteString normalizedValue2 = rule.normalizeAttributeValue(ByteString
+        .valueOf(value2));
+    final ConditionResult liveResult = assertion.matches(normalizedValue2);
+    assertEquals(result, liveResult);
+  }
+
+
+
+  /**
+   * Tests the stringprep preparation with case folding. This is applicable to
+   * case ignore matching rules only.
+   */
+  @Test(dataProvider = "caseFoldRuleData")
+  public void testStringPrepWithCaseFold(final String value1,
+      final String value2, final ConditionResult result) throws Exception
+  {
+    // Take any caseExact matching rule.
+    final MatchingRule rule = Schema.getCoreSchema()
+        .getMatchingRule("2.5.13.2");
+    final Assertion assertion = rule.getAssertion(ByteString.valueOf(value1));
+    final ByteString normalizedValue2 = rule.normalizeAttributeValue(ByteString
+        .valueOf(value2));
+    final ConditionResult liveResult = assertion.matches(normalizedValue2);
+    assertEquals(result, liveResult);
+  }
+
+
+
+  // Generates data for case exact matching rules.
+  @DataProvider(name = "exactRuleData")
+  private Object[][] createExactRuleData()
+  {
+    return new Object[][] { { "12345678", "12345678", ConditionResult.TRUE },
+        { "ABC45678", "ABC45678", ConditionResult.TRUE },
+        { "ABC45678", "abc45678", ConditionResult.FALSE },
+        { "\u0020foo\u0020bar\u0020\u0020", "foo bar", ConditionResult.TRUE },
+        { "test\u00AD\u200D", "test", ConditionResult.TRUE },
+        { "foo\u000Bbar", "foo\u0020bar", ConditionResult.TRUE },
+        { "foo\u070Fbar", "foobar", ConditionResult.TRUE }, };
+  }
+
+
+
+  // Generates data for case ignore matching rules.
+  @DataProvider(name = "caseFoldRuleData")
+  private Object[][] createIgnoreRuleData()
+  {
+    return new Object[][] { { "12345678", "12345678", ConditionResult.TRUE },
+        { "ABC45678", "abc45678", ConditionResult.TRUE },
+        { "\u0020foo\u0020bar\u0020\u0020", "foo bar", ConditionResult.TRUE },
+        { "test\u00AD\u200D", "test", ConditionResult.TRUE },
+        { "foo\u000Bbar", "foo\u0020bar", ConditionResult.TRUE },
+        { "foo\u070Fbar", "foobar", ConditionResult.TRUE },
+        { "foo\u0149bar", "foo\u02BC\u006Ebar", ConditionResult.TRUE },
+        { "foo\u017Bbar", "foo\u017Cbar", ConditionResult.TRUE },
+        { "foo\u017BBAR", "foo\u017Cbar", ConditionResult.TRUE }, };
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/UtilTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/UtilTestCase.java
new file mode 100644
index 0000000..af703f4
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/com/sun/opends/sdk/util/UtilTestCase.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package com.sun.opends.sdk.util;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all util unit tests should extend. Util represents the
+ * classes found directly under the package org.opends.sdk.util.
+ */
+@Test(groups = { "precommit", "util", "sdk" }, sequential = true)
+public abstract class UtilTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/AttributeDescriptionTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/AttributeDescriptionTestCase.java
new file mode 100644
index 0000000..76da7f8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/AttributeDescriptionTestCase.java
@@ -0,0 +1,373 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 200-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Iterator;
+
+import org.opends.sdk.schema.Schema;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test {@code AttributeDescription}.
+ */
+public final class AttributeDescriptionTestCase extends OpenDSTestCase
+{
+  @DataProvider(name = "dataForCompareCoreSchema")
+  public Object[][] dataForCompareCoreSchema()
+  {
+    // AD1, AD2, compare result, isSubtype, isSuperType
+    return new Object[][] { { "cn", "cn", 0, true, true },
+        { "cn", "commonName", 0, true, true },
+        { " cn", "commonName ", 0, true, true },
+        { "commonName", "cn", 0, true, true },
+        { "commonName", "commonName", 0, true, true },
+        { "cn", "objectClass", 1, false, false },
+        { "objectClass", "cn", -1, false, false },
+        { "name", "cn", 1, false, true }, { "cn", "name", -1, true, false },
+        { "name;foo", "cn", 1, false, false },
+        { "cn;foo", "name", -1, true, false },
+        { "name", "cn;foo", 1, false, true },
+        { "cn", "name;foo", -1, false, false }, };
+  }
+
+
+
+  @DataProvider(name = "dataForCompareNoSchema")
+  public Object[][] dataForCompareNoSchema()
+  {
+    // AD1, AD2, compare result, isSubtype, isSuperType
+    return new Object[][] { { "cn", "cn", 0, true, true },
+        { "cn", "CN", 0, true, true }, { "CN", "cn", 0, true, true },
+        { "CN", "CN", 0, true, true },
+        { "cn", "commonName", -1, false, false },
+        { "commonName", "cn", 1, false, false },
+        { "commonName", "commonName", 0, true, true },
+        { "cn", "cn;foo", -1, false, true },
+        { "cn;foo", "cn", 1, true, false },
+        { "cn;foo", "cn;foo", 0, true, true },
+        { "CN;FOO", "cn;foo", 0, true, true },
+        { "cn;foo", "CN;FOO", 0, true, true },
+        { "CN;FOO", "CN;FOO", 0, true, true },
+        { "cn;foo", "cn;bar", 1, false, false },
+        { "cn;bar", "cn;foo", -1, false, false },
+
+        { "cn;xxx;yyy", "cn", 1, true, false },
+        { "cn;xxx;yyy", "cn;yyy", 1, true, false },
+        { "cn;xxx;yyy", "cn;xxx", 1, true, false },
+        { "cn;xxx;yyy", "cn;xxx;yyy", 0, true, true },
+        { "cn;xxx;yyy", "cn;yyy;xxx", 0, true, true },
+
+        { "cn", "cn;xxx;yyy", -1, false, true },
+        { "cn;yyy", "cn;xxx;yyy", -1, false, true },
+        { "cn;xxx", "cn;xxx;yyy", -1, false, true },
+        { "cn;xxx;yyy", "cn;xxx;yyy", 0, true, true },
+        { "cn;yyy;xxx", "cn;xxx;yyy", 0, true, true }, };
+  }
+
+
+
+  @DataProvider(name = "dataForValueOfCoreSchema")
+  public Object[][] dataForValueOfCoreSchema()
+  {
+    // Value, type, isObjectClass
+    return new Object[][] { { "cn", "cn", false }, { "CN", "cn", false },
+        { "commonName", "cn", false }, { "objectclass", "objectClass", true }, };
+  }
+
+
+
+  @DataProvider(name = "dataForValueOfInvalidAttributeDescriptions")
+  public Object[][] dataForValueOfInvalidAttributeDescriptions()
+  {
+    return new Object[][] { { "" }, { " " }, { ";" }, { " ; " }, { "0cn" },
+        { "cn." }, { "cn;foo+bar" }, { "cn;foo;foo+bar" }, { ";foo" },
+        { "cn;" }, { "cn;;foo" }, { "cn; ;foo" }, { "cn;foo;" },
+        { "cn;foo; " }, { "cn;foo;;bar" }, { "cn;foo; ;bar" },
+        { "cn;foo;bar;;" }, { "1a" }, { "1.a" }, { "1-" }, { "1.1a" },
+        { "1.1.a" }, };
+  }
+
+
+
+  @DataProvider(name = "dataForValueOfNoSchema")
+  public Object[][] dataForValueOfNoSchema()
+  {
+    // Value, type, options, containsOptions("foo")
+    return new Object[][] {
+        { "cn", "cn", new String[0], false },
+        { " cn ", "cn", new String[0], false },
+        { "  cn  ", "cn", new String[0], false },
+        { "CN", "CN", new String[0], false },
+        { "1", "1", new String[0], false },
+        { "1.2", "1.2", new String[0], false },
+        { "1.2.3", "1.2.3", new String[0], false },
+        { "111.222.333", "111.222.333", new String[0], false },
+        { "objectClass", "objectClass", new String[0], false },
+        { "cn;foo", "cn", new String[] { "foo" }, true },
+        { "cn;FOO", "cn", new String[] { "FOO" }, true },
+        { "cn;bar", "cn", new String[] { "bar" }, false },
+        { "cn;BAR", "cn", new String[] { "BAR" }, false },
+        { "cn;foo;bar", "cn", new String[] { "foo", "bar" }, true },
+        { "cn;FOO;bar", "cn", new String[] { "FOO", "bar" }, true },
+        { "cn;foo;BAR", "cn", new String[] { "foo", "BAR" }, true },
+        { "cn;FOO;BAR", "cn", new String[] { "FOO", "BAR" }, true },
+        { "cn;bar;FOO", "cn", new String[] { "bar", "FOO" }, true },
+        { "cn;BAR;foo", "cn", new String[] { "BAR", "foo" }, true },
+        { "cn;bar;FOO", "cn", new String[] { "bar", "FOO" }, true },
+        { "cn;BAR;FOO", "cn", new String[] { "BAR", "FOO" }, true },
+        { " cn;BAR;FOO ", "cn", new String[] { "BAR", "FOO" }, true },
+        { "  cn;BAR;FOO  ", "cn", new String[] { "BAR", "FOO" }, true },
+        { "cn;xxx;yyy;zzz", "cn", new String[] { "xxx", "yyy", "zzz" }, false },
+        { "cn;zzz;YYY;xxx", "cn", new String[] { "zzz", "YYY", "xxx" }, false }, };
+  }
+
+
+
+  @Test(dataProvider = "dataForCompareCoreSchema")
+  public void testCompareCoreSchema(final String ad1, final String ad2,
+      final int compare, final boolean isSubType, final boolean isSuperType)
+  {
+    final AttributeDescription attributeDescription1 = AttributeDescription
+        .valueOf(ad1, Schema.getCoreSchema());
+
+    final AttributeDescription attributeDescription2 = AttributeDescription
+        .valueOf(ad2, Schema.getCoreSchema());
+
+    // Identity.
+    Assert.assertTrue(attributeDescription1.equals(attributeDescription1));
+    Assert
+        .assertTrue(attributeDescription1.compareTo(attributeDescription1) == 0);
+    Assert.assertTrue(attributeDescription1.isSubTypeOf(attributeDescription1));
+    Assert.assertTrue(attributeDescription1
+        .isSuperTypeOf(attributeDescription1));
+
+    if (compare == 0)
+    {
+      Assert.assertTrue(attributeDescription1.equals(attributeDescription2));
+      Assert.assertTrue(attributeDescription2.equals(attributeDescription1));
+      Assert
+          .assertTrue(attributeDescription1.compareTo(attributeDescription2) == 0);
+      Assert
+          .assertTrue(attributeDescription2.compareTo(attributeDescription1) == 0);
+
+      Assert.assertTrue(attributeDescription1
+          .isSubTypeOf(attributeDescription2));
+      Assert.assertTrue(attributeDescription1
+          .isSuperTypeOf(attributeDescription2));
+      Assert.assertTrue(attributeDescription2
+          .isSubTypeOf(attributeDescription1));
+      Assert.assertTrue(attributeDescription2
+          .isSuperTypeOf(attributeDescription1));
+    }
+    else
+    {
+      Assert.assertFalse(attributeDescription1.equals(attributeDescription2));
+      Assert.assertFalse(attributeDescription2.equals(attributeDescription1));
+
+      if (compare < 0)
+      {
+        Assert.assertTrue(attributeDescription1
+            .compareTo(attributeDescription2) < 0);
+        Assert.assertTrue(attributeDescription2
+            .compareTo(attributeDescription1) > 0);
+      }
+      else
+      {
+        Assert.assertTrue(attributeDescription1
+            .compareTo(attributeDescription2) > 0);
+        Assert.assertTrue(attributeDescription2
+            .compareTo(attributeDescription1) < 0);
+      }
+
+      Assert.assertEquals(attributeDescription1
+          .isSubTypeOf(attributeDescription2), isSubType);
+
+      Assert.assertEquals(attributeDescription1
+          .isSuperTypeOf(attributeDescription2), isSuperType);
+    }
+  }
+
+
+
+  @Test(dataProvider = "dataForCompareNoSchema")
+  public void testCompareNoSchema(final String ad1, final String ad2,
+      final int compare, final boolean isSubType, final boolean isSuperType)
+  {
+    final AttributeDescription attributeDescription1 = AttributeDescription
+        .valueOf(ad1, Schema.getEmptySchema());
+
+    final AttributeDescription attributeDescription2 = AttributeDescription
+        .valueOf(ad2, Schema.getEmptySchema());
+
+    // Identity.
+    Assert.assertTrue(attributeDescription1.equals(attributeDescription1));
+    Assert
+        .assertTrue(attributeDescription1.compareTo(attributeDescription1) == 0);
+    Assert.assertTrue(attributeDescription1.isSubTypeOf(attributeDescription1));
+    Assert.assertTrue(attributeDescription1
+        .isSuperTypeOf(attributeDescription1));
+
+    if (compare == 0)
+    {
+      Assert.assertTrue(attributeDescription1.equals(attributeDescription2));
+      Assert.assertTrue(attributeDescription2.equals(attributeDescription1));
+      Assert
+          .assertTrue(attributeDescription1.compareTo(attributeDescription2) == 0);
+      Assert
+          .assertTrue(attributeDescription2.compareTo(attributeDescription1) == 0);
+
+      Assert.assertTrue(attributeDescription1
+          .isSubTypeOf(attributeDescription2));
+      Assert.assertTrue(attributeDescription1
+          .isSuperTypeOf(attributeDescription2));
+      Assert.assertTrue(attributeDescription2
+          .isSubTypeOf(attributeDescription1));
+      Assert.assertTrue(attributeDescription2
+          .isSuperTypeOf(attributeDescription1));
+    }
+    else
+    {
+      Assert.assertFalse(attributeDescription1.equals(attributeDescription2));
+      Assert.assertFalse(attributeDescription2.equals(attributeDescription1));
+
+      if (compare < 0)
+      {
+        Assert.assertTrue(attributeDescription1
+            .compareTo(attributeDescription2) < 0);
+        Assert.assertTrue(attributeDescription2
+            .compareTo(attributeDescription1) > 0);
+      }
+      else
+      {
+        Assert.assertTrue(attributeDescription1
+            .compareTo(attributeDescription2) > 0);
+        Assert.assertTrue(attributeDescription2
+            .compareTo(attributeDescription1) < 0);
+      }
+
+      Assert.assertEquals(attributeDescription1
+          .isSubTypeOf(attributeDescription2), isSubType);
+
+      Assert.assertEquals(attributeDescription1
+          .isSuperTypeOf(attributeDescription2), isSuperType);
+    }
+  }
+
+
+
+  @Test(dataProvider = "dataForValueOfCoreSchema")
+  public void testValueOfCoreSchema(final String ad, final String at,
+      final boolean isObjectClass)
+  {
+    final AttributeDescription attributeDescription = AttributeDescription
+        .valueOf(ad, Schema.getCoreSchema());
+
+    Assert.assertEquals(attributeDescription.toString(), ad);
+
+    Assert.assertEquals(attributeDescription.getAttributeType().getNameOrOID(),
+        at);
+
+    Assert.assertEquals(attributeDescription.isObjectClass(), isObjectClass);
+
+    Assert.assertFalse(attributeDescription.hasOptions());
+    Assert.assertFalse(attributeDescription.containsOption("dummy"));
+
+    final Iterator<String> iterator = attributeDescription.getOptions()
+        .iterator();
+    Assert.assertFalse(iterator.hasNext());
+  }
+
+
+
+  // FIXME: none of these pass! The valueOf method is far to lenient.
+  @Test(dataProvider = "dataForValueOfInvalidAttributeDescriptions", expectedExceptions = LocalizedIllegalArgumentException.class)
+  public void testValueOfInvalidAttributeDescriptions(final String ad)
+  {
+    AttributeDescription.valueOf(ad, Schema.getEmptySchema());
+  }
+
+
+
+  @Test(dataProvider = "dataForValueOfNoSchema")
+  public void testValueOfNoSchema(final String ad, final String at,
+      final String[] options, final boolean containsFoo)
+  {
+    final AttributeDescription attributeDescription = AttributeDescription
+        .valueOf(ad, Schema.getEmptySchema());
+
+    Assert.assertEquals(attributeDescription.toString(), ad);
+
+    Assert.assertEquals(attributeDescription.getAttributeType().getNameOrOID(),
+        at);
+
+    Assert.assertFalse(attributeDescription.isObjectClass());
+
+    if (options.length == 0)
+    {
+      Assert.assertFalse(attributeDescription.hasOptions());
+    }
+    else
+    {
+      Assert.assertTrue(attributeDescription.hasOptions());
+    }
+
+    Assert.assertFalse(attributeDescription.containsOption("dummy"));
+    if (containsFoo)
+    {
+      Assert.assertTrue(attributeDescription.containsOption("foo"));
+      Assert.assertTrue(attributeDescription.containsOption("FOO"));
+      Assert.assertTrue(attributeDescription.containsOption("FoO"));
+    }
+    else
+    {
+      Assert.assertFalse(attributeDescription.containsOption("foo"));
+      Assert.assertFalse(attributeDescription.containsOption("FOO"));
+      Assert.assertFalse(attributeDescription.containsOption("FoO"));
+    }
+
+    for (final String option : options)
+    {
+      Assert.assertTrue(attributeDescription.containsOption(option));
+    }
+
+    final Iterator<String> iterator = attributeDescription.getOptions()
+        .iterator();
+    for (final String option : options)
+    {
+      Assert.assertTrue(iterator.hasNext());
+      Assert.assertEquals(iterator.next(), option);
+    }
+    Assert.assertFalse(iterator.hasNext());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteSequenceTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteSequenceTestCase.java
new file mode 100644
index 0000000..0d29541
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteSequenceTestCase.java
@@ -0,0 +1,247 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Abstract test case for the ByteSequence interface.
+ */
+public abstract class ByteSequenceTestCase extends SdkTestCase
+{
+  /**
+   * ByteSequence data provider that gets the ByteSequence implementation from
+   * the abstract method.
+   *
+   * @return The array of ByteStrings and the bytes it should contain.
+   */
+  @DataProvider(name = "byteSequenceProvider")
+  public Object[][] concreteByteSequenceProvider() throws Exception
+  {
+    return byteSequenceProvider();
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testByteAt(final ByteSequence bs, final byte[] ba)
+  {
+    for (int i = 0; i < ba.length; i++)
+    {
+      Assert.assertEquals(bs.byteAt(i), ba[i]);
+    }
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider", expectedExceptions = IndexOutOfBoundsException.class)
+  public void testByteAtBadIndex1(final ByteSequence bs, final byte[] ba)
+  {
+    bs.byteAt(ba.length);
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider", expectedExceptions = IndexOutOfBoundsException.class)
+  public void testByteAtBadIndex2(final ByteSequence bs, final byte[] ba)
+  {
+    bs.byteAt(-1);
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyTo(final ByteSequence bs, final byte[] ba)
+  {
+    final byte[] newBa = new byte[ba.length];
+    bs.copyTo(newBa);
+    Assert.assertTrue(Arrays.equals(newBa, ba));
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyToByteSequenceBuilder(final ByteSequence bs,
+      final byte[] ba)
+  {
+    final ByteStringBuilder builder = new ByteStringBuilder();
+    bs.copyTo(builder);
+    Assert.assertTrue(Arrays.equals(builder.toByteArray(), ba));
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyToOutputStream(final ByteSequence bs, final byte[] ba)
+      throws Exception
+  {
+    final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+    bs.copyTo(stream);
+    Assert.assertTrue(Arrays.equals(stream.toByteArray(), ba));
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider", expectedExceptions = IndexOutOfBoundsException.class)
+  public void testCopyToWithBadOffset(final ByteSequence bs, final byte[] ba)
+  {
+    bs.copyTo(new byte[0], -1);
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testCopyToWithOffset(final ByteSequence bs, final byte[] ba)
+  {
+    for (int i = 0; i < ba.length * 2; i++)
+    {
+      final byte[] newBa = new byte[ba.length * 2];
+      bs.copyTo(newBa, i);
+
+      final byte[] resultBa = new byte[ba.length * 2];
+      System.arraycopy(ba, 0, resultBa, i, Math.min(ba.length, ba.length * 2
+          - i));
+      Assert.assertTrue(Arrays.equals(newBa, resultBa));
+    }
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testEquals(final ByteSequence bs, final byte[] ba)
+      throws Exception
+  {
+    Assert.assertTrue(bs.equals(ByteString.wrap(ba)));
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testLength(final ByteSequence bs, final byte[] ba)
+      throws Exception
+  {
+    Assert.assertEquals(bs.length(), ba.length);
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testSubSequence(final ByteSequence bs, final byte[] ba)
+  {
+    ByteSequence bsSub = bs.subSequence(0, bs.length() / 2);
+    byte[] baSub = new byte[ba.length / 2];
+    System.arraycopy(ba, 0, baSub, 0, baSub.length);
+    Assert.assertTrue(Arrays.equals(bsSub.toByteArray(), baSub));
+
+    bsSub = bs.subSequence(ba.length / 4, (bs.length() / 4) * 3);
+    baSub = new byte[(bs.length() / 4) * 3 - ba.length / 4];
+    System.arraycopy(ba, ba.length / 4, baSub, 0, baSub.length);
+    Assert.assertTrue(Arrays.equals(bsSub.toByteArray(), baSub));
+
+    bsSub = bs.subSequence(ba.length / 2, bs.length());
+    baSub = new byte[bs.length() - ba.length / 2];
+    System.arraycopy(ba, ba.length / 2, baSub, 0, baSub.length);
+    Assert.assertTrue(Arrays.equals(bsSub.toByteArray(), baSub));
+
+    bsSub = bs.subSequence(0, bs.length());
+    Assert.assertTrue(Arrays.equals(bsSub.toByteArray(), ba));
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider", expectedExceptions = IndexOutOfBoundsException.class)
+  public void testSubSequenceBadStartEnd1(final ByteSequence bs, final byte[] ba)
+  {
+    bs.subSequence(-1, bs.length());
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider", expectedExceptions = IndexOutOfBoundsException.class)
+  public void testSubSequenceBadStartEnd2(final ByteSequence bs, final byte[] ba)
+  {
+    bs.subSequence(0, bs.length() + 1);
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider", expectedExceptions = IndexOutOfBoundsException.class)
+  public void testSubSequenceBadStartEnd3(final ByteSequence bs, final byte[] ba)
+  {
+    bs.subSequence(-1, bs.length() + 1);
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testToByteArray(final ByteSequence bs, final byte[] ba)
+  {
+    Assert.assertTrue(Arrays.equals(bs.toByteArray(), ba));
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testToByteSequence(final ByteSequence bs, final byte[] ba)
+  {
+    Assert.assertTrue(Arrays.equals(bs.toByteString().toByteArray(), ba));
+  }
+
+
+
+  @Test(dataProvider = "byteSequenceProvider")
+  public void testToString(final ByteSequence bs, final byte[] ba)
+  {
+    String str;
+    try
+    {
+      str = new String(ba, "UTF-8");
+    }
+    catch (final UnsupportedEncodingException uee)
+    {
+      str = new String(ba);
+    }
+
+    Assert.assertTrue(bs.toString().equals(str));
+  }
+
+
+
+  protected abstract Object[][] byteSequenceProvider() throws Exception;
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringBuilderTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringBuilderTestCase.java
new file mode 100644
index 0000000..462ce1c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringBuilderTestCase.java
@@ -0,0 +1,296 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test case for ByteStringBuilder.
+ */
+public class ByteStringBuilderTestCase extends ByteSequenceTestCase
+{
+  private static final byte[] eightBytes = new byte[] { (byte) 0x01,
+      (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06,
+      (byte) 0x07, (byte) 0x08 };
+
+
+
+  /**
+   * ByteSequence data provider.
+   *
+   * @return The array of ByteStrings and the bytes it should contain.
+   */
+  @Override
+  @DataProvider(name = "byteSequenceProvider")
+  public Object[][] byteSequenceProvider() throws Exception
+  {
+    final Object[][] builders = byteStringBuilderProvider();
+    final Object[][] addlSequences = new Object[builders.length + 1][];
+    System.arraycopy(builders, 0, addlSequences, 0, builders.length);
+    addlSequences[builders.length] = new Object[] {
+        new ByteStringBuilder().append(eightBytes).subSequence(2, 6),
+        new byte[] { (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 } };
+
+    return addlSequences;
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadByteBufferLength1()
+  {
+    new ByteStringBuilder().append(ByteBuffer.wrap(new byte[5]), -1);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadByteBufferLength2()
+  {
+    new ByteStringBuilder().append(ByteBuffer.wrap(new byte[5]), 6);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadByteSequenceReaderLength1()
+  {
+    new ByteStringBuilder().append(ByteString.wrap(new byte[5]).asReader(), -1);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadByteSequenceReaderLength2()
+  {
+    new ByteStringBuilder().append(ByteString.wrap(new byte[5]).asReader(), 6);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadInputStreamLength() throws Exception
+  {
+    final ByteArrayInputStream stream = new ByteArrayInputStream(new byte[5]);
+    new ByteStringBuilder().append(stream, -1);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadLength1()
+  {
+    new ByteStringBuilder().append(new byte[5], 0, 6);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadLength2()
+  {
+    new ByteStringBuilder().append(new byte[5], 0, -1);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadOffset1()
+  {
+    new ByteStringBuilder().append(new byte[5], -1, 3);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testAppendBadOffset2()
+  {
+    new ByteStringBuilder().append(new byte[5], 6, 0);
+  }
+
+
+
+  @Test
+  public void testAppendInputStream() throws Exception
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+    final ByteArrayInputStream stream = new ByteArrayInputStream(new byte[5]);
+    Assert.assertEquals(bsb.append(stream, 10), 5);
+  }
+
+
+
+  @Test(dataProvider = "builderProvider", expectedExceptions = IndexOutOfBoundsException.class)
+  public void testClear(final ByteStringBuilder bs, final byte[] ba)
+  {
+    bs.clear();
+    Assert.assertEquals(bs.length(), 0);
+    bs.byteAt(0);
+  }
+
+
+
+  @Test
+  public void testEnsureAdditionalCapacity()
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder(8);
+    Assert.assertEquals(bsb.getBackingArray().length, 8);
+    bsb.ensureAdditionalCapacity(43);
+    bsb.ensureAdditionalCapacity(2);
+    Assert.assertTrue(bsb.getBackingArray().length >= 43);
+  }
+
+
+
+  @Test(dataProvider = "builderProvider")
+  public void testGetBackingArray(final ByteStringBuilder bs, final byte[] ba)
+  {
+    final byte[] trimmedArray = new byte[bs.length()];
+    System.arraycopy(bs.getBackingArray(), 0, trimmedArray, 0, bs.length());
+    Assert.assertTrue(Arrays.equals(trimmedArray, ba));
+  }
+
+
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void testInvalidCapacity()
+  {
+    new ByteStringBuilder(-1);
+  }
+
+
+
+  @Test
+  public void testTrimToSize()
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(eightBytes);
+    Assert.assertTrue(bsb.getBackingArray().length > 8);
+    bsb.trimToSize();
+    Assert.assertEquals(bsb.getBackingArray().length, 8);
+  }
+
+
+
+  @DataProvider(name = "builderProvider")
+  private Object[][] byteStringBuilderProvider() throws Exception
+  {
+    final ByteBuffer testBuffer = ByteBuffer.wrap(eightBytes);
+    final ByteString testByteString = ByteString.wrap(eightBytes);
+    final ByteSequenceReader testByteReader = testByteString.asReader();
+    final InputStream testStream = new ByteArrayInputStream(eightBytes);
+    final ByteStringBuilder testBuilderFromStream = new ByteStringBuilder(8);
+    testBuilderFromStream.append(testStream, 8);
+
+    return new Object[][] {
+        { new ByteStringBuilder().append((byte) 0x00).append((byte) 0x01),
+            new byte[] { (byte) 0x00, (byte) 0x01 } },
+        {
+            new ByteStringBuilder(5)
+                .append(
+                    new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                        (byte) 0x04 }).append(
+                    new byte[] { (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                        (byte) 0x08 }), eightBytes },
+        {
+            new ByteStringBuilder(3).append(eightBytes, 0, 3).append(
+                eightBytes, 3, 5), eightBytes },
+        { new ByteStringBuilder().append(testBuffer, 3).append(testBuffer, 5),
+            eightBytes },
+        { new ByteStringBuilder(2).append(testByteString), eightBytes },
+        {
+            new ByteStringBuilder().append(testByteReader, 5).append(
+                testByteReader, 3), eightBytes },
+        { testBuilderFromStream, eightBytes },
+        {
+            new ByteStringBuilder().append(Short.MIN_VALUE).append(
+                Short.MAX_VALUE),
+            new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x7F, (byte) 0xFF } },
+        {
+            new ByteStringBuilder(5).append(Integer.MIN_VALUE).append(
+                Integer.MAX_VALUE),
+            new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF } },
+        {
+            new ByteStringBuilder().append(Long.MIN_VALUE).append(
+                Long.MAX_VALUE),
+            new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+                (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF } },
+        { new ByteStringBuilder(11).append("this is a").append(" test"),
+            "this is a test".getBytes("UTF-8") },
+        {
+            new ByteStringBuilder().appendBERLength(0x00000000)
+                .appendBERLength(0x00000001).appendBERLength(0x0000000F)
+                .appendBERLength(0x00000010).appendBERLength(0x0000007F).
+
+                appendBERLength(0x000000FF).
+
+                appendBERLength(0x00000100).appendBERLength(0x00000FFF)
+                .appendBERLength(0x00001000).appendBERLength(0x0000FFFF).
+
+                appendBERLength(0x00010000).appendBERLength(0x000FFFFF)
+                .appendBERLength(0x00100000).appendBERLength(0x00FFFFFF).
+
+                appendBERLength(0x01000000).appendBERLength(0x0FFFFFFF)
+                .appendBERLength(0x10000000).appendBERLength(0xFFFFFFFF),
+
+            new byte[] { (byte) 0x00, (byte) 0x01, (byte) 0x0F, (byte) 0x10,
+                (byte) 0x7F,
+
+                (byte) 0x81, (byte) 0xFF,
+
+                (byte) 0x82, (byte) 0x01, (byte) 0x00, (byte) 0x82,
+                (byte) 0x0F, (byte) 0xFF, (byte) 0x82, (byte) 0x10,
+                (byte) 0x00, (byte) 0x82, (byte) 0xFF, (byte) 0xFF,
+
+                (byte) 0x83, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+                (byte) 0x83, (byte) 0x0F, (byte) 0xFF, (byte) 0xFF,
+                (byte) 0x83, (byte) 0x10, (byte) 0x00, (byte) 0x00,
+                (byte) 0x83, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+
+                (byte) 0x84, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x84, (byte) 0x0F, (byte) 0xFF,
+                (byte) 0xFF, (byte) 0xFF, (byte) 0x84, (byte) 0x10,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x84,
+                (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF } },
+
+    };
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringTestCase.java
new file mode 100644
index 0000000..809937d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ByteStringTestCase.java
@@ -0,0 +1,195 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Arrays;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class defines a set of tests for the org.opends.server.types.ByteString
+ * class.
+ */
+public class ByteStringTestCase extends ByteSequenceTestCase
+{
+  /**
+   * ByteString data provider.
+   *
+   * @return The array of ByteStrings and the bytes it should contain.
+   */
+  @Override
+  @DataProvider(name = "byteSequenceProvider")
+  public Object[][] byteSequenceProvider() throws Exception
+  {
+    return new Object[][] {
+        { ByteString.empty(), new byte[0] },
+        { ByteString.valueOf(1),
+            new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 } },
+        { ByteString.valueOf(Integer.MAX_VALUE),
+            new byte[] { (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF } },
+        { ByteString.valueOf(Integer.MIN_VALUE),
+            new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00 } },
+        {
+            ByteString.valueOf(Long.MAX_VALUE),
+            new byte[] { (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+                (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF } },
+        {
+            ByteString.valueOf(Long.MIN_VALUE),
+            new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 } },
+        { ByteString.valueOf("cn=testvalue"), "cn=testvalue".getBytes("UTF-8") },
+        { ByteString.wrap(new byte[0]), new byte[0] },
+        {
+            ByteString
+                .wrap(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                    (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                    (byte) 0x08 }),
+            new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+                (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08 } },
+        {
+            ByteString.wrap(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                (byte) 0x08, (byte) 0x09, (byte) 0x10 }, 0, 8),
+            new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+                (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08 } },
+        {
+            ByteString.wrap(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                (byte) 0x08, (byte) 0x09, (byte) 0x10 }, 1, 8),
+            new byte[] { (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
+                (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x09 } },
+        {
+            ByteString.wrap(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                (byte) 0x08, (byte) 0x09, (byte) 0x10 }, 2, 8),
+            new byte[] { (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06,
+                (byte) 0x07, (byte) 0x08, (byte) 0x09, (byte) 0x10 } },
+        {
+            ByteString.wrap(
+                new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
+                    (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
+                    (byte) 0x08 }, 3, 0), new byte[0] }, };
+  }
+
+
+
+  @DataProvider(name = "byteStringIntegerProvider")
+  public Object[][] byteStringIntegerProvider()
+  {
+    return new Object[][] { { ByteString.valueOf(0), 0 },
+        { ByteString.valueOf(1), 1 },
+        { ByteString.valueOf(Integer.MAX_VALUE), Integer.MAX_VALUE },
+        { ByteString.valueOf(Integer.MIN_VALUE), Integer.MIN_VALUE }, };
+  }
+
+
+
+  @DataProvider(name = "byteStringLongProvider")
+  public Object[][] byteStringLongProvider()
+  {
+    return new Object[][] { { ByteString.valueOf(0L), 0L },
+        { ByteString.valueOf(1L), 1L },
+        { ByteString.valueOf(Long.MAX_VALUE), Long.MAX_VALUE },
+        { ByteString.valueOf(Long.MIN_VALUE), Long.MIN_VALUE } };
+  }
+
+
+
+  @DataProvider(name = "byteStringCharArrayProvider")
+  public Object[][] byteStringCharArrayProvider()
+  {
+    return new Object[][] { { "" }, { "1" }, { "1234567890" } };
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testInvalidWrapLength()
+  {
+    ByteString.wrap(new byte[] { (byte) 0x00, (byte) 0x01, (byte) 0x02,
+        (byte) 0x03 }, 2, 8);
+  }
+
+
+
+  @Test(dataProvider = "byteStringIntegerProvider")
+  public void testToInteger(final ByteString bs, final int i)
+  {
+    Assert.assertEquals(bs.toInt(), i);
+  }
+
+
+
+  @Test(dataProvider = "byteStringLongProvider")
+  public void testToLong(final ByteString bs, final long l)
+  {
+    Assert.assertEquals(bs.toLong(), l);
+  }
+
+
+
+  @Test(dataProvider = "byteStringCharArrayProvider")
+  public void testToCharArray(final String s)
+  {
+    ByteString bs = ByteString.valueOf(s);
+    Assert.assertTrue(Arrays.equals(bs.toCharArray(), s.toCharArray()));
+  }
+
+
+
+  @Test(dataProvider = "byteStringCharArrayProvider")
+  public void testValueOfCharArray(final String s)
+  {
+    ByteString bs = ByteString.valueOf(s.toCharArray());
+    Assert.assertEquals(bs.toString(), s);
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testUndersizedToInteger()
+  {
+    ByteString.wrap(new byte[] { (byte) 0x00, (byte) 0x01 }).toInt();
+  }
+
+
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void testUndersizedToLong()
+  {
+    ByteString.wrap(
+        new byte[] { (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03 })
+        .toLong();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ConnectionFactoryTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ConnectionFactoryTestCase.java
new file mode 100644
index 0000000..5c60a52
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ConnectionFactoryTestCase.java
@@ -0,0 +1,308 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.InetSocketAddress;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+
+import org.opends.sdk.requests.DigestMD5SASLBindRequest;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.requests.SearchRequest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+import javax.net.ssl.SSLContext;
+
+
+
+/**
+ * Tests the connectionfactory classes.
+ */
+public class ConnectionFactoryTestCase extends SdkTestCase
+{
+  class MyResultHandler implements ResultHandler<AsynchronousConnection>
+  {
+    // latch.
+    private final CountDownLatch latch;
+    // invalid flag.
+    private volatile ErrorResultException error;
+
+
+
+    MyResultHandler(final CountDownLatch latch)
+    {
+      this.latch = latch;
+    }
+
+
+
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      // came here.
+      this.error = error;
+      latch.countDown();
+    }
+
+
+
+    public void handleResult(final AsynchronousConnection con)
+    {
+      //
+      latch.countDown();
+    }
+  }
+
+
+
+  /**
+   * Ensures that the LDAP Server is running.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer() throws Exception
+  {
+    TestCaseUtils.startServer();
+  }
+
+
+
+  /**
+   * Disables logging before the tests.
+   */
+  @BeforeClass()
+  public void disableLogging()
+  {
+    StaticUtils.DEBUG_LOG.setLevel(Level.SEVERE);
+  }
+
+
+
+  /**
+   * Re-enable logging after the tests.
+   */
+  @AfterClass()
+  public void enableLogging()
+  {
+    StaticUtils.DEBUG_LOG.setLevel(Level.INFO);
+  }
+
+
+
+  @DataProvider(name = "connectionFactories")
+  public Object[][] getConnectionFactories() throws Exception
+  {
+    Object[][] factories = new Object[21][1];
+
+    // HeartBeatConnectionFactory
+    // Use custom search request.
+    SearchRequest request = Requests.newSearchRequest(
+        "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT,
+        "objectclass=*", "cn");
+
+    factories[0][0] = new HeartBeatConnectionFactory(new LDAPConnectionFactory(
+        "localhost", TestCaseUtils.getLdapPort()), 1000, TimeUnit.MILLISECONDS,
+        request);
+
+    // InternalConnectionFactory
+    factories[1][0] = Connections.newInternalConnectionFactory(
+        LDAPServer.getInstance(), null);
+
+    // AuthenticatedConnectionFactory
+    factories[2][0] = new AuthenticatedConnectionFactory(
+        new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()),
+        Requests.newSimpleBindRequest("", new char[0]));
+
+    // AuthenticatedConnectionFactory with multi-stage SASL
+    factories[3][0] = new AuthenticatedConnectionFactory(
+        new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()),
+        Requests.newCRAMMD5SASLBindRequest("id:user",
+            ByteString.valueOf("password")));
+
+    // LDAPConnectionFactory with default options
+    factories[4][0] = new LDAPConnectionFactory("localhost",
+        TestCaseUtils.getLdapPort());
+
+    // LDAPConnectionFactory with startTLS
+    SSLContext sslContext = new SSLContextBuilder().setTrustManager(
+        TrustManagers.trustAll()).getSSLContext();
+    LDAPOptions options = new LDAPOptions()
+        .setSSLContext(sslContext)
+        .setUseStartTLS(true)
+        .addEnabledCipherSuite(
+            new String[] { "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+                "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+                "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
+                "SSL_DH_anon_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_RC4_128_MD5",
+                "TLS_DH_anon_WITH_AES_128_CBC_SHA",
+                "TLS_DH_anon_WITH_AES_256_CBC_SHA" });
+    factories[5][0] = new LDAPConnectionFactory("localhost",
+        TestCaseUtils.getLdapPort(), options);
+
+    // startTLS + SASL confidentiality
+    // Use IP address here so that DIGEST-MD5 host verification works if local
+    // host name is not localhost (e.g. on some machines it might be
+    // localhost.localdomain).
+    factories[6][0] = new AuthenticatedConnectionFactory(
+        new LDAPConnectionFactory(new InetSocketAddress("127.0.0.1",
+            TestCaseUtils.getLdapPort()), options), Requests
+            .newDigestMD5SASLBindRequest("id:user",
+                ByteString.valueOf("password"))
+            .addQOP(DigestMD5SASLBindRequest.QOP_AUTH_CONF)
+            .setCipher(DigestMD5SASLBindRequest.CIPHER_LOW));
+
+    // Connection pool and load balancing tests.
+    ConnectionFactory offlineServer1 = Connections.newNamedConnectionFactory(
+        new LDAPConnectionFactory("localhost", TestCaseUtils.findFreePort()),
+        "offline1");
+    ConnectionFactory offlineServer2 = Connections.newNamedConnectionFactory(
+        new LDAPConnectionFactory("localhost", TestCaseUtils.findFreePort()),
+        "offline2");
+    ConnectionFactory onlineServer = Connections.newNamedConnectionFactory(
+        new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()),
+        "online");
+
+    // Connection pools.
+    factories[7][0] = Connections.newConnectionPool(onlineServer, 10);
+
+    // Round robin.
+    factories[8][0] = Connections
+        .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
+            onlineServer, offlineServer1)));
+    factories[9][0] = factories[8][0];
+    factories[10][0] = factories[8][0];
+    factories[11][0] = Connections
+        .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
+            offlineServer1, onlineServer)));
+    factories[12][0] = Connections
+        .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
+            offlineServer1, offlineServer2, onlineServer)));
+    factories[13][0] = Connections
+        .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
+            Connections.newConnectionPool(offlineServer1, 10),
+            Connections.newConnectionPool(onlineServer, 10))));
+
+    // Fail-over.
+    factories[14][0] = Connections
+        .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
+            onlineServer, offlineServer1)));
+    factories[15][0] = factories[14][0];
+    factories[16][0] = factories[14][0];
+    factories[17][0] = Connections
+        .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
+            offlineServer1, onlineServer)));
+    factories[18][0] = Connections
+        .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
+            offlineServer1, offlineServer2, onlineServer)));
+    factories[19][0] = Connections
+        .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList(
+            Connections.newConnectionPool(offlineServer1, 10),
+            Connections.newConnectionPool(onlineServer, 10))));
+
+    factories[20][0] = Connections.newConnectionPool(onlineServer, 10);
+
+    return factories;
+  }
+
+
+
+  /**
+   * Tests the async connection in the blocking mode. This is not fully async as
+   * it blocks on the future.
+   *
+   * @throws Exception
+   */
+  @Test(dataProvider = "connectionFactories")
+  public void testBlockingFutureNoHandler(ConnectionFactory factory)
+      throws Exception
+  {
+    final FutureResult<AsynchronousConnection> future = factory
+        .getAsynchronousConnection(null);
+    final AsynchronousConnection con = future.get();
+    // quickly check if it is a valid connection.
+    // Don't use a result handler.
+    assertNotNull(con.readRootDSE(null).get());
+    con.close();
+  }
+
+
+
+  /**
+   * Tests the non-blocking fully async connection using a handler.
+   *
+   * @throws Exception
+   */
+  @Test(dataProvider = "connectionFactories")
+  public void testNonBlockingFutureWithHandler(ConnectionFactory factory)
+      throws Exception
+  {
+    // Use the handler to get the result asynchronously.
+    final CountDownLatch latch = new CountDownLatch(1);
+    final MyResultHandler handler = new MyResultHandler(latch);
+    final FutureResult<AsynchronousConnection> future = factory
+        .getAsynchronousConnection(handler);
+    // Since we don't have anything to do, we would rather
+    // be notified by the latch when the other thread calls our handler.
+    latch.await(); // should do a timed wait rather?
+    if (handler.error != null)
+    {
+      throw handler.error;
+    }
+  }
+
+
+
+  /**
+   * Tests the synchronous connection.
+   *
+   * @throws Exception
+   */
+  @Test(dataProvider = "connectionFactories")
+  public void testSynchronousConnection(ConnectionFactory factory)
+      throws Exception
+  {
+    final Connection con = factory.getConnection();
+    assertNotNull(con);
+    // quickly check if iit is a valid connection.
+    assertTrue(con.readRootDSE().getEntry().getName().isRootDN());
+    con.close();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/DNTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/DNTestCase.java
new file mode 100644
index 0000000..893ec98
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/DNTestCase.java
@@ -0,0 +1,980 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class defines a set of tests for the org.opends.sdk.DN class.
+ */
+public class DNTestCase extends SdkTestCase
+{
+  /**
+   * child DN test data provider.
+   *
+   * @return The array of test data.
+   */
+  @DataProvider(name = "createChildDNTestData")
+  public Object[][] createChildDNTestData()
+  {
+    return new Object[][] {
+        { "", "", "" },
+        { "", "dc=org", "dc=org" },
+        { "", "dc=opends,dc=org", "dc=opends,dc=org" },
+        { "dc=org", "", "dc=org" },
+        { "dc=org", "dc=opends", "dc=opends,dc=org" },
+        { "dc=org", "dc=foo,dc=opends", "dc=foo,dc=opends,dc=org" },
+        { "dc=opends,dc=org", "", "dc=opends,dc=org" },
+        { "dc=opends,dc=org", "dc=foo", "dc=foo,dc=opends,dc=org" },
+        { "dc=opends,dc=org", "dc=bar,dc=foo", "dc=bar,dc=foo,dc=opends,dc=org" }, };
+  }
+
+
+
+  /**
+   * Child RDN test data provider.
+   *
+   * @return The array of test data.
+   */
+  @DataProvider(name = "createChildRDNTestData")
+  public Object[][] createChildRDNTestData()
+  {
+    return new Object[][] { { "", "dc=org", "dc=org" },
+        { "dc=org", "dc=opends", "dc=opends,dc=org" },
+        { "dc=opends,dc=org", "dc=foo", "dc=foo,dc=opends,dc=org" }, };
+  }
+
+
+
+  /**
+   * DN test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "testDNs")
+  public Object[][] createData()
+  {
+    return new Object[][] {
+        { "", "", "" },
+        { "   ", "", "" },
+        { "cn=", "cn=", "cn=" },
+        { "cn= ", "cn=", "cn=" },
+        { "cn =", "cn=", "cn=" },
+        { "cn = ", "cn=", "cn=" },
+        { "dc=com", "dc=com", "dc=com" },
+        { "dc=com+o=com", "dc=com+o=com", "dc=com+o=com" },
+        { "DC=COM", "dc=com", "DC=COM" },
+        { "dc = com", "dc=com", "dc=com" },
+        { " dc = com ", "dc=com", "dc=com" },
+        { "dc=example,dc=com", "dc=example,dc=com", "dc=example,dc=com" },
+        { "dc=example, dc=com", "dc=example,dc=com", "dc=example,dc=com" },
+        { "dc=example ,dc=com", "dc=example,dc=com", "dc=example,dc=com" },
+        { "dc =example , dc  =   com", "dc=example,dc=com", "dc=example,dc=com" },
+        { "givenName=John+cn=Doe,ou=People,dc=example,dc=com",
+            "cn=doe+givenname=john,ou=people,dc=example,dc=com",
+            "givenName=John+cn=Doe,ou=People,dc=example,dc=com" },
+        { "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com",
+            "givenname=john\\+cn\\=doe,ou=people,dc=example,dc=com",
+            "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com" },
+        { "cn=Doe\\, John,ou=People,dc=example,dc=com",
+            "cn=doe\\, john,ou=people,dc=example,dc=com",
+            "cn=Doe\\, John,ou=People,dc=example,dc=com" },
+        { "UID=jsmith,DC=example,DC=net", "uid=jsmith,dc=example,dc=net",
+            "UID=jsmith,DC=example,DC=net" },
+        { "OU=Sales+CN=J. Smith,DC=example,DC=net",
+            "cn=j. smith+ou=sales,dc=example,dc=net",
+            "OU=Sales+CN=J. Smith,DC=example,DC=net" },
+        { "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net",
+            "cn=james \\\"jim\\\" smith\\, iii,dc=example,dc=net",
+            "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net" },
+        { "CN=John Smith\\2C III,DC=example,DC=net",
+            "cn=john smith\\, iii,dc=example,dc=net",
+            "CN=John Smith\\, III,DC=example,DC=net" },
+        { "CN=\\23John Smith\\20,DC=example,DC=net",
+            "cn=\\#john smith,dc=example,dc=net",
+            "CN=\\#John Smith\\ ,DC=example,DC=net" },
+        {
+            "CN=Before\\0dAfter,DC=example,DC=net",
+            // \0d is a hex representation of Carriage return. It is mapped
+            // to a SPACE as defined in the MAP ( RFC 4518)
+            "cn=before after,dc=example,dc=net",
+            "CN=Before\\0dAfter,DC=example,DC=net" },
+        { "2.5.4.3=#04024869",
+        // Unicode codepoints from 0000-0008 are mapped to nothing.
+            "cn=hi", "2.5.4.3=\\04\\02Hi" },
+        { "1.1.1=", "1.1.1=", "1.1.1=" },
+        { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107", "CN=Lu\u010di\u0107" },
+        { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius",
+            "ou=\u55b6\u696d\u90e8,o=airius", "ou=\u55b6\u696d\u90e8,o=Airius" },
+        { "photo=\\ john \\ ,dc=com", "photo=\\ john \\ ,dc=com",
+            "photo=\\ john \\ ,dc=com" },
+        { "AB-global=", "ab-global=", "AB-global=" },
+        { "OU= Sales + CN = J. Smith ,DC=example,DC=net",
+            "cn=j. smith+ou=sales,dc=example,dc=net",
+            "OU=Sales+CN=J. Smith,DC=example,DC=net" },
+        { "cn=John+a=", "a=+cn=john", "cn=John+a=" },
+        { "O=\"Sue, Grabbit and Runn\",C=US", "o=sue\\, grabbit and runn,c=us",
+            "O=Sue\\, Grabbit and Runn,C=US" }, };
+  }
+
+
+
+  /**
+   * DN comparison test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "createDNComparisonData")
+  public Object[][] createDNComparisonData()
+  {
+    return new Object[][] {
+        { "cn=hello world,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=hello world,dc=com", "CN=hello world,dc=com", 0 },
+        { "cn=hello   world,dc=com", "cn=hello world,dc=com", 0 },
+        { "  cn =  hello world  ,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=hello world\\ ,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=HELLO WORLD,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=HELLO+sn=WORLD,dc=com", "sn=world+cn=hello,dc=com", 0 },
+        /**
+         * { "x-test-integer-type=10,dc=com", "x-test-integer-type=9,dc=com", 1
+         * }, { "x-test-integer-type=999,dc=com",
+         * "x-test-integer-type=1000,dc=com", -1 }, {
+         * "x-test-integer-type=-1,dc=com", "x-test-integer-type=0,dc=com", -1
+         * }, { "x-test-integer-type=0,dc=com", "x-test-integer-type=-1,dc=com",
+         * 1 },
+         **/
+        { "cn=aaa,dc=com", "cn=aaaa,dc=com", -1 },
+        { "cn=AAA,dc=com", "cn=aaaa,dc=com", -1 },
+        { "cn=aaa,dc=com", "cn=AAAA,dc=com", -1 },
+        { "cn=aaaa,dc=com", "cn=aaa,dc=com", 1 },
+        { "cn=AAAA,dc=com", "cn=aaa,dc=com", 1 },
+        { "cn=aaaa,dc=com", "cn=AAA,dc=com", 1 },
+        { "cn=aaab,dc=com", "cn=aaaa,dc=com", 1 },
+        { "cn=aaaa,dc=com", "cn=aaab,dc=com", -1 },
+        { "dc=aaa,dc=aaa", "dc=bbb", -1 },
+        { "dc=bbb,dc=aaa", "dc=bbb", -1 },
+        { "dc=ccc,dc=aaa", "dc=bbb", -1 },
+        { "dc=aaa,dc=bbb", "dc=bbb", 1 },
+        { "dc=bbb,dc=bbb", "dc=bbb", 1 },
+        { "dc=ccc,dc=bbb", "dc=bbb", 1 },
+        { "dc=aaa,dc=ccc", "dc=bbb", 1 },
+        { "dc=bbb,dc=ccc", "dc=bbb", 1 },
+        { "dc=ccc,dc=ccc", "dc=bbb", 1 },
+        { "", "dc=bbb", -1 },
+        { "dc=bbb", "", 1 } };
+  }
+
+
+
+  /**
+   * DN equality test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "createDNEqualityData")
+  public Object[][] createDNEqualityData()
+  {
+    return new Object[][] {
+        { "cn=hello world,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=hello world,dc=com", "CN=hello world,dc=com", 0 },
+        { "cn=hello   world,dc=com", "cn=hello world,dc=com", 0 },
+        { "  cn =  hello world  ,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=hello world\\ ,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=HELLO WORLD,dc=com", "cn=hello world,dc=com", 0 },
+        { "cn=HELLO+sn=WORLD,dc=com", "sn=world+cn=hello,dc=com", 0 },
+        { "x-test-integer-type=10,dc=com", "x-test-integer-type=9,dc=com", 1 },
+        { "x-test-integer-type=999,dc=com", "x-test-integer-type=1000,dc=com",
+            -1 },
+        { "x-test-integer-type=-1,dc=com", "x-test-integer-type=0,dc=com", -1 },
+        { "x-test-integer-type=0,dc=com", "x-test-integer-type=-1,dc=com", 1 },
+        { "cn=aaa,dc=com", "cn=aaaa,dc=com", -1 },
+        { "cn=AAA,dc=com", "cn=aaaa,dc=com", -1 },
+        { "cn=aaa,dc=com", "cn=AAAA,dc=com", -1 },
+        { "cn=aaaa,dc=com", "cn=aaa,dc=com", 1 },
+        { "cn=AAAA,dc=com", "cn=aaa,dc=com", 1 },
+        { "cn=aaaa,dc=com", "cn=AAA,dc=com", 1 },
+        { "cn=aaab,dc=com", "cn=aaaa,dc=com", 1 },
+        { "cn=aaaa,dc=com", "cn=aaab,dc=com", -1 },
+        { "dc=aaa,dc=aaa", "dc=bbb", -1 }, { "dc=bbb,dc=aaa", "dc=bbb", -1 },
+        { "dc=ccc,dc=aaa", "dc=bbb", -1 }, { "dc=aaa,dc=bbb", "dc=bbb", 1 },
+        { "dc=bbb,dc=bbb", "dc=bbb", 1 }, { "dc=ccc,dc=bbb", "dc=bbb", 1 },
+        { "dc=aaa,dc=ccc", "dc=bbb", 1 }, { "dc=bbb,dc=ccc", "dc=bbb", 1 },
+        { "dc=ccc,dc=ccc", "dc=bbb", 1 }, { "", "dc=bbb", -1 },
+        { "dc=bbb", "", 1 } };
+  }
+
+
+
+  /**
+   * Illegal DN test data provider.
+   *
+   * @return The array of illegal test DN strings.
+   */
+  @DataProvider(name = "illegalDNs")
+  public Object[][] createIllegalData()
+  {
+    return new Object[][] { { "manager" }, { "manager " }, { "=Jim" },
+        { " =Jim" }, { "= Jim" },
+        { " = Jim" },
+        { "cn+Jim" },
+        { "cn + Jim" },
+        { "cn=Jim+" },
+        { "cn=Jim+manager" },
+        { "cn=Jim+manager " },
+        { "cn=Jim+manager," },// { "cn=Jim," }, { "cn=Jim,  " }, { "c[n]=Jim" },
+        { "_cn=Jim" }, { "c_n=Jim" }, { "cn\"=Jim" }, { "c\"n=Jim" },
+        { "1cn=Jim" }, { "cn+uid=Jim" }, { "-cn=Jim" }, { "/tmp=a" },
+        { "\\tmp=a" }, { "cn;lang-en=Jim" }, { "@cn=Jim" },
+        { "_name_=Jim" },
+        { "\u03c0=pi" },
+        { "v1.0=buggy" },// { "1.=buggy" }, { ".1=buggy" },
+        { "oid.1." }, { "1.3.6.1.4.1.1466..0=#04024869" }, { "cn=#a" },
+        { "cn=#ag" }, { "cn=#ga" }, { "cn=#abcdefgh" },
+        { "cn=a\\b" }, // { "cn=a\\bg" }, { "cn=\"hello" },
+        { "cn=+mail=,dc=example,dc=com" }, { "cn=xyz+sn=,dc=example,dc=com" },
+        { "cn=,dc=example,dc=com" } };
+  }
+
+
+
+  /**
+   * Is Child of test data provider.
+   *
+   * @return The array of test data.
+   */
+  @DataProvider(name = "createIsChildOfTestData")
+  public Object[][] createIsChildOfTestData()
+  {
+    return new Object[][] { { "", "", false }, { "", "dc=org", false },
+        { "", "dc=opends,dc=org", false },
+        { "", "dc=foo,dc=opends,dc=org", false }, { "dc=org", "", true },
+        { "dc=org", "dc=org", false }, { "dc=org", "dc=opends,dc=org", false },
+        { "dc=org", "dc=foo,dc=opends,dc=org", false },
+        { "dc=opends,dc=org", "", false },
+        { "dc=opends,dc=org", "dc=org", true },
+        { "dc=opends,dc=org", "dc=opends,dc=org", false },
+        { "dc=opends,dc=org", "dc=foo,dc=opends,dc=org", false },
+        { "dc=foo,dc=opends,dc=org", "", false },
+        { "dc=foo,dc=opends,dc=org", "dc=org", false },
+        { "dc=foo,dc=opends,dc=org", "dc=opends,dc=org", true },
+        { "dc=foo,dc=opends,dc=org", "dc=foo,dc=opends,dc=org", false },
+        { "dc=org", "dc=com", false },
+        { "dc=opends,dc=org", "dc=foo,dc=org", false },
+        { "dc=opends,dc=org", "dc=opends,dc=com", false }, };
+  }
+
+
+
+  /**
+   * DN test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "createNumComponentsTestData")
+  public Object[][] createNumComponentsTestData()
+  {
+    return new Object[][] { { "", 0 }, { "dc=com", 1 },
+        { "dc=opends,dc=com", 2 }, { "dc=world,dc=opends,dc=com", 3 },
+        { "dc=hello,dc=world,dc=opends,dc=com", 4 }, };
+  }
+
+
+
+  /**
+   * DN test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "createParentAndRDNTestData")
+  public Object[][] createParentAndRDNTestData()
+  {
+    return new Object[][] {
+        { "", null, null },
+        { "dc=com", "", "dc=com" },
+        { "dc=opends,dc=com", "dc=com", "dc=opends" },
+        { "dc=world,dc=opends,dc=com", "dc=opends,dc=com", "dc=world" },
+        { "dc=hello,dc=world,dc=opends,dc=com", "dc=world,dc=opends,dc=com",
+            "dc=hello" }, };
+  }
+
+
+
+  /**
+   * DN test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "createRDNTestData")
+  public Object[][] createRDNTestData()
+  {
+    return new Object[][] { { "dc=com", 0, "dc=com" },
+        { "dc=opends,dc=com", 0, "dc=opends" },
+        { "dc=opends,dc=com", 1, "dc=com" },
+        { "dc=hello,dc=world,dc=opends,dc=com", 0, "dc=hello" },
+        { "dc=hello,dc=world,dc=opends,dc=com", 1, "dc=world" },
+        { "dc=hello,dc=world,dc=opends,dc=com", 2, "dc=opends" },
+        { "dc=hello,dc=world,dc=opends,dc=com", 3, "dc=com" }, };
+  }
+
+
+
+  /**
+   * Subordinate test data provider.
+   *
+   * @return The array of subordinate and superior DN Strings.
+   */
+  @DataProvider(name = "createSubordinateTestData")
+  public Object[][] createSubordinateTestData()
+  {
+    return new Object[][] { { "", "", true }, { "", "dc=org", false },
+        { "", "dc=opends,dc=org", false },
+        { "", "dc=foo,dc=opends,dc=org", false }, { "dc=org", "", true },
+        { "dc=org", "dc=org", true }, { "dc=org", "dc=opends,dc=org", false },
+        { "dc=org", "dc=foo,dc=opends,dc=org", false },
+        { "dc=opends,dc=org", "", true },
+        { "dc=opends,dc=org", "dc=org", true },
+        { "dc=opends,dc=org", "dc=opends,dc=org", true },
+        { "dc=opends,dc=org", "dc=foo,dc=opends,dc=org", false },
+        { "dc=foo,dc=opends,dc=org", "", true },
+        { "dc=foo,dc=opends,dc=org", "dc=org", true },
+        { "dc=foo,dc=opends,dc=org", "dc=opends,dc=org", true },
+        { "dc=foo,dc=opends,dc=org", "dc=foo,dc=opends,dc=org", true },
+        { "dc=org", "dc=com", false },
+        { "dc=opends,dc=org", "dc=foo,dc=org", false },
+        { "dc=opends,dc=org", "dc=opends,dc=com", false }, };
+  }
+
+
+
+  /**
+   * Superior test data provider.
+   *
+   * @return The array of superior and subordindate DN Strings.
+   */
+  @DataProvider(name = "createSuperiorTestData")
+  public Object[][] createSuperiorTestData()
+  {
+    return new Object[][] { { "", "", true }, { "", "dc=org", true },
+        { "", "dc=opends,dc=org", true },
+        { "", "dc=foo,dc=opends,dc=org", true }, { "dc=org", "", false },
+        { "dc=org", "dc=org", true }, { "dc=org", "dc=opends,dc=org", true },
+        { "dc=org", "dc=foo,dc=opends,dc=org", true },
+        { "dc=opends,dc=org", "", false },
+        { "dc=opends,dc=org", "dc=org", false },
+        { "dc=opends,dc=org", "dc=opends,dc=org", true },
+        { "dc=opends,dc=org", "dc=foo,dc=opends,dc=org", true },
+        { "dc=foo,dc=opends,dc=org", "", false },
+        { "dc=foo,dc=opends,dc=org", "dc=org", false },
+        { "dc=foo,dc=opends,dc=org", "dc=opends,dc=org", false },
+        { "dc=foo,dc=opends,dc=org", "dc=foo,dc=opends,dc=org", true },
+        { "dc=org", "dc=com", false },
+        { "dc=opends,dc=org", "dc=foo,dc=org", false },
+        { "dc=opends,dc=org", "dc=opends,dc=com", false }, };
+  }
+
+
+
+  @Test()
+  public void testAdminData()
+  {
+    DN.valueOf("cn=cn\\=admin data");
+    final DN theDN = DN.valueOf("cn=my dn");
+    final RDN theRDN = new RDN("cn", "my rdn");
+    final DN theChildDN = theDN.child(theRDN);
+    DN.valueOf(theChildDN.toString());
+  }
+
+
+
+  /**
+   * Test the child(DN) method.
+   *
+   * @param s
+   *          The test DN string.
+   * @param l
+   *          The local name to be appended.
+   * @param e
+   *          The expected DN.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createChildDNTestData")
+  public void testChildDN(final String s, final String l, final String e)
+      throws Exception
+  {
+    final DN dn = DN.valueOf(s);
+    final DN localName = DN.valueOf(l);
+    final DN expected = DN.valueOf(e);
+
+    assertEquals(dn.child(localName), expected);
+  }
+
+
+
+  /**
+   * Test the child(DN) method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { NullPointerException.class, AssertionError.class })
+  public void testChildDNException() throws Exception
+  {
+    final DN dn = DN.valueOf("dc=org");
+    dn.child((DN) null);
+  }
+
+
+
+  /**
+   * Test the child(DN) method's interaction with other methods.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testChildDNInteraction() throws Exception
+  {
+    final DN p = DN.valueOf("dc=opends,dc=org");
+    final DN l = DN.valueOf("dc=foo");
+    final DN e = DN.valueOf("dc=foo,dc=opends,dc=org");
+    final DN c = p.child(l);
+
+    assertEquals(c.size(), 3);
+
+    assertEquals(c.compareTo(p), 1);
+    assertEquals(p.compareTo(c), -1);
+
+    assertTrue(p.isParentOf(c));
+    assertFalse(c.isParentOf(p));
+
+    assertTrue(c.isChildOf(p));
+    assertFalse(p.isChildOf(c));
+
+    assertEquals(c, e);
+    assertEquals(c.hashCode(), e.hashCode());
+
+    assertEquals(c.toString(), e.toString());
+
+    assertEquals(c.rdn(), RDN.valueOf("dc=foo"));
+
+    assertEquals(c.parent(), DN.valueOf("dc=opends,dc=org"));
+    assertEquals(c.parent(), e.parent());
+
+    assertEquals(c.child(RDN.valueOf("dc=xxx")), DN
+        .valueOf("dc=xxx,dc=foo,dc=opends,dc=org"));
+    assertEquals(c.child(DN.valueOf("dc=xxx,dc=yyy")), DN
+        .valueOf("dc=xxx,dc=yyy,dc=foo,dc=opends,dc=org"));
+  }
+
+
+
+  /**
+   * Test the child(RDN...) method.
+   *
+   * @param s
+   *          The test DN string.
+   * @param r
+   *          The RDN to be appended.
+   * @param e
+   *          The expected DN.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createChildRDNTestData")
+  public void testChildSingleRDN(final String s, final String r, final String e)
+      throws Exception
+  {
+    final DN dn = DN.valueOf(s);
+    final RDN rdn = RDN.valueOf(r);
+    final DN expected = DN.valueOf(e);
+
+    assertEquals(dn.child(rdn), expected);
+  }
+
+
+
+  /**
+   * Test DN compareTo
+   *
+   * @param first
+   *          First DN to compare.
+   * @param second
+   *          Second DN to compare.
+   * @param result
+   *          Expected comparison result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createDNComparisonData")
+  public void testCompareTo(final String first, final String second,
+      final int result) throws Exception
+  {
+    final DN dn1 = DN.valueOf(first);
+    final DN dn2 = DN.valueOf(second);
+
+    int rc = dn1.compareTo(dn2);
+
+    // Normalize the result.
+    if (rc < 0)
+    {
+      rc = -1;
+    }
+    else if (rc > 0)
+    {
+      rc = 1;
+    }
+
+    assertEquals(rc, result, "Comparison for <" + first + "> and <" + second
+        + ">.");
+  }
+
+
+
+  /**
+   * Test DN equality
+   *
+   * @param first
+   *          First DN to compare.
+   * @param second
+   *          Second DN to compare.
+   * @param result
+   *          Expected comparison result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createDNEqualityData")
+  public void testEquality(final String first, final String second,
+      final int result) throws Exception
+  {
+    final DN dn1 = DN.valueOf(first);
+    final DN dn2 = DN.valueOf(second);
+
+    if (result == 0)
+    {
+      assertTrue(dn1.equals(dn2), "DN equality for <" + first + "> and <"
+          + second + ">");
+    }
+    else
+    {
+      assertFalse(dn1.equals(dn2), "DN equality for <" + first + "> and <"
+          + second + ">");
+    }
+  }
+
+
+
+  /**
+   * Tests the equals method with a value that's not a DN.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+  public void testEqualsNonDN() throws Exception
+  {
+    final DN dn = DN.valueOf("dc=example,dc=com");
+
+    assertFalse(dn.equals(DN.valueOf("not a DN")));
+  }
+
+
+
+  /**
+   * Test DN hashCode
+   *
+   * @param first
+   *          First DN to compare.
+   * @param second
+   *          Second DN to compare.
+   * @param result
+   *          Expected comparison result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createDNEqualityData")
+  public void testHashCode(final String first, final String second,
+      final int result) throws Exception
+  {
+    final DN dn1 = DN.valueOf(first);
+    final DN dn2 = DN.valueOf(second);
+
+    final int h1 = dn1.hashCode();
+    final int h2 = dn2.hashCode();
+
+    if (result == 0)
+    {
+      if (h1 != h2)
+      {
+        fail("Hash codes for <" + first + "> and <" + second
+            + "> should be the same.");
+      }
+    }
+    else
+    {
+      if (h1 == h2)
+      {
+        fail("Hash codes for <" + first + "> and <" + second
+            + "> should be the same.");
+      }
+    }
+  }
+
+
+
+  /**
+   * Test that decoding an illegal DN as a String throws an exception.
+   *
+   * @param dn
+   *          The illegal DN to be tested.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "illegalDNs", expectedExceptions = {
+      StringIndexOutOfBoundsException.class,
+      LocalizedIllegalArgumentException.class, NullPointerException.class })
+  public void testIllegalStringDNs(final String dn) throws Exception
+  {
+    DN.valueOf(dn);
+  }
+
+
+
+  /**
+   * Test the isChildOf method.
+   *
+   * @param s
+   *          The test DN string.
+   * @param d
+   *          The dn parameter.
+   * @param e
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createIsChildOfTestData")
+  public void testIsChildOf(final String s, final String d, final boolean e)
+      throws Exception
+  {
+    final DN dn = DN.valueOf(s);
+    final DN other = DN.valueOf(d);
+
+    assertEquals(dn.isChildOf(other), e, s + " isChildOf " + d);
+  }
+
+
+
+  /**
+   * Test the isChildOf method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { NullPointerException.class, AssertionError.class })
+  public void testIsChildOfException() throws Exception
+  {
+    final DN dn = DN.valueOf("dc=com");
+    dn.isChildOf((String) null);
+  }
+
+
+
+  /**
+   * Tests the parent method that require iteration.
+   */
+  @Test()
+  public void testIterableParent()
+  {
+    final String str = "ou=people,dc=example,dc=com";
+    final DN dn = DN.valueOf(str);
+    // Parent at index 0 is self.
+    assertEquals(dn, dn.parent(0));
+    assertEquals(dn.parent(1), DN.valueOf("dc=example,dc=com"));
+    assertEquals(dn.parent(2), DN.valueOf("dc=com"));
+    assertEquals(dn.parent(3), DN.rootDN());
+  }
+
+
+
+  /**
+   * Test the getNumComponents method.
+   *
+   * @param s
+   *          The test DN string.
+   * @param sz
+   *          The expected number of RDNs.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createNumComponentsTestData")
+  public void testNumComponents(final String s, final int sz) throws Exception
+  {
+    final DN dn = DN.valueOf(s);
+    assertEquals(dn.size(), sz);
+  }
+
+
+
+  /**
+   * Test the parent method.
+   *
+   * @param s
+   *          The test DN string.
+   * @param p
+   *          The expected parent.
+   * @param r
+   *          The expected rdn.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createParentAndRDNTestData")
+  public void testParent(final String s, final String p, final String r)
+      throws Exception
+  {
+    final DN dn = DN.valueOf(s);
+    final DN parent = (p != null ? DN.valueOf(p) : null);
+
+    assertEquals(dn.parent(), parent, "For DN " + s);
+  }
+
+
+
+  /**
+   * Test the parent method's interaction with other methods.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testParentInteraction() throws Exception
+  {
+    final DN c = DN.valueOf("dc=foo,dc=bar,dc=opends,dc=org");
+    final DN e = DN.valueOf("dc=bar,dc=opends,dc=org");
+    final DN p = c.parent();
+
+    assertEquals(p.size(), 3);
+
+    assertEquals(p.compareTo(c), -1);
+    assertEquals(c.compareTo(p), 1);
+
+    assertTrue(p.isParentOf(c));
+    assertFalse(c.isParentOf(p));
+
+    assertTrue(c.isChildOf(p));
+    assertFalse(p.isChildOf(c));
+
+    assertEquals(p, e);
+    assertEquals(p.hashCode(), e.hashCode());
+
+    assertEquals(p.toString(), e.toString());
+
+    assertEquals(p.rdn(), RDN.valueOf("dc=bar"));
+
+    assertEquals(p.rdn(), RDN.valueOf("dc=bar"));
+
+    assertEquals(p.parent(), DN.valueOf("dc=opends,dc=org"));
+    assertEquals(p.parent(), e.parent());
+
+    assertEquals(p.child(RDN.valueOf("dc=foo")), DN
+        .valueOf("dc=foo,dc=bar,dc=opends,dc=org"));
+    assertEquals(p.child(RDN.valueOf("dc=foo")), c);
+    assertEquals(p.child(DN.valueOf("dc=xxx,dc=foo")), DN
+        .valueOf("dc=xxx,dc=foo,dc=bar,dc=opends,dc=org"));
+  }
+
+
+
+  /**
+   * Test the getRDN method.
+   *
+   * @param s
+   *          The test DN string.
+   * @param p
+   *          The expected parent.
+   * @param r
+   *          The expected rdn.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createParentAndRDNTestData")
+  public void testRDN(final String s, final String p, final String r)
+      throws Exception
+  {
+    final DN dn = DN.valueOf(s);
+    final RDN rdn = (r != null ? RDN.valueOf(r) : null);
+
+    assertEquals(dn.rdn(), rdn, "For DN " + s);
+  }
+
+
+
+  /**
+   * Tests the root DN.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testRootDN1() throws Exception
+  {
+    final DN dn = DN.valueOf("");
+    assertTrue(dn.isRootDN());
+    assertEquals(dn, DN.rootDN());
+  }
+
+
+
+  /**
+   * Tests the root DN.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { NullPointerException.class, AssertionError.class })
+  public void testRootDN2() throws Exception
+  {
+    final DN dn = DN.valueOf(null);
+    assertEquals(dn, DN.rootDN());
+  }
+
+
+
+  /**
+   * Test the root dn.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testRootDN3() throws Exception
+  {
+    final DN nullDN = DN.rootDN();
+    assertTrue(nullDN.isRootDN());
+    assertTrue(nullDN.size() == 0);
+  }
+
+
+
+  /**
+   * Test the root dn.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testRootDN4() throws Exception
+  {
+    final DN dn = DN.valueOf("dc=com");
+    assertFalse(dn.isRootDN());
+  }
+
+
+
+  /**
+   * Tests the subordinate dns.
+   */
+  @Test(dataProvider = "createSubordinateTestData")
+  public void testSubordinateDN(final String sub, final String base,
+      final boolean e) throws Exception
+  {
+    final DN dn = DN.valueOf(sub);
+    final DN other = DN.valueOf(base);
+    assertEquals(dn.isSubordinateOrEqualTo(other), e, sub + " isSubordinateOf "
+        + base);
+  }
+
+
+
+  /**
+   * Tests the supeiror dns.
+   */
+  @Test(dataProvider = "createSuperiorTestData")
+  public void testSuperiorDN(final String base, final String sub,
+      final boolean e) throws Exception
+  {
+    final DN dn = DN.valueOf(base);
+    final DN other = DN.valueOf(sub);
+    assertEquals(dn.isSuperiorOrEqualTo(other), e, base + " isSuperiorOf "
+        + sub);
+  }
+
+
+
+  /**
+   * Test the RFC 4514 string representation of the DN.
+   *
+   * @param rawDN
+   *          Raw DN string representation.
+   * @param normDN
+   *          Normalized DN string representation.
+   * @param stringDN
+   *          String representation.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "testDNs")
+  public void testToString(final String rawDN, final String normDN,
+      final String stringDN) throws Exception
+  {
+    // DN dn = DN.valueOf(rawDN);
+    // assertEquals(dn.toString(), stringDN);
+  }
+
+
+
+  /**
+   * Tests the <CODE>valueOf</CODE> method which takes a String argument.
+   *
+   * @param rawDN
+   *          Raw DN string representation.
+   * @param normDN
+   *          Normalized DN string representation.
+   * @param stringDN
+   *          String representation.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "testDNs")
+  public void testValueOfString(final String rawDN, final String normDN,
+      final String stringDN) throws Exception
+  {
+    final DN raw = DN.valueOf(rawDN);
+    final DN string = DN.valueOf(stringDN);
+    assertEquals(raw, string);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntriesTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntriesTestCase.java
new file mode 100644
index 0000000..8b0ee61
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntriesTestCase.java
@@ -0,0 +1,229 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Iterator;
+
+import org.opends.sdk.requests.ModifyRequest;
+import org.opends.sdk.requests.Requests;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test {@code Entries}.
+ */
+public final class EntriesTestCase extends SdkTestCase
+{
+  /**
+   * Creates test data for {@link #testDiffEntries}.
+   *
+   * @return The test data.
+   */
+  @DataProvider(name = "createTestDiffEntriesData")
+  public Object[][] createTestDiffEntriesData()
+  {
+    // @formatter:off
+    Entry empty = new LinkedHashMapEntry(
+        "dn: cn=test",
+        "objectClass: top",
+        "objectClass: test"
+    );
+
+    Entry from = new LinkedHashMapEntry(
+        "dn: cn=test",
+        "objectClass: top",
+        "objectClass: test",
+        "fromOnly: fromOnlyValue",
+        "bothSame: one",
+        "bothSame: two",
+        "bothSame: three",
+        "bothDifferentDeletes: common",
+        "bothDifferentDeletes: fromOnly1",
+        "bothDifferentDeletes: fromOnly2",
+        "bothDifferentAdds: common",
+        "bothDifferentAddsAndDeletes: common",
+        "bothDifferentAddsAndDeletes: fromOnly",
+        "bothDifferentReplace: fromOnly1",
+        "bothDifferentReplace: fromOnly2"
+    );
+
+    Entry to = new LinkedHashMapEntry(
+        "dn: cn=test",
+        "objectClass: top",
+        "objectClass: test",
+        "toOnly: toOnlyValue",
+        "bothSame: one",
+        "bothSame: two",
+        "bothSame: three",
+        "bothDifferentDeletes: common",
+        "bothDifferentAdds: common",
+        "bothDifferentAdds: toOnly1",
+        "bothDifferentAdds: toOnly2",
+        "bothDifferentAddsAndDeletes: common",
+        "bothDifferentAddsAndDeletes: toOnly",
+        "bothDifferentReplace: toOnly1",
+        "bothDifferentReplace: toOnly2"
+    );
+
+    ModifyRequest diffFromEmpty = Requests.newModifyRequest(
+        "dn: cn=test",
+        "changetype: modify",
+        "delete: bothDifferentAdds",
+        "bothDifferentAdds: common",
+        "-",
+        "delete: bothDifferentAddsAndDeletes",
+        "bothDifferentAddsAndDeletes: common",
+        "bothDifferentAddsAndDeletes: fromOnly",
+        "-",
+        "delete: bothDifferentDeletes",
+        "bothDifferentDeletes: common",
+        "bothDifferentDeletes: fromOnly1",
+        "bothDifferentDeletes: fromOnly2",
+        "-",
+        "delete: bothDifferentReplace",
+        "bothDifferentReplace: fromOnly1",
+        "bothDifferentReplace: fromOnly2",
+        "-",
+        "delete: bothSame",
+        "bothSame: one",
+        "bothSame: two",
+        "bothSame: three",
+        "-",
+        "delete: fromOnly",
+        "fromOnly: fromOnlyValue"
+    );
+
+    ModifyRequest diffEmptyTo = Requests.newModifyRequest(
+        "dn: cn=test",
+        "changetype: modify",
+        "add: bothDifferentAdds",
+        "bothDifferentAdds: common",
+        "bothDifferentAdds: toOnly1",
+        "bothDifferentAdds: toOnly2",
+        "-",
+        "add: bothDifferentAddsAndDeletes",
+        "bothDifferentAddsAndDeletes: common",
+        "bothDifferentAddsAndDeletes: toOnly",
+        "-",
+        "add: bothDifferentDeletes",
+        "bothDifferentDeletes: common",
+        "-",
+        "add: bothDifferentReplace",
+        "bothDifferentReplace: toOnly1",
+        "bothDifferentReplace: toOnly2",
+        "-",
+        "add: bothSame",
+        "bothSame: one",
+        "bothSame: two",
+        "bothSame: three",
+        "-",
+        "add: toOnly",
+        "toOnly: toOnlyValue"
+    );
+
+    ModifyRequest diffFromTo = Requests.newModifyRequest(
+        "dn: cn=test",
+        "changetype: modify",
+        "add: bothDifferentAdds",
+        "bothDifferentAdds: toOnly1",
+        "bothDifferentAdds: toOnly2",
+        "-",
+        "add: bothDifferentAddsAndDeletes",
+        "bothDifferentAddsAndDeletes: toOnly",
+        "-",
+        "delete: bothDifferentAddsAndDeletes",
+        "bothDifferentAddsAndDeletes: fromOnly",
+        "-",
+        "delete: bothDifferentDeletes",
+        "bothDifferentDeletes: fromOnly1",
+        "bothDifferentDeletes: fromOnly2",
+        "-",
+        "add: bothDifferentReplace",
+        "bothDifferentReplace: toOnly1",
+        "bothDifferentReplace: toOnly2",
+        "-",
+        "delete: bothDifferentReplace",
+        "bothDifferentReplace: fromOnly1",
+        "bothDifferentReplace: fromOnly2",
+        "-",
+        "delete: fromOnly",
+        "fromOnly: fromOnlyValue",
+        "-",
+        "add: toOnly",
+        "toOnly: toOnlyValue"
+    );
+
+    // From, to, diff.
+    return new Object[][]
+    {
+      { from,  empty, diffFromEmpty },
+      { empty, to,    diffEmptyTo   },
+      { from,  to,    diffFromTo    }
+    };
+
+    // @formatter:on
+  }
+
+
+
+  /**
+   * Tests {@link Entries#diffEntries(Entry, Entry)}.
+   *
+   * @param from
+   *          Source entry.
+   * @param to
+   *          Destination entry.
+   * @param expected
+   *          Expected modifications.
+   */
+  @Test(dataProvider = "createTestDiffEntriesData")
+  public void testDiffEntries(final Entry from, final Entry to,
+      final ModifyRequest expected)
+  {
+    ModifyRequest actual = Entries.diffEntries(from, to);
+
+    Assert.assertEquals(from.getName(), actual.getName());
+    Assert.assertEquals(actual.getModifications().size(), expected
+        .getModifications().size());
+    Iterator<Modification> i1 = actual.getModifications().iterator();
+    Iterator<Modification> i2 = expected.getModifications().iterator();
+    while (i1.hasNext())
+    {
+      Modification m1 = i1.next();
+      Modification m2 = i2.next();
+
+      Assert.assertEquals(m1.getModificationType(), m2.getModificationType());
+      Assert.assertEquals(m1.getAttribute(), m2.getAttribute());
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntryTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntryTestCase.java
new file mode 100644
index 0000000..f1297e0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/EntryTestCase.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test {@code Entry}.
+ */
+public final class EntryTestCase extends SdkTestCase
+{
+  private static interface EntryFactory
+  {
+    Entry newEntry(String... ldifLines);
+  }
+
+
+
+  private static final class LinkedHashMapEntryFactory implements EntryFactory
+  {
+    public Entry newEntry(final String... ldifLines)
+    {
+      return new LinkedHashMapEntry(ldifLines);
+    }
+  }
+
+
+
+  private static final class TreeMapEntryFactory implements EntryFactory
+  {
+    public Entry newEntry(final String... ldifLines)
+    {
+      return new TreeMapEntry(ldifLines);
+    }
+  }
+
+
+
+  @DataProvider(name = "EntryFactory")
+  public Object[][] entryFactory()
+  {
+    // Value, type, options, containsOptions("foo")
+    return new Object[][] { { new TreeMapEntryFactory() },
+        { new LinkedHashMapEntryFactory() } };
+  }
+
+
+
+  @Test(dataProvider = "EntryFactory")
+  public void smokeTest(final EntryFactory factory) throws Exception
+  {
+    final Entry entry1 = factory.newEntry(
+        "dn: cn=Joe Bloggs,dc=example,dc=com", "objectClass: top",
+        "objectClass: person", "cn: Joe Bloggs", "sn: Bloggs",
+        "givenName: Joe", "description: A description");
+
+    final Entry entry2 = factory.newEntry(
+        "dn: cn=Joe Bloggs,dc=example,dc=com", "changetype: add",
+        "objectClass: top", "objectClass: person", "cn: Joe Bloggs",
+        "sn: Bloggs", "givenName: Joe", "description: A description");
+
+    Assert.assertEquals(entry1, entry2);
+
+    for (final Entry e : new Entry[] { entry1, entry2 })
+    {
+      Assert.assertEquals(e.getName(), DN
+          .valueOf("cn=Joe Bloggs,dc=example,dc=com"));
+      Assert.assertEquals(e.getAttributeCount(), 5);
+
+      Assert.assertEquals(e.getAttribute("objectClass").size(), 2);
+      Assert.assertTrue(e.containsAttribute("objectClass", "top", "person"));
+      Assert.assertFalse(e.containsAttribute("objectClass", "top", "person",
+          "foo"));
+
+      Assert.assertTrue(e.containsAttribute("objectClass"));
+      Assert.assertTrue(e.containsAttribute("cn"));
+      Assert.assertTrue(e.containsAttribute("cn", "Joe Bloggs"));
+      Assert.assertFalse(e.containsAttribute("cn", "Jane Bloggs"));
+      Assert.assertTrue(e.containsAttribute("sn"));
+      Assert.assertTrue(e.containsAttribute("givenName"));
+      Assert.assertTrue(e.containsAttribute("description"));
+
+      Assert.assertEquals(e.getAttribute("cn").firstValueAsString(),
+          "Joe Bloggs");
+      Assert.assertEquals(e.getAttribute("sn").firstValueAsString(), "Bloggs");
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/FilterTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/FilterTestCase.java
new file mode 100644
index 0000000..224b370
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/FilterTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+public class FilterTestCase extends SdkTestCase
+{
+  @DataProvider(name = "badfilterstrings")
+  public Object[][] getBadFilterStrings() throws Exception
+  {
+    return new Object[][] { { null, null }, { "", null }, { "=", null },
+        { "()", null }, { "(&(objectClass=*)(sn=s*s)", null },
+        { "(dob>12221)", null }, { "(cn=bob\\2 doe)", null },
+        { "(cn=\\4j\\w2\\yu)", null }, { "(cn=ds\\2)", null },
+        { "(&(givenname=bob)|(sn=pep)dob=12))", null }, { "(:=bob)", null },
+        { "(=sally)", null }, { "(cn=billy bob", null },
+        { "(|(!(title=sweep*)(l=Paris*)))", null }, { "(|(!))", null },
+        { "((uid=user.0))", null }, { "(&&(uid=user.0))", null },
+        { "!uid=user.0", null }, { "(:dn:=Sally)", null }, };
+  }
+
+
+
+  @DataProvider(name = "filterstrings")
+  public Object[][] getFilterStrings() throws Exception
+  {
+    final Filter equal = Filter.newEqualityMatchFilter("objectClass",
+        ByteString.valueOf("\\test*(Value)"));
+    final Filter equal2 = Filter.newEqualityMatchFilter("objectClass",
+        ByteString.valueOf(""));
+    final Filter approx = Filter.newApproxMatchFilter("sn", ByteString
+        .valueOf("\\test*(Value)"));
+    final Filter greater = Filter.newGreaterOrEqualFilter("employeeNumber",
+        ByteString.valueOf("\\test*(Value)"));
+    final Filter less = Filter.newLessOrEqualFilter("dob", ByteString
+        .valueOf("\\test*(Value)"));
+    final Filter presense = Filter.newPresentFilter("login");
+
+    final ArrayList<ByteString> any = new ArrayList<ByteString>(0);
+    final ArrayList<ByteString> multiAny = new ArrayList<ByteString>(1);
+    multiAny.add(ByteString.valueOf("\\wid*(get)"));
+    multiAny.add(ByteString.valueOf("*"));
+
+    final Filter substring1 = Filter.newSubstringsFilter("givenName",
+        ByteString.valueOf("\\Jo*()"), any, ByteString.valueOf("\\n*()"));
+    final Filter substring2 = Filter.newSubstringsFilter("givenName",
+        ByteString.valueOf("\\Jo*()"), multiAny, ByteString.valueOf("\\n*()"));
+    final Filter substring3 = Filter.newSubstringsFilter("givenName",
+        ByteString.valueOf(""), any, ByteString.valueOf("\\n*()"));
+    final Filter substring4 = Filter.newSubstringsFilter("givenName",
+        ByteString.valueOf("\\Jo*()"), any, ByteString.valueOf(""));
+    final Filter substring5 = Filter.newSubstringsFilter("givenName",
+        ByteString.valueOf(""), multiAny, ByteString.valueOf(""));
+    final Filter extensible1 = Filter.newExtensibleMatchFilter("2.4.6.8.19",
+        "cn", ByteString.valueOf("\\John* (Doe)"), false);
+    final Filter extensible2 = Filter.newExtensibleMatchFilter("2.4.6.8.19",
+        "cn", ByteString.valueOf("\\John* (Doe)"), true);
+    final Filter extensible3 = Filter.newExtensibleMatchFilter("2.4.6.8.19",
+        null, ByteString.valueOf("\\John* (Doe)"), true);
+    final Filter extensible4 = Filter.newExtensibleMatchFilter(null, "cn",
+        ByteString.valueOf("\\John* (Doe)"), true);
+    final Filter extensible5 = Filter.newExtensibleMatchFilter("2.4.6.8.19",
+        null, ByteString.valueOf("\\John* (Doe)"), false);
+
+    final ArrayList<Filter> list1 = new ArrayList<Filter>();
+    list1.add(equal);
+    list1.add(approx);
+
+    final Filter and = Filter.newAndFilter(list1);
+
+    final ArrayList<Filter> list2 = new ArrayList<Filter>();
+    list2.add(substring1);
+    list2.add(extensible1);
+    list2.add(and);
+
+    return new Object[][] {
+        { "(objectClass=\\5ctest\\2a\\28Value\\29)", equal },
+
+        { "(objectClass=)", equal2 },
+
+        { "(sn~=\\5ctest\\2a\\28Value\\29)", approx },
+
+        { "(employeeNumber>=\\5ctest\\2a\\28Value\\29)", greater },
+
+        { "(dob<=\\5ctest\\2a\\28Value\\29)", less },
+
+        { "(login=*)", presense },
+
+        { "(givenName=\\5cJo\\2a\\28\\29*\\5cn\\2a\\28\\29)", substring1 },
+
+        {
+            "(givenName=\\5cJo\\2a\\28\\29*\\5cwid\\2a\\28get\\29*\\2a*\\5cn\\2a\\28\\29)",
+            substring2 },
+
+        { "(givenName=*\\5cn\\2a\\28\\29)", substring3 },
+
+        { "(givenName=\\5cJo\\2a\\28\\29*)", substring4 },
+
+        { "(givenName=*\\5cwid\\2a\\28get\\29*\\2a*)", substring5 },
+
+        { "(cn:2.4.6.8.19:=\\5cJohn\\2a \\28Doe\\29)", extensible1 },
+
+        { "(cn:dn:2.4.6.8.19:=\\5cJohn\\2a \\28Doe\\29)", extensible2 },
+
+        { "(:dn:2.4.6.8.19:=\\5cJohn\\2a \\28Doe\\29)", extensible3 },
+
+        { "(cn:dn:=\\5cJohn\\2a \\28Doe\\29)", extensible4 },
+
+        { "(:2.4.6.8.19:=\\5cJohn\\2a \\28Doe\\29)", extensible5 },
+
+        {
+            "(&(objectClass=\\5ctest\\2a\\28Value\\29)(sn~=\\5ctest\\2a\\28Value\\29))",
+            Filter.newAndFilter(list1) },
+
+        {
+            "(|(objectClass=\\5ctest\\2a\\28Value\\29)(sn~=\\5ctest\\2a\\28Value\\29))",
+            Filter.newOrFilter(list1) },
+
+        { "(!(objectClass=\\5ctest\\2a\\28Value\\29))",
+            Filter.newNotFilter(equal) },
+
+        {
+            "(|(givenName=\\5cJo\\2a\\28\\29*\\5cn\\2a\\28\\29)(cn:2.4.6.8.19:=\\5cJohn\\2a \\28Doe\\29)"
+                + "(&(objectClass=\\5ctest\\2a\\28Value\\29)(sn~=\\5ctest\\2a\\28Value\\29)))",
+            Filter.newOrFilter(list2) }
+
+    };
+  }
+
+
+
+  /**
+   * Decodes the specified filter strings.
+   *
+   * @param filterStr
+   * @param filter
+   * @throws Exception
+   */
+  @Test(dataProvider = "filterstrings")
+  public void testDecode(final String filterStr, final Filter filter)
+      throws Exception
+  {
+    final Filter decoded = Filter.valueOf(filterStr);
+    assertEquals(decoded.toString(), filter.toString());
+  }
+
+
+
+  /**
+   * Decodes the erroneous filter strings.
+   *
+   * @param filterStr
+   * @param filter
+   * @throws Exception
+   */
+  @Test(dataProvider = "badfilterstrings", expectedExceptions = {
+      LocalizedIllegalArgumentException.class, NullPointerException.class })
+  public void testDecodeException(final String filterStr, final Filter filter)
+      throws Exception
+  {
+    Filter.valueOf(filterStr);
+  }
+
+
+
+  /**
+   * Tests the matcher.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testMatcher() throws Exception
+  {
+    final Filter equal = Filter.newEqualityMatchFilter("cn", ByteString
+        .valueOf("\\test*(Value)"));
+    final LinkedHashMapEntry entry = new LinkedHashMapEntry(DN
+        .valueOf("cn=\\test*(Value),dc=org"));
+    entry.addAttribute("cn", "\\test*(Value)");
+    entry.addAttribute("objectclass", "top,person");
+    final Matcher matcher = equal.matcher();
+    assertTrue(matcher.matches(entry).toBoolean());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPListenerTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPListenerTestCase.java
new file mode 100644
index 0000000..34998fb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPListenerTestCase.java
@@ -0,0 +1,1062 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * Tests the LDAPListener class.
+ */
+public class LDAPListenerTestCase extends SdkTestCase
+{
+
+  private static class MockConnectionEventListener implements
+      ConnectionEventListener
+  {
+    final CountDownLatch closeLatch = new CountDownLatch(1);
+    String errorMessage = null;
+
+
+
+    @Override
+    public void handleConnectionClosed()
+    {
+      errorMessage = "Unexpected call to handleConnectionClosed";
+      closeLatch.countDown();
+    }
+
+
+
+    @Override
+    public void handleConnectionError(final boolean isDisconnectNotification,
+        final ErrorResultException error)
+    {
+      errorMessage = "Unexpected call to handleConnectionError";
+      closeLatch.countDown();
+    }
+
+
+
+    @Override
+    public void handleUnsolicitedNotification(final ExtendedResult notification)
+    {
+      errorMessage = "Unexpected call to handleUnsolicitedNotification";
+      closeLatch.countDown();
+    }
+  }
+
+
+
+  private static class MockServerConnection implements
+      ServerConnection<Integer>
+  {
+    volatile LDAPClientContext context = null;
+    final CountDownLatch isConnected = new CountDownLatch(1);
+    final CountDownLatch isClosed = new CountDownLatch(1);
+
+
+
+    MockServerConnection()
+    {
+      // Do nothing.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleAbandon(final Integer requestContext,
+        final AbandonRequest request) throws UnsupportedOperationException
+    {
+      // Do nothing.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleAdd(final Integer requestContext,
+        final AddRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleBind(final Integer requestContext, final int version,
+        final BindRequest request,
+        final ResultHandler<? super BindResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleCompare(final Integer requestContext,
+        final CompareRequest request,
+        final ResultHandler<? super CompareResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler
+          .handleResult(Responses.newCompareResult(ResultCode.SUCCESS));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleConnectionClosed(final Integer requestContext,
+        final UnbindRequest request)
+    {
+      isClosed.countDown();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleConnectionDisconnected(final ResultCode resultCode,
+        final String message)
+    {
+      // Do nothing.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleConnectionError(final Throwable error)
+    {
+      // Do nothing.
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleDelete(final Integer requestContext,
+        final DeleteRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <R extends ExtendedResult> void handleExtendedRequest(
+        final Integer requestContext, final ExtendedRequest<R> request,
+        final ResultHandler<? super R> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler
+          .handleErrorResult(ErrorResultException.wrap(request
+              .getResultDecoder().newExtendedErrorResult(
+                  ResultCode.PROTOCOL_ERROR, "",
+                  "Extended operation " + request.getOID() + " not supported")));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleModify(final Integer requestContext,
+        final ModifyRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleModifyDN(final Integer requestContext,
+        final ModifyDNRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleSearch(final Integer requestContext,
+        final SearchRequest request, final SearchResultHandler resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
+    }
+
+  }
+
+
+
+  private static class MockServerConnectionFactory implements
+      ServerConnectionFactory<LDAPClientContext, Integer>
+  {
+
+    private final MockServerConnection serverConnection;
+
+
+
+    private MockServerConnectionFactory(
+        final MockServerConnection serverConnection)
+    {
+      this.serverConnection = serverConnection;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ServerConnection<Integer> handleAccept(
+        final LDAPClientContext clientContext) throws ErrorResultException
+    {
+      serverConnection.context = clientContext;
+      serverConnection.isConnected.countDown();
+      return serverConnection;
+    }
+  }
+
+
+
+  /**
+   * Disables logging before the tests.
+   */
+  @BeforeClass()
+  public void disableLogging()
+  {
+    StaticUtils.DEBUG_LOG.setLevel(Level.SEVERE);
+  }
+
+
+
+  /**
+   * Re-enable logging after the tests.
+   */
+  @AfterClass()
+  public void enableLogging()
+  {
+    StaticUtils.DEBUG_LOG.setLevel(Level.INFO);
+  }
+
+
+
+  /**
+   * Tests connection event listener.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testConnectionEventListenerClose() throws Exception
+  {
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), onlineServerConnectionFactory);
+
+    final Connection connection;
+    try
+    {
+      // Connect and bind.
+      connection = new LDAPConnectionFactory(
+          onlineServerListener.getSocketAddress()).getConnection();
+
+      final MockConnectionEventListener listener = new MockConnectionEventListener()
+      {
+
+        @Override
+        public void handleConnectionClosed()
+        {
+          closeLatch.countDown();
+        }
+      };
+
+      connection.addConnectionEventListener(listener);
+      Assert.assertEquals(listener.closeLatch.getCount(), 1);
+      connection.close();
+      listener.closeLatch.await();
+      Assert.assertNull(listener.errorMessage);
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests connection event listener.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testConnectionEventListenerDisconnect() throws Exception
+  {
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), onlineServerConnectionFactory);
+
+    final Connection connection;
+    try
+    {
+      // Connect and bind.
+      connection = new LDAPConnectionFactory(
+          onlineServerListener.getSocketAddress()).getConnection();
+
+      final MockConnectionEventListener listener = new MockConnectionEventListener()
+      {
+
+        @Override
+        public void handleConnectionError(
+            final boolean isDisconnectNotification,
+            final ErrorResultException error)
+        {
+          if (isDisconnectNotification)
+          {
+            errorMessage = "Unexpected disconnect notification";
+          }
+          closeLatch.countDown();
+        }
+      };
+
+      connection.addConnectionEventListener(listener);
+      Assert.assertEquals(listener.closeLatch.getCount(), 1);
+      Assert.assertTrue(onlineServerConnection.isConnected
+          .await(10, TimeUnit.SECONDS));
+      onlineServerConnection.context.disconnect();
+      listener.closeLatch.await();
+      Assert.assertNull(listener.errorMessage);
+      connection.close();
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests connection event listener.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testConnectionEventListenerDisconnectNotification()
+      throws Exception
+  {
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), onlineServerConnectionFactory);
+
+    final Connection connection;
+    try
+    {
+      // Connect and bind.
+      connection = new LDAPConnectionFactory(
+          onlineServerListener.getSocketAddress()).getConnection();
+
+      final MockConnectionEventListener listener = new MockConnectionEventListener()
+      {
+
+        @Override
+        public void handleConnectionError(
+            final boolean isDisconnectNotification,
+            final ErrorResultException error)
+        {
+          if (!isDisconnectNotification
+              || !error.getResult().getResultCode().equals(ResultCode.BUSY)
+              || !error.getResult().getDiagnosticMessage().equals("test"))
+          {
+            errorMessage = "Missing disconnect notification: " + error;
+          }
+          closeLatch.countDown();
+        }
+      };
+
+      connection.addConnectionEventListener(listener);
+      Assert.assertEquals(listener.closeLatch.getCount(), 1);
+      Assert.assertTrue(onlineServerConnection.isConnected
+          .await(10, TimeUnit.SECONDS));
+      onlineServerConnection.context.disconnect(ResultCode.BUSY, "test");
+      listener.closeLatch.await();
+      Assert.assertNull(listener.errorMessage);
+      connection.close();
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests connection event listener.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testConnectionEventListenerUnbind() throws Exception
+  {
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), onlineServerConnectionFactory);
+
+    final Connection connection;
+    try
+    {
+      // Connect and bind.
+      connection = new LDAPConnectionFactory(
+          onlineServerListener.getSocketAddress()).getConnection();
+
+      final MockConnectionEventListener listener = new MockConnectionEventListener()
+      {
+
+        @Override
+        public void handleConnectionClosed()
+        {
+          closeLatch.countDown();
+        }
+      };
+
+      connection.addConnectionEventListener(listener);
+      Assert.assertEquals(listener.closeLatch.getCount(), 1);
+      connection.close(Requests.newUnbindRequest(), "called from unit test");
+      listener.closeLatch.await();
+      Assert.assertNull(listener.errorMessage);
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests basic LDAP listener functionality.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testLDAPListenerBasic() throws Exception
+  {
+    final MockServerConnection serverConnection = new MockServerConnection();
+    final MockServerConnectionFactory serverConnectionFactory = new MockServerConnectionFactory(
+        serverConnection);
+    final LDAPListener listener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), serverConnectionFactory);
+    try
+    {
+      // Connect and close.
+      final Connection connection = new LDAPConnectionFactory(
+          listener.getSocketAddress()).getConnection();
+
+      Assert.assertTrue(serverConnection.isConnected
+          .await(10, TimeUnit.SECONDS));
+      Assert.assertEquals(serverConnection.isClosed.getCount(), 1);
+
+      connection.close();
+
+      Assert.assertTrue(serverConnection.isClosed.await(10, TimeUnit.SECONDS));
+    }
+    finally
+    {
+      listener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests LDAP listener which attempts to open a connection to a remote offline
+   * server at the point when the listener accepts the client connection.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = false)
+  public void testLDAPListenerLoadBalanceDuringHandleAccept() throws Exception
+  {
+    // Online server listener.
+    final int onlineServerPort = TestCaseUtils.findFreePort();
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        onlineServerPort, onlineServerConnectionFactory);
+
+    try
+    {
+      // Connection pool and load balancing tests.
+      final ConnectionFactory offlineServer1 = Connections
+          .newNamedConnectionFactory(new LDAPConnectionFactory("localhost",
+              TestCaseUtils.findFreePort()), "offline1");
+      final ConnectionFactory offlineServer2 = Connections
+          .newNamedConnectionFactory(new LDAPConnectionFactory("localhost",
+              TestCaseUtils.findFreePort()), "offline2");
+      final ConnectionFactory onlineServer = Connections
+          .newNamedConnectionFactory(new LDAPConnectionFactory("localhost",
+              onlineServerPort), "online");
+
+      // Round robin.
+      final ConnectionFactory loadBalancer = Connections
+          .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
+              Connections.newConnectionPool(offlineServer1, 10),
+              Connections.newConnectionPool(offlineServer2, 10),
+              Connections.newConnectionPool(onlineServer, 10))));
+
+      final MockServerConnection proxyServerConnection = new MockServerConnection();
+      final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory(
+          proxyServerConnection)
+      {
+
+        @Override
+        public ServerConnection<Integer> handleAccept(
+            final LDAPClientContext clientContext) throws ErrorResultException
+        {
+          // Get connection from load balancer, this should fail over twice
+          // before getting connection to online server.
+          try
+          {
+            loadBalancer.getConnection().close();
+          }
+          catch (final InterruptedException e)
+          {
+            // Unexpected.
+            throw ErrorResultException.newErrorResult(ResultCode.OTHER,
+                "Unexpected exception when connecting to online server", e);
+          }
+          return super.handleAccept(clientContext);
+        }
+
+      };
+
+      final LDAPListener proxyListener = new LDAPListener("localhost",
+          TestCaseUtils.findFreePort(), proxyServerConnectionFactory);
+      try
+      {
+        // Connect and close.
+        final Connection connection = new LDAPConnectionFactory(
+            proxyListener.getSocketAddress()).getConnection();
+
+        Assert.assertTrue(proxyServerConnection.isConnected.await(10,
+            TimeUnit.SECONDS));
+        Assert.assertTrue(onlineServerConnection.isConnected.await(10,
+            TimeUnit.SECONDS));
+
+        // Wait for connect/close to complete.
+        connection.close();
+
+        proxyServerConnection.isClosed.await();
+      }
+      finally
+      {
+        proxyListener.close();
+      }
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests LDAP listener which attempts to open a connection to a load balancing
+   * pool at the point when the listener handles a bind request.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testLDAPListenerLoadBalanceDuringHandleBind() throws Exception
+  {
+    // Online server listener.
+    final int onlineServerPort = TestCaseUtils.findFreePort();
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        onlineServerPort, onlineServerConnectionFactory);
+
+    try
+    {
+      // Connection pool and load balancing tests.
+      final ConnectionFactory offlineServer1 = Connections
+          .newNamedConnectionFactory(new LDAPConnectionFactory("localhost",
+              TestCaseUtils.findFreePort()), "offline1");
+      final ConnectionFactory offlineServer2 = Connections
+          .newNamedConnectionFactory(new LDAPConnectionFactory("localhost",
+              TestCaseUtils.findFreePort()), "offline2");
+      final ConnectionFactory onlineServer = Connections
+          .newNamedConnectionFactory(new LDAPConnectionFactory("localhost",
+              onlineServerPort), "online");
+
+      // Round robin.
+      final ConnectionFactory loadBalancer = Connections
+          .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList(
+              Connections.newConnectionPool(offlineServer1, 10),
+              Connections.newConnectionPool(offlineServer2, 10),
+              Connections.newConnectionPool(onlineServer, 10))));
+
+      final MockServerConnection proxyServerConnection = new MockServerConnection()
+      {
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void handleBind(final Integer requestContext, final int version,
+            final BindRequest request,
+            final ResultHandler<? super BindResult> resultHandler,
+            final IntermediateResponseHandler intermediateResponseHandler)
+            throws UnsupportedOperationException
+        {
+          // Get connection from load balancer, this should fail over twice
+          // before getting connection to online server.
+          try
+          {
+            loadBalancer.getConnection().close();
+            resultHandler.handleResult(Responses
+                .newBindResult(ResultCode.SUCCESS));
+          }
+          catch (final Exception e)
+          {
+            // Unexpected.
+            resultHandler
+                .handleErrorResult(ErrorResultException.newErrorResult(
+                    ResultCode.OTHER,
+                    "Unexpected exception when connecting to load balancer", e));
+          }
+        }
+
+      };
+      final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory(
+          proxyServerConnection);
+
+      final LDAPListener proxyListener = new LDAPListener("localhost",
+          TestCaseUtils.findFreePort(), proxyServerConnectionFactory);
+      try
+      {
+        // Connect, bind, and close.
+        final Connection connection = new LDAPConnectionFactory(
+            proxyListener.getSocketAddress()).getConnection();
+        try
+        {
+          connection.bind("cn=test", "password".toCharArray());
+
+          Assert.assertTrue(proxyServerConnection.isConnected.await(10,
+              TimeUnit.SECONDS));
+          Assert.assertTrue(onlineServerConnection.isConnected.await(10,
+              TimeUnit.SECONDS));
+        }
+        finally
+        {
+          connection.close();
+        }
+
+        // Wait for connect/close to complete.
+        proxyServerConnection.isClosed.await();
+      }
+      finally
+      {
+        proxyListener.close();
+      }
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests LDAP listener which attempts to open a connection to a remote offline
+   * server at the point when the listener accepts the client connection.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = false)
+  public void testLDAPListenerProxyDuringHandleAccept() throws Exception
+  {
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), onlineServerConnectionFactory);
+
+    try
+    {
+      final int offlineServerPort = TestCaseUtils.findFreePort();
+
+      final MockServerConnection proxyServerConnection = new MockServerConnection();
+      final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory(
+          proxyServerConnection)
+      {
+
+        @Override
+        public ServerConnection<Integer> handleAccept(
+            final LDAPClientContext clientContext) throws ErrorResultException
+        {
+          // First attempt offline server.
+          LDAPConnectionFactory lcf = new LDAPConnectionFactory("localhost",
+              offlineServerPort);
+          try
+          {
+            // This is expected to fail.
+            lcf.getConnection().close();
+            throw ErrorResultException.newErrorResult(ResultCode.OTHER,
+                "Connection to offline server succeeded unexpectedly");
+          }
+          catch (final ConnectionException ce)
+          {
+            // This is expected - so go to online server.
+            try
+            {
+              lcf = new LDAPConnectionFactory(
+                  onlineServerListener.getSocketAddress());
+              lcf.getConnection().close();
+            }
+            catch (final Exception e)
+            {
+              // Unexpected.
+              throw ErrorResultException.newErrorResult(ResultCode.OTHER,
+                  "Unexpected exception when connecting to online server", e);
+            }
+          }
+          catch (final Exception e)
+          {
+            // Unexpected.
+            throw ErrorResultException.newErrorResult(ResultCode.OTHER,
+                "Unexpected exception when connecting to offline server", e);
+          }
+
+          return super.handleAccept(clientContext);
+        }
+
+      };
+      final LDAPListener proxyListener = new LDAPListener("localhost",
+          TestCaseUtils.findFreePort(), proxyServerConnectionFactory);
+      try
+      {
+        // Connect and close.
+        final Connection connection = new LDAPConnectionFactory(
+            proxyListener.getSocketAddress()).getConnection();
+
+        Assert.assertTrue(proxyServerConnection.isConnected.await(10,
+            TimeUnit.SECONDS));
+        Assert.assertTrue(onlineServerConnection.isConnected.await(10,
+            TimeUnit.SECONDS));
+
+        connection.close();
+
+        // Wait for connect/close to complete.
+        proxyServerConnection.isClosed.await();
+      }
+      finally
+      {
+        proxyListener.close();
+      }
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests LDAP listener which attempts to open a connection to a remote offline
+   * server at the point when the listener handles a bind request.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test
+  public void testLDAPListenerProxyDuringHandleBind() throws Exception
+  {
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), onlineServerConnectionFactory);
+
+    try
+    {
+      final int offlineServerPort = TestCaseUtils.findFreePort();
+
+      final MockServerConnection proxyServerConnection = new MockServerConnection()
+      {
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void handleBind(final Integer requestContext, final int version,
+            final BindRequest request,
+            final ResultHandler<? super BindResult> resultHandler,
+            final IntermediateResponseHandler intermediateResponseHandler)
+            throws UnsupportedOperationException
+        {
+          // First attempt offline server.
+          LDAPConnectionFactory lcf = new LDAPConnectionFactory("localhost",
+              offlineServerPort);
+          try
+          {
+            // This is expected to fail.
+            lcf.getConnection().close();
+            resultHandler.handleErrorResult(ErrorResultException
+                .newErrorResult(ResultCode.OTHER,
+                    "Connection to offline server succeeded unexpectedly"));
+          }
+          catch (final ConnectionException ce)
+          {
+            // This is expected - so go to online server.
+            try
+            {
+              lcf = new LDAPConnectionFactory(
+                  onlineServerListener.getSocketAddress());
+              lcf.getConnection().close();
+              resultHandler.handleResult(Responses
+                  .newBindResult(ResultCode.SUCCESS));
+            }
+            catch (final Exception e)
+            {
+              // Unexpected.
+              resultHandler.handleErrorResult(ErrorResultException
+                  .newErrorResult(ResultCode.OTHER,
+                      "Unexpected exception when connecting to online server",
+                      e));
+            }
+          }
+          catch (final Exception e)
+          {
+            // Unexpected.
+            resultHandler
+                .handleErrorResult(ErrorResultException
+                    .newErrorResult(
+                        ResultCode.OTHER,
+                        "Unexpected exception when connecting to offline server",
+                        e));
+          }
+        }
+
+      };
+      final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory(
+          proxyServerConnection);
+      final LDAPListener proxyListener = new LDAPListener("localhost",
+          TestCaseUtils.findFreePort(), proxyServerConnectionFactory);
+      try
+      {
+        // Connect, bind, and close.
+        final Connection connection = new LDAPConnectionFactory(
+            proxyListener.getSocketAddress()).getConnection();
+        try
+        {
+          connection.bind("cn=test", "password".toCharArray());
+
+          Assert.assertTrue(proxyServerConnection.isConnected.await(10,
+              TimeUnit.SECONDS));
+          Assert.assertTrue(onlineServerConnection.isConnected.await(10,
+              TimeUnit.SECONDS));
+        }
+        finally
+        {
+          connection.close();
+        }
+
+        // Wait for connect/close to complete.
+        proxyServerConnection.isClosed.await();
+      }
+      finally
+      {
+        proxyListener.close();
+      }
+    }
+    finally
+    {
+      onlineServerListener.close();
+    }
+  }
+
+
+
+  /**
+   * Tests server-side disconnection.
+   *
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @Test
+  public void testServerDisconnect() throws Exception
+  {
+    final MockServerConnection onlineServerConnection = new MockServerConnection();
+    final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory(
+        onlineServerConnection);
+    final LDAPListener onlineServerListener = new LDAPListener("localhost",
+        TestCaseUtils.findFreePort(), onlineServerConnectionFactory);
+
+    final Connection connection;
+    try
+    {
+      // Connect and bind.
+      connection = new LDAPConnectionFactory(
+          onlineServerListener.getSocketAddress()).getConnection();
+      try
+      {
+        connection.bind("cn=test", "password".toCharArray());
+      }
+      catch (final ErrorResultException e)
+      {
+        connection.close();
+        throw e;
+      }
+    }
+    finally
+    {
+      onlineServerConnection.context.disconnect();
+      onlineServerListener.close();
+    }
+
+    try
+    {
+      // Connect and bind.
+      final Connection failedConnection = new LDAPConnectionFactory(
+          onlineServerListener.getSocketAddress()).getConnection();
+      failedConnection.close();
+      connection.close();
+      Assert
+          .fail("Connection attempt to closed listener succeeded unexpectedly");
+    }
+    catch (final ConnectionException e)
+    {
+      // Expected.
+    }
+
+    try
+    {
+      connection.bind("cn=test", "password".toCharArray());
+      Assert.fail("Bind attempt on closed connection succeeded unexpectedly");
+    }
+    catch (final ErrorResultException e)
+    {
+      // Expected.
+      Assert.assertFalse(connection.isValid());
+      Assert.assertFalse(connection.isClosed());
+    }
+    finally
+    {
+      connection.close();
+      Assert.assertFalse(connection.isValid());
+      Assert.assertTrue(connection.isClosed());
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPServer.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPServer.java
new file mode 100644
index 0000000..140dab6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPServer.java
@@ -0,0 +1,789 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.ldap.LDAPConstants.TYPE_AUTHENTICATION_SASL;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.net.ssl.SSLContext;
+import javax.security.auth.callback.*;
+import javax.security.sasl.*;
+
+import org.opends.sdk.asn1.ASN1;
+import org.opends.sdk.asn1.ASN1Reader;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.requests.*;
+import org.opends.sdk.responses.*;
+
+import org.glassfish.grizzly.TransportFactory;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+import com.sun.opends.sdk.controls.AccountUsabilityRequestControl;
+import com.sun.opends.sdk.controls.AccountUsabilityResponseControl;
+
+
+
+/**
+ * A simple ldap server that manages 1000 entries and used for running
+ * testcases. //FIXME: make it MT-safe.
+ */
+public class LDAPServer implements
+    ServerConnectionFactory<LDAPClientContext, Integer>
+{
+  // Creates an abandonable request from the ordinary requests.
+  private static class AbandonableRequest implements Request
+  {
+    // the request.
+    private final Request request;
+
+    // whether is has been cancelled.
+    private final AtomicBoolean isCanceled;
+
+
+
+    // Ctor.
+    AbandonableRequest(final Request request)
+    {
+      this.request = request;
+      this.isCanceled = new AtomicBoolean(false);
+    }
+
+
+
+    public Request addControl(final Control cntrl)
+        throws UnsupportedOperationException, NullPointerException
+    {
+      return request.addControl(cntrl);
+    }
+
+
+
+    public <C extends Control> C getControl(final ControlDecoder<C> decoder,
+        final DecodeOptions options) throws DecodeException,
+        NullPointerException
+    {
+      return request.getControl(decoder, options);
+    }
+
+
+
+    public List<Control> getControls()
+    {
+      return request.getControls();
+    }
+
+
+
+    void cancel()
+    {
+      isCanceled.set(true);
+    }
+
+
+
+    boolean isCanceled()
+    {
+      return isCanceled.get();
+    }
+  }
+
+
+
+  // The singleton instance.
+  private static final LDAPServer instance = new LDAPServer();
+
+
+
+  /**
+   * Returns the singleton instance.
+   *
+   * @return Singleton instance.
+   */
+  public static LDAPServer getInstance()
+  {
+    return instance;
+  }
+
+
+
+  private class LDAPServerConnection implements
+      ServerConnection<Integer>
+  {
+
+    private final LDAPClientContext clientContext;
+    private SaslServer saslServer;
+
+
+
+    private LDAPServerConnection(LDAPClientContext clientContext)
+    {
+      this.clientContext = clientContext;
+    }
+
+
+
+    /**
+     * Abandons the request sent by the client.
+     *
+     * @param context
+     * @param request
+     * @throws UnsupportedOperationException
+     */
+    public void handleAbandon(final Integer context,
+        final AbandonRequest request) throws UnsupportedOperationException
+    {
+      // Check if we have any concurrent operation with this message id.
+      final AbandonableRequest req = requestsInProgress.get(request
+          .getRequestID());
+      if (req == null)
+      {
+        // Nothing to do here.
+        return;
+      }
+      // Cancel the request
+      req.cancel();
+      // No response is needed.
+    }
+
+
+
+    /**
+     * Adds the request sent by the client.
+     *
+     * @param context
+     * @param request
+     * @param handler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public void handleAdd(final Integer context,
+        final AddRequest request, final ResultHandler<? super Result> handler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      Result result = null;
+      final AbandonableRequest abReq = new AbandonableRequest(request);
+      requestsInProgress.put(context, abReq);
+      // Get the DN.
+      final DN dn = request.getName();
+      if (entryMap.containsKey(dn))
+      {
+        // duplicate entry.
+        result = Responses.newResult(ResultCode.ENTRY_ALREADY_EXISTS);
+        final ErrorResultException ere = ErrorResultException.wrap(result);
+        handler.handleErrorResult(ere);
+        // doesn't matter if it was canceled.
+        requestsInProgress.remove(context);
+        return;
+      }
+
+      // Create an entry out of this request.
+      final SearchResultEntry entry = Responses.newSearchResultEntry(dn);
+      for (final Control control : request.getControls())
+      {
+        entry.addControl(control);
+      }
+
+      for (final Attribute attr : request.getAllAttributes())
+      {
+        entry.addAttribute(attr);
+      }
+
+      if (abReq.isCanceled())
+      {
+        result = Responses.newResult(ResultCode.CANCELLED);
+        final ErrorResultException ere = ErrorResultException.wrap(result);
+        handler.handleErrorResult(ere);
+        requestsInProgress.remove(context);
+        return;
+      }
+      // Add this to the map.
+      entryMap.put(dn, entry);
+      requestsInProgress.remove(context);
+      result = Responses.newResult(ResultCode.SUCCESS);
+      handler.handleResult(result);
+    }
+
+
+
+    /**
+     * @param context
+     * @param version
+     * @param request
+     * @param resultHandler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public void handleBind(final Integer context, final int version,
+        final BindRequest request,
+        final ResultHandler<? super BindResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      // TODO: all bind types.
+      final AbandonableRequest abReq = new AbandonableRequest(request);
+      requestsInProgress.put(context, abReq);
+      if (request.getAuthenticationType() == TYPE_AUTHENTICATION_SASL
+          && request instanceof GenericBindRequest)
+      {
+        ASN1Reader reader = ASN1.getReader(((GenericBindRequest) request)
+            .getAuthenticationValue());
+        try
+        {
+          String saslMech = reader.readOctetStringAsString();
+          ByteString saslCred;
+          if (reader.hasNextElement())
+          {
+            saslCred = reader.readOctetString();
+          }
+          else
+          {
+            saslCred = ByteString.empty();
+          }
+
+          if (saslServer == null
+              || !saslServer.getMechanismName().equalsIgnoreCase(saslMech))
+          {
+            final Map<String, String> props = new HashMap<String, String>();
+            props.put(Sasl.QOP, "auth-conf,auth-int,auth");
+            saslServer = Sasl.createSaslServer(saslMech, "ldap", clientContext
+                .getLocalAddress().getHostName(), props, new CallbackHandler()
+            {
+              public void handle(Callback[] callbacks) throws IOException,
+                  UnsupportedCallbackException
+              {
+                for (final Callback callback : callbacks)
+                {
+                  if (callback instanceof NameCallback)
+                  {
+                    // Do nothing
+                  }
+                  else if (callback instanceof PasswordCallback)
+                  {
+                    ((PasswordCallback) callback).setPassword("password"
+                        .toCharArray());
+                  }
+                  else if (callback instanceof AuthorizeCallback)
+                  {
+                    ((AuthorizeCallback) callback).setAuthorized(true);
+                  }
+                  else if (callback instanceof RealmCallback)
+                  {
+                    // Do nothing
+                  }
+                  else
+                  {
+                    throw new UnsupportedCallbackException(callback);
+
+                  }
+                }
+              }
+            });
+          }
+
+          byte[] challenge = saslServer
+              .evaluateResponse(saslCred.toByteArray());
+          if (saslServer.isComplete())
+          {
+            resultHandler.handleResult(Responses.newBindResult(
+                ResultCode.SUCCESS).setServerSASLCredentials(
+                ByteString.wrap(challenge)));
+
+            String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
+            if (qop != null
+                && (qop.equalsIgnoreCase("auth-int") || qop
+                    .equalsIgnoreCase("auth-conf")))
+            {
+              ConnectionSecurityLayer csl = new ConnectionSecurityLayer()
+              {
+                public void dispose()
+                {
+                  try
+                  {
+                    saslServer.dispose();
+                  }
+                  catch (SaslException e)
+                  {
+                    e.printStackTrace();
+                  }
+                }
+
+
+
+                public byte[] unwrap(byte[] incoming, int offset, int len)
+                    throws ErrorResultException
+                {
+                  try
+                  {
+                    return saslServer.unwrap(incoming, offset, len);
+                  }
+                  catch (SaslException e)
+                  {
+                    throw ErrorResultException.wrap(Responses.newResult(
+                        ResultCode.OPERATIONS_ERROR).setCause(e));
+                  }
+                }
+
+
+
+                public byte[] wrap(byte[] outgoing, int offset, int len)
+                    throws ErrorResultException
+                {
+                  try
+                  {
+                    return saslServer.wrap(outgoing, offset, len);
+                  }
+                  catch (SaslException e)
+                  {
+                    throw ErrorResultException.wrap(Responses.newResult(
+                        ResultCode.OPERATIONS_ERROR).setCause(e));
+                  }
+                }
+              };
+
+              clientContext.startSASL(csl);
+            }
+
+          }
+          else
+          {
+            resultHandler.handleResult(Responses.newBindResult(
+                ResultCode.SASL_BIND_IN_PROGRESS).setServerSASLCredentials(
+                ByteString.wrap(challenge)));
+          }
+        }
+        catch (Exception e)
+        {
+          resultHandler.handleErrorResult(ErrorResultException.wrap(Responses
+              .newBindResult(ResultCode.OPERATIONS_ERROR).setCause(e)
+              .setDiagnosticMessage(e.toString())));
+        }
+      }
+      else
+      {
+        resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
+      }
+      requestsInProgress.remove(context);
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleConnectionClosed(final Integer context,
+        final UnbindRequest request)
+    {
+      close();
+    }
+
+
+
+    private void close()
+    {
+      if (saslServer != null)
+      {
+        try
+        {
+          saslServer.dispose();
+        }
+        catch (SaslException e)
+        {
+          e.printStackTrace();
+        }
+      }
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleConnectionDisconnected(ResultCode resultCode,
+        String message)
+    {
+      close();
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handleConnectionError(final Throwable error)
+    {
+      close();
+    }
+
+
+
+    /**
+     * @param context
+     * @param request
+     * @param resultHandler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public void handleCompare(final Integer context,
+        final CompareRequest request,
+        final ResultHandler<? super CompareResult> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      CompareResult result = null;
+      final AbandonableRequest abReq = new AbandonableRequest(request);
+      requestsInProgress.put(context, abReq);
+      // Get the DN.
+      final DN dn = request.getName();
+      if (!entryMap.containsKey(dn))
+      {
+        // entry not found.
+        result = Responses.newCompareResult(ResultCode.NO_SUCH_ATTRIBUTE);
+        final ErrorResultException ere = ErrorResultException.wrap(result);
+        resultHandler.handleErrorResult(ere);
+        // doesn't matter if it was canceled.
+        requestsInProgress.remove(context);
+        return;
+      }
+
+      // Get the entry.
+      final Entry entry = entryMap.get(dn);
+      final AttributeDescription attrDesc = request.getAttributeDescription();
+      for (final Attribute attr : entry.getAllAttributes(attrDesc))
+      {
+        final Iterator<ByteString> it = attr.iterator();
+        while (it.hasNext())
+        {
+          final ByteString s = it.next();
+          if (abReq.isCanceled())
+          {
+            final Result r = Responses.newResult(ResultCode.CANCELLED);
+            final ErrorResultException ere = ErrorResultException.wrap(r);
+            resultHandler.handleErrorResult(ere);
+            requestsInProgress.remove(context);
+            return;
+          }
+          if (s.equals(request.getAssertionValue()))
+          {
+            result = Responses.newCompareResult(ResultCode.COMPARE_TRUE);
+            resultHandler.handleResult(result);
+          }
+        }
+      }
+      result = Responses.newCompareResult(ResultCode.COMPARE_FALSE);
+      resultHandler.handleResult(result);
+      requestsInProgress.remove(context);
+    }
+
+
+
+    /**
+     * @param context
+     * @param request
+     * @param handler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public void handleDelete(final Integer context,
+        final DeleteRequest request,
+        final ResultHandler<? super Result> handler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      Result result = null;
+      final AbandonableRequest abReq = new AbandonableRequest(request);
+      requestsInProgress.put(context, abReq);
+      // Get the DN.
+      final DN dn = request.getName();
+      if (!entryMap.containsKey(dn))
+      {
+        // entry is not found.
+        result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
+        final ErrorResultException ere = ErrorResultException.wrap(result);
+        handler.handleErrorResult(ere);
+        // doesn't matter if it was canceled.
+        requestsInProgress.remove(context);
+        return;
+      }
+
+      if (abReq.isCanceled())
+      {
+        result = Responses.newResult(ResultCode.CANCELLED);
+        final ErrorResultException ere = ErrorResultException.wrap(result);
+        handler.handleErrorResult(ere);
+        requestsInProgress.remove(context);
+        return;
+      }
+      // Remove this from the map.
+      entryMap.remove(dn);
+      requestsInProgress.remove(context);
+    }
+
+
+
+    /**
+     * @param context
+     * @param request
+     * @param resultHandler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public <R extends ExtendedResult> void handleExtendedRequest(
+        final Integer context, final ExtendedRequest<R> request,
+        final ResultHandler<? super R> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      if (request.getOID().equals(StartTLSExtendedRequest.OID))
+      {
+        final R result = request.getResultDecoder().newExtendedErrorResult(
+            ResultCode.SUCCESS, "", "");
+        resultHandler.handleResult(result);
+        clientContext.startTLS(sslContext, null, sslContext.getSocketFactory()
+            .getSupportedCipherSuites(), false, false);
+      }
+    }
+
+
+
+    /**
+     * @param context
+     * @param request
+     * @param resultHandler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public void handleModify(final Integer context,
+        final ModifyRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      // TODO:
+    }
+
+
+
+    /**
+     * @param context
+     * @param request
+     * @param resultHandler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public void handleModifyDN(final Integer context,
+        final ModifyDNRequest request,
+        final ResultHandler<? super Result> resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      // TODO
+    }
+
+
+
+    /**
+     * @param context
+     * @param request
+     * @param resultHandler
+     * @param intermediateResponseHandler
+     * @throws UnsupportedOperationException
+     */
+    public void handleSearch(final Integer context,
+        final SearchRequest request, final SearchResultHandler resultHandler,
+        final IntermediateResponseHandler intermediateResponseHandler)
+        throws UnsupportedOperationException
+    {
+      Result result = null;
+      final AbandonableRequest abReq = new AbandonableRequest(request);
+      requestsInProgress.put(context, abReq);
+      // Get the DN.
+      final DN dn = request.getName();
+      if (!entryMap.containsKey(dn))
+      {
+        // Entry not found.
+        result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
+        final ErrorResultException ere = ErrorResultException.wrap(result);
+        resultHandler.handleErrorResult(ere);
+        // Should searchResultHandler handle anything?
+
+        // doesn't matter if it was canceled.
+        requestsInProgress.remove(context);
+        return;
+      }
+
+      if (abReq.isCanceled())
+      {
+        result = Responses.newResult(ResultCode.CANCELLED);
+        final ErrorResultException ere = ErrorResultException.wrap(result);
+        resultHandler.handleErrorResult(ere);
+        requestsInProgress.remove(context);
+        return;
+      }
+
+      final SearchResultEntry e = Responses
+          .newSearchResultEntry(new LinkedHashMapEntry(entryMap.get(dn)));
+      // Check we have had any controls in the request.
+      for (final Control control : request.getControls())
+      {
+        if (control.getOID().equals(AccountUsabilityRequestControl.OID))
+        {
+          e.addControl(AccountUsabilityResponseControl.newControl(false, false,
+              false, 10, false, 0));
+        }
+      }
+      resultHandler.handleEntry(e);
+      result = Responses.newResult(ResultCode.SUCCESS);
+      resultHandler.handleResult(result);
+      requestsInProgress.remove(context);
+    }
+  }
+
+
+
+  // The mapping between entry DNs and the corresponding entries.
+  private final ConcurrentHashMap<DN, Entry> entryMap = new ConcurrentHashMap<DN, Entry>();
+
+  // The grizzly transport.
+  private final TCPNIOTransport transport = TransportFactory.getInstance()
+      .createTCPTransport();
+
+  // The LDAP listener.
+  private LDAPListener listener = null;
+
+  // whether the server is running.
+  private volatile boolean isRunning;
+
+  // The mapping between the message id and the requests the server is currently
+  // handling.
+  private final ConcurrentHashMap<Integer, AbandonableRequest> requestsInProgress = new ConcurrentHashMap<Integer, AbandonableRequest>();
+
+  // The Set used for locking dns.
+  private final HashSet<DN> lockedDNs = new HashSet<DN>();
+
+  private SSLContext sslContext;
+
+
+
+  private LDAPServer()
+  {
+    // Add the root dse first.
+    entryMap.put(DN.rootDN(),
+        Entries.unmodifiableEntry(new LinkedHashMapEntry()));
+    for (int i = 0; i < 1000; i++)
+    {
+      final String dn = String.format("uid=user.%d,ou=people,o=test", i);
+      final String cn = String.format("cn: user.%d", i);
+      final String sn = String.format("sn: %d", i);
+      final String uid = String.format("uid: user.%d", i);
+
+      final DN d = DN.valueOf(dn);
+      final Entry e = new LinkedHashMapEntry("dn: " + dn,
+          "objectclass: person", "objectclass: inetorgperson",
+          "objectclass: top", cn, sn, uid);
+      entryMap.put(d, Entries.unmodifiableEntry(e));
+    }
+  }
+
+
+
+  /**
+   * @param context
+   * @return
+   */
+  public ServerConnection<Integer> handleAccept(final LDAPClientContext context)
+  {
+    return new LDAPServerConnection(context);
+  }
+
+
+
+  /**
+   * Returns whether the server is running or not.
+   *
+   * @return Whether the server is running.
+   */
+  public boolean isRunning()
+  {
+    return isRunning;
+  }
+
+
+
+  /**
+   * Starts the server.
+   *
+   * @param port
+   * @exception IOException
+   */
+  public synchronized void start(final int port) throws Exception
+  {
+    if (isRunning)
+    {
+      return;
+    }
+    sslContext = new SSLContextBuilder().getSSLContext();
+
+    transport.setSelectorRunnersCount(2);
+    listener = new LDAPListener(port, getInstance(),
+        new LDAPListenerOptions().setTCPNIOTransport(transport)
+            .setBacklog(4096));
+    transport.start();
+    isRunning = true;
+  }
+
+
+
+  /**
+   * Stops the server.
+   */
+  public synchronized void stop()
+  {
+    if (!isRunning)
+    {
+      return;
+    }
+    listener.close();
+    try
+    {
+      transport.stop();
+    }
+    catch (final IOException e)
+    {
+      e.printStackTrace();
+    }
+    TransportFactory.getInstance().close();
+    isRunning = false;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPUrlTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPUrlTestCase.java
new file mode 100644
index 0000000..df0222d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LDAPUrlTestCase.java
@@ -0,0 +1,232 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class defines a set of tests for the org.opends.sdk.LDAPUrl class.
+ */
+public class LDAPUrlTestCase extends SdkTestCase
+{
+  /**
+   * LDAPUrl encoding test data provider.
+   *
+   * @return The array of test encoding of LDAP URL strings.
+   */
+  @DataProvider(name = "ldapurls")
+  public Object[][] createEncodingData()
+  {
+    return new Object[][] {
+        { "ldap://", "ldap://", true },
+        { "ldap:///", "ldap:///", true },
+        { "ldap://ldap.example.net", "ldap://ldap.example.net", true },
+        { "ldap://ldap.example.net/", "ldap://ldap.example.net/", true },
+        { "ldap://ldap.example.net/?", "ldap://ldap.example.net/?", true },
+        { "ldap:///o=University of Michigan,c=US",
+            "ldap:///o=University%20of%20Michigan,c=US", true },
+        { "ldap://ldap1.example.net/o=University of Michigan,c=US",
+            "ldap://ldap1.example.net/o=University%20of%20Michigan,c=US", true },
+        {
+            "ldap://ldap1.example.net/o=University of Michigan,c=US?postalAddress",
+            "ldap://ldap1.example.net/o=University%20of%20Michigan,c=US?postalAddress",
+            true },
+        {
+            "ldap://ldap1.example.net:6666/o=University of Michigan,c=US??sub?(cn=Babs Jensen)",
+            "ldap://ldap1.example.net:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)",
+            true },
+        { "LDAP://ldap1.example.com/c=GB?objectClass?ONE",
+            "LDAP://ldap1.example.com/c=GB?objectClass?ONE", true },
+        // { "ldap://ldap2.example.com/o=Question?,c=US?mail",
+        // "ldap://ldap2.example.com/o=Question%3f,c=US?mail",true },
+        {
+            "ldap://ldap3.example.com/o=Babsco,c=US???(four-octet=\00\00\00\04)",
+            "ldap://ldap3.example.com/o=Babsco,c=US???(four-octet=%5c00%5c00%5c00%5c04)",
+            true },
+        { "ldap://ldap.example.com/o=An Example\\2C Inc.,c=US",
+            "ldap://ldap.example.com/o=An%20Example%5C2C%20Inc.,c=US", true },
+        { "ldap:///", "ldap:///", true }, { "ldap:///", "ldap:///", true },
+        { "ldap:///", "ldap:///", true }, };
+  }
+
+
+
+  /**
+   * LDAPUrl construction test data provider.
+   *
+   * @return The array of test construction of LDAPUrl objects.
+   */
+  @DataProvider(name = "urlobjects1")
+  public Object[][] createURLObjects1()
+  {
+    return new Object[][] {
+        { new LDAPUrl(false, null, null, null, null, null), "ldap:///???" },
+        { new LDAPUrl(true, null, null, null, null, null), "ldaps:///???" },
+        { new LDAPUrl(true, "void.central.sun.com", null, null, null, null),
+            "ldaps://void.central.sun.com/???" },
+        { new LDAPUrl(true, null, 1245, null, null, null), "ldaps://:1245/???" },
+        { new LDAPUrl(true, "void.central", 123, null, null, null),
+            "ldaps://void.central:123/???" },
+        { new LDAPUrl(true, null, null, null, null, null, "cn", "sn"),
+            "ldaps:///?cn,sn??" },
+        {
+            new LDAPUrl(true, null, null, null, null, Filter
+                .newEqualityMatchFilter("uid", "abc"), "cn"),
+            "ldaps:///?cn??(uid=abc)" },
+        {
+            new LDAPUrl(true, null, null, null, SearchScope.WHOLE_SUBTREE,
+                Filter.newEqualityMatchFilter("uid", "abc"), "cn"),
+            "ldaps:///?cn?sub?(uid=abc)" },
+        {
+            new LDAPUrl(true, null, null, DN.valueOf("uid=abc,o=target"),
+                SearchScope.WHOLE_SUBTREE, Filter.newEqualityMatchFilter("uid",
+                    "abc"), "cn"), "ldaps:///uid=abc,o=target?cn?sub?(uid=abc)" },
+        {
+            new LDAPUrl(true, "localhost", 1345,
+                DN.valueOf("uid=abc,o=target"), SearchScope.WHOLE_SUBTREE,
+                Filter.newEqualityMatchFilter("uid", "abc"), "cn"),
+            "ldaps://localhost:1345/uid=abc,o=target?cn?sub?(uid=abc)" }, };
+  }
+
+
+
+  /**
+   * LDAPUrl construction test data provider.
+   *
+   * @return The array of test construction of LDAPUrl objects.
+   */
+  @DataProvider(name = "urlobjects2")
+  public Object[][] createURLObjects2()
+  {
+    return new Object[][] {
+        { new LDAPUrl(false, null, null, null, null, null),
+            LDAPUrl.valueOf("ldap:///") },
+        { new LDAPUrl(true, null, null, null, null, null),
+            LDAPUrl.valueOf("ldaps:///") },
+        { new LDAPUrl(true, "void.central.sun.com", null, null, null, null),
+            LDAPUrl.valueOf("ldaps://void.central.sun.com") },
+        { new LDAPUrl(true, null, 1245, null, null, null),
+            LDAPUrl.valueOf("ldaps://:1245") },
+        { new LDAPUrl(true, "void.central", 123, null, null, null),
+            LDAPUrl.valueOf("ldaps://void.central:123") },
+        { new LDAPUrl(true, null, null, null, null, null, "cn", "sn"),
+            LDAPUrl.valueOf("ldaps:///?cn,sn??") },
+        {
+            new LDAPUrl(true, null, null, null, null, Filter
+                .newEqualityMatchFilter("uid", "abc"), "cn"),
+            LDAPUrl.valueOf("ldaps:///?cn??(uid=abc)") },
+        {
+            new LDAPUrl(true, null, null, null, SearchScope.WHOLE_SUBTREE,
+                Filter.newEqualityMatchFilter("uid", "abc"), "cn"),
+            LDAPUrl.valueOf("ldaps:///?cn?sub?(uid=abc)") },
+        {
+            new LDAPUrl(true, null, null, DN.valueOf("uid=abc,o=target"),
+                SearchScope.WHOLE_SUBTREE, Filter.newEqualityMatchFilter("uid",
+                    "abc"), "cn"),
+            LDAPUrl.valueOf("ldaps:///uid=abc,o=target?cn?sub?(uid=abc)") },
+        {
+            new LDAPUrl(true, "localhost", 1345,
+                DN.valueOf("uid=abc,o=target"), SearchScope.WHOLE_SUBTREE,
+                Filter.newEqualityMatchFilter("uid", "abc"), "cn"),
+            LDAPUrl
+                .valueOf("ldaps://localhost:1345/uid=abc,o=target?cn?sub?(uid=abc)") }, };
+  }
+
+
+
+  /**
+   * Tests equals method of the LDAP URL.
+   *
+   * @param urlObj1
+   *          The LDAPUrl object.
+   * @param urlObj2
+   *          The LDAPUrl object.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "urlobjects2")
+  public void testLDAPURLCtor(final LDAPUrl urlObj1, final LDAPUrl urlObj2)
+      throws Exception
+  {
+    assertTrue(urlObj1.equals(urlObj2));
+  }
+
+
+
+  /**
+   * Test Whether the LDAP URL (non-encoded) is constructed properly from the
+   * arguments.
+   *
+   * @param urlObj
+   *          The LDAPUrl object.
+   * @param urlString
+   *          The non-encoded ldap url.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "urlobjects1")
+  public void testLDAPURLCtor(final LDAPUrl urlObj, final String urlString)
+      throws Exception
+  {
+    assertEquals(urlString, urlObj.toString());
+  }
+
+
+
+  /**
+   * Test the LDAP URL encoding.
+   *
+   * @param toEncode
+   *          The URL that needs encoding.
+   * @param encoded
+   *          The encoded URL.
+   * @param valid
+   *          if the encoding is valid.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "ldapurls")
+  public void testURLEncoding(final String toEncode, final String encoded,
+      final boolean valid) throws Exception
+  {
+    final LDAPUrl url1 = LDAPUrl.valueOf(toEncode);
+    final LDAPUrl url2 = LDAPUrl.valueOf(encoded);
+    if (valid)
+    {
+      assertTrue(url1.equals(url2));
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LinkedAttributeTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LinkedAttributeTestCase.java
new file mode 100644
index 0000000..4ec0f6b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/LinkedAttributeTestCase.java
@@ -0,0 +1,486 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.opends.sdk.schema.Schema;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test {@code BasicAttribute}.
+ */
+
+public final class LinkedAttributeTestCase extends SdkTestCase
+{
+  @Test
+  public void smokeTest() throws Exception
+  {
+    // TODO: write a proper test suite.
+    final AbstractAttribute attribute = new LinkedAttribute(
+        AttributeDescription.valueOf("ALTSERVER", Schema.getCoreSchema()));
+
+    attribute.add(1);
+    attribute.add("a value");
+    attribute.add(ByteString.valueOf("another value"));
+
+    Assert.assertTrue(attribute.contains(1));
+    Assert.assertTrue(attribute.contains("a value"));
+    Assert.assertTrue(attribute.contains(ByteString.valueOf("another value")));
+
+    Assert.assertEquals(attribute.size(), 3);
+    Assert.assertTrue(attribute.remove(1));
+    Assert.assertEquals(attribute.size(), 2);
+    Assert.assertFalse(attribute.remove("a missing value"));
+    Assert.assertEquals(attribute.size(), 2);
+    Assert.assertTrue(attribute.remove("a value"));
+    Assert.assertEquals(attribute.size(), 1);
+    Assert.assertTrue(attribute.remove(ByteString.valueOf("another value")));
+    Assert.assertEquals(attribute.size(), 0);
+  }
+
+
+
+  @Test
+  public void testAdd()
+  {
+    Attribute a = new LinkedAttribute("test");
+    Assert.assertTrue(a.add(ByteString.valueOf("value1")));
+    Assert.assertFalse(a.add(ByteString.valueOf("value1")));
+    Assert.assertTrue(a.add(ByteString.valueOf("value2")));
+    Assert.assertFalse(a.add(ByteString.valueOf("value2")));
+    Assert.assertTrue(a.add(ByteString.valueOf("value3")));
+    Assert.assertFalse(a.add(ByteString.valueOf("value3")));
+    Assert.assertEquals(a.size(), 3);
+    Iterator<ByteString> i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value3"));
+    Assert.assertFalse(i.hasNext());
+  }
+
+
+
+  @Test
+  public void testAddAll()
+  {
+    // addAll to an empty attribute.
+    Attribute a = new LinkedAttribute("test");
+    Assert.assertFalse(a.addAll(Collections.<ByteString> emptyList(), null));
+    Iterator<ByteString> i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test");
+    Assert.assertTrue(a.addAll(Arrays.asList(ByteString.valueOf("value1")),
+        null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test");
+    Assert.assertTrue(a.addAll(
+        Arrays.asList(ByteString.valueOf("value1"),
+            ByteString.valueOf("value2")), null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertFalse(i.hasNext());
+
+    // addAll to a single-valued attribute.
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertFalse(a.addAll(Collections.<ByteString> emptyList(), null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertTrue(a.addAll(Arrays.asList(ByteString.valueOf("value2")),
+        null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertTrue(a.addAll(
+        Arrays.asList(ByteString.valueOf("value2"),
+            ByteString.valueOf("value3")), null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value3"));
+    Assert.assertFalse(i.hasNext());
+
+    // addAll to a multi-valued attribute.
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"));
+    Assert.assertFalse(a.addAll(Collections.<ByteString> emptyList(), null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"));
+    Assert.assertTrue(a.addAll(Arrays.asList(ByteString.valueOf("value3")),
+        null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value3"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"));
+    Assert.assertTrue(a.addAll(
+        Arrays.asList(ByteString.valueOf("value3"),
+            ByteString.valueOf("value4")), null));
+    i = a.iterator();
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value3"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value4"));
+    Assert.assertFalse(i.hasNext());
+  }
+
+
+
+  @Test
+  public void testClear()
+  {
+    Attribute a = new LinkedAttribute("test");
+    Assert.assertTrue(a.isEmpty());
+    Assert.assertEquals(a.size(), 0);
+    a.clear();
+    Assert.assertTrue(a.isEmpty());
+    Assert.assertEquals(a.size(), 0);
+
+    a.add(ByteString.valueOf("value1"));
+    Assert.assertFalse(a.isEmpty());
+    Assert.assertEquals(a.size(), 1);
+    a.clear();
+    Assert.assertTrue(a.isEmpty());
+    Assert.assertEquals(a.size(), 0);
+
+    a.add(ByteString.valueOf("value1"));
+    a.add(ByteString.valueOf("value2"));
+    Assert.assertFalse(a.isEmpty());
+    Assert.assertEquals(a.size(), 2);
+    a.clear();
+    Assert.assertTrue(a.isEmpty());
+    Assert.assertEquals(a.size(), 0);
+
+    a.add(ByteString.valueOf("value1"));
+    a.add(ByteString.valueOf("value2"));
+    a.add(ByteString.valueOf("value3"));
+    Assert.assertFalse(a.isEmpty());
+    Assert.assertEquals(a.size(), 3);
+    a.clear();
+    Assert.assertTrue(a.isEmpty());
+    Assert.assertEquals(a.size(), 0);
+  }
+
+
+
+  @Test
+  public void testContains()
+  {
+    Attribute a = new LinkedAttribute("test");
+    Assert.assertFalse(a.contains(ByteString.valueOf("value4")));
+
+    a.add(ByteString.valueOf("value1"));
+    Assert.assertTrue(a.contains(ByteString.valueOf("value1")));
+    Assert.assertFalse(a.contains(ByteString.valueOf("value4")));
+
+    a.add(ByteString.valueOf("value2"));
+    Assert.assertTrue(a.contains(ByteString.valueOf("value1")));
+    Assert.assertTrue(a.contains(ByteString.valueOf("value2")));
+    Assert.assertFalse(a.contains(ByteString.valueOf("value4")));
+
+    a.add(ByteString.valueOf("value3"));
+    Assert.assertTrue(a.contains(ByteString.valueOf("value1")));
+    Assert.assertTrue(a.contains(ByteString.valueOf("value2")));
+    Assert.assertTrue(a.contains(ByteString.valueOf("value3")));
+    Assert.assertFalse(a.contains(ByteString.valueOf("value4")));
+  }
+
+
+
+  @Test
+  public void testContainsAll()
+  {
+    Attribute a = new LinkedAttribute("test");
+    Assert.assertTrue(a.containsAll(Collections.<ByteString> emptyList()));
+    Assert
+        .assertFalse(a.containsAll(Arrays.asList(ByteString.valueOf("value1"))));
+    Assert.assertFalse(a.containsAll(Arrays.asList(
+        ByteString.valueOf("value1"), ByteString.valueOf("value2"))));
+    Assert.assertFalse(a.containsAll(Arrays.asList(
+        ByteString.valueOf("value1"), ByteString.valueOf("value2"),
+        ByteString.valueOf("value3"))));
+
+    a.add(ByteString.valueOf("value1"));
+    Assert.assertTrue(a.containsAll(Collections.<ByteString> emptyList()));
+    Assert
+        .assertTrue(a.containsAll(Arrays.asList(ByteString.valueOf("value1"))));
+    Assert.assertFalse(a.containsAll(Arrays.asList(
+        ByteString.valueOf("value1"), ByteString.valueOf("value2"))));
+    Assert.assertFalse(a.containsAll(Arrays.asList(
+        ByteString.valueOf("value1"), ByteString.valueOf("value2"),
+        ByteString.valueOf("value3"))));
+
+    a.add(ByteString.valueOf("value2"));
+    Assert.assertTrue(a.containsAll(Collections.<ByteString> emptyList()));
+    Assert
+        .assertTrue(a.containsAll(Arrays.asList(ByteString.valueOf("value1"))));
+    Assert.assertTrue(a.containsAll(Arrays.asList(ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"))));
+    Assert.assertFalse(a.containsAll(Arrays.asList(
+        ByteString.valueOf("value1"), ByteString.valueOf("value2"),
+        ByteString.valueOf("value3"))));
+  }
+
+
+
+  @Test
+  public void testFirstValue()
+  {
+    Attribute a = new LinkedAttribute("test");
+    try
+    {
+      a.firstValue();
+      Assert.fail("Expected NoSuchElementException");
+    }
+    catch (NoSuchElementException e)
+    {
+      // Expected.
+    }
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertEquals(a.firstValue(), ByteString.valueOf("value1"));
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"));
+    Assert.assertEquals(a.firstValue(), ByteString.valueOf("value1"));
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value2"),
+        ByteString.valueOf("value1"));
+    Assert.assertEquals(a.firstValue(), ByteString.valueOf("value2"));
+  }
+
+
+
+  @Test
+  public void testGetAttributeDescription()
+  {
+    AttributeDescription ad = AttributeDescription.valueOf("test");
+    Attribute a = new LinkedAttribute(ad);
+    Assert.assertEquals(a.getAttributeDescription(), ad);
+  }
+
+
+
+  @Test
+  public void testIterator()
+  {
+    Attribute a = new LinkedAttribute("test");
+    Iterator<ByteString> i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertFalse(i.hasNext());
+  }
+
+
+
+  @Test
+  public void testRemove()
+  {
+    Attribute a = new LinkedAttribute("test");
+    Assert.assertFalse(a.remove(ByteString.valueOf("value1")));
+    Iterator<ByteString> i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertFalse(a.remove(ByteString.valueOf("value2")));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertFalse(i.hasNext());
+    Assert.assertTrue(a.remove(ByteString.valueOf("value1")));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"));
+    Assert.assertFalse(a.remove(ByteString.valueOf("value3")));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertFalse(i.hasNext());
+    Assert.assertTrue(a.remove(ByteString.valueOf("value1")));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertFalse(i.hasNext());
+    Assert.assertTrue(a.remove(ByteString.valueOf("value2")));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+  }
+
+
+
+  @Test
+  public void testRemoveAll()
+  {
+    // removeAll from an empty attribute.
+    Attribute a = new LinkedAttribute("test");
+    Assert.assertFalse(a.removeAll(Collections.<ByteString> emptyList(), null));
+    Iterator<ByteString> i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test");
+    Assert.assertFalse(a.removeAll(Arrays.asList(ByteString.valueOf("value1")),
+        null));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test");
+    Assert.assertFalse(a.removeAll(Arrays.asList(ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"))));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    // removeAll from single-valued attribute.
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertFalse(a.removeAll(Collections.<ByteString> emptyList(), null));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1")),
+        null));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"));
+    Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"))));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    // removeAll from multi-valued attribute.
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4"));
+    Assert.assertFalse(a.removeAll(Collections.<ByteString> emptyList(), null));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value1"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value3"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value4"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4"));
+    Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1")),
+        null));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value2"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value3"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value4"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4"));
+    Assert.assertTrue(a.removeAll(
+        Arrays.asList(ByteString.valueOf("value1"),
+            ByteString.valueOf("value2")), null));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value3"));
+    Assert.assertEquals(i.next(), ByteString.valueOf("value4"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4"));
+    Assert.assertTrue(a.removeAll(
+        Arrays.asList(ByteString.valueOf("value1"),
+            ByteString.valueOf("value2"), ByteString.valueOf("value3")), null));
+    i = a.iterator();
+    Assert.assertTrue(i.hasNext());
+    Assert.assertEquals(i.next(), ByteString.valueOf("value4"));
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4"));
+    Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4")), null));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+
+    a = new LinkedAttribute("test", ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4"));
+    Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1"),
+        ByteString.valueOf("value2"), ByteString.valueOf("value3"),
+        ByteString.valueOf("value4"), ByteString.valueOf("value5")), null));
+    i = a.iterator();
+    Assert.assertFalse(i.hasNext());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/OpenDSTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/OpenDSTestCase.java
new file mode 100644
index 0000000..9847b93
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/OpenDSTestCase.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class defines a base test case that should be subclassed by all unit
+ * tests used by OpenDS.
+ * <p>
+ * This class adds the ability to print error messages and automatically have
+ * them include the class name.
+ */
+@Test(sequential = true)
+public abstract class OpenDSTestCase
+{
+
+  //
+  // This is all a HACK to reduce the amount of memory that's consumed.
+  //
+  // This could be a problem if a subclass references a @DataProvider in
+  // a super-class that provides static parameters, i.e. the parameters
+  // are not regenerated for each invocation of the DataProvider.
+  //
+
+  /**
+   * A list of all parameters that were generated by a @DataProvider and passed
+   * to a test method of this class. TestListener helps us keep this so that
+   * once all of the tests are finished, we can clear it out in an @AfterClass
+   * method. We can't just clear it out right away in the TestListener because
+   * some methods share a @DataProvider.
+   */
+  private final IdentityHashMap<Object[], Object> successfulTestParams = new IdentityHashMap<Object[], Object>();
+
+  /**
+   * These are test parameters from a test that has failed. We need to keep
+   * these around because the test report expects to find them when printing out
+   * failures.
+   */
+  private final IdentityHashMap<Object[], Object> failedTestParams = new IdentityHashMap<Object[], Object>();
+
+
+
+  /**
+   * null out all test parameters except the ones used in failed tests since we
+   * might need these again.
+   */
+  @AfterClass(alwaysRun = true)
+  public void clearSuccessfulTestParams()
+  {
+    final Set<Object[]> paramsSet = successfulTestParams.keySet();
+    if (paramsSet == null)
+    { // Can this ever happen?
+      return;
+    }
+    for (final Object[] params : paramsSet)
+    {
+      if (failedTestParams.containsKey(params))
+      {
+        continue;
+      }
+
+      for (int i = 0; i < params.length; i++)
+      {
+        params[i] = null;
+      }
+    }
+    successfulTestParams.clear();
+    failedTestParams.clear();
+  }
+
+
+
+  /**
+   * The member variables of a test class can prevent lots of memory from being
+   * reclaimed, so we use reflection to null out all of the member variables
+   * after the tests have run. Since all tests must inherit from
+   * DirectoryServerTestCase, TestNG guarantees that this method runs after all
+   * of the subclass methods, so this isn't too dangerous.
+   */
+  @AfterClass(alwaysRun = true)
+  public void nullMemberVariablesAfterTest()
+  {
+    Class<?> cls = this.getClass();
+    // Iterate through all of the fields in all subclasses of
+    // DirectoryServerTestCase, but not DirectoryServerTestCase itself.
+    while (OpenDSTestCase.class.isAssignableFrom(cls)
+        && !OpenDSTestCase.class.equals(cls))
+    {
+      final Field fields[] = cls.getDeclaredFields();
+      for (final Field field : fields)
+      {
+        final int modifiers = field.getModifiers();
+        final Class<?> fieldClass = field.getType();
+        // If it's a non-static non-final non-primitive type, then null
+        // it out
+        // so that the garbage collector can reclaim it and everything
+        // it
+        // references.
+        if (!fieldClass.isPrimitive() && !fieldClass.isEnum()
+            && !Modifier.isFinal(modifiers) && !Modifier.isStatic(modifiers))
+        {
+          field.setAccessible(true);
+          try
+          {
+            field.set(this, null);
+          }
+          catch (final IllegalAccessException e)
+          {
+            // We're only doing this to save memory, so it's no big deal
+            // if we can't set it.
+          }
+        }
+      }
+      cls = cls.getSuperclass();
+    }
+  }
+
+
+
+  /**
+   * Adds testParams to the list of all failed test parameters, so that we know
+   * to NOT null it out later.
+   */
+  void addParamsFromFailedTest(final Object[] testParams)
+  {
+    if (testParams != null)
+    {
+      failedTestParams.put(testParams, testParams);
+    }
+  }
+
+
+
+  /**
+   * Adds testParams to the list of all test parameters, so it can be null'ed
+   * out later if it's not part.
+   */
+  void addParamsFromSuccessfulTests(final Object[] testParams)
+  {
+    if (testParams != null)
+    {
+      successfulTestParams.put(testParams, testParams);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/RDNTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/RDNTestCase.java
new file mode 100644
index 0000000..c116b69
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/RDNTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.Iterator;
+
+import org.opends.sdk.schema.AttributeType;
+import org.opends.sdk.schema.Schema;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class defines a set of tests for the {@link org.opends.sdk.RDN} class.
+ */
+public final class RDNTestCase extends TypesTestCase
+{
+
+  // Domain component attribute type.
+  private AttributeType AT_DC;
+
+  // Common name attribute type.
+  private AttributeType AT_CN;
+
+  // Test attribute value.
+  private AVA AV_DC_ORG;
+
+  // org bytestring.
+  private static final ByteString ORG = ByteString.valueOf("org");
+
+  // opends bytestring.
+  private static final ByteString OPENDS = ByteString.valueOf("opends");
+
+
+
+  /**
+   * RDN test data provider.
+   *
+   * @return The array of test RDN strings.
+   */
+  @DataProvider(name = "testRDNs")
+  public Object[][] createData()
+  {
+    return new Object[][] {
+        { "dc=hello world", "dc=hello world", "dc=hello world" },
+        { "dc =hello world", "dc=hello world", "dc=hello world" },
+        { "dc  =hello world", "dc=hello world", "dc=hello world" },
+        { "dc= hello world", "dc=hello world", "dc=hello world" },
+        { "dc=  hello world", "dc=hello world", "dc=hello world" },
+        { "undefined=hello", "undefined=hello", "undefined=hello" },
+        { "DC=HELLO WORLD", "dc=hello world", "DC=HELLO WORLD" },
+        { "dc = hello    world", "dc=hello world", "dc=hello    world" },
+        { "   dc = hello world   ", "dc=hello world", "dc=hello world" },
+        { "givenName=John+cn=Doe", "cn=doe+givenname=john",
+            "givenName=John+cn=Doe" },
+        { "givenName=John\\+cn=Doe", "givenname=john\\+cn\\=doe",
+            "givenName=John\\+cn=Doe" },
+        { "cn=Doe\\, John", "cn=doe\\, john", "cn=Doe\\, John" },
+        { "OU=Sales+CN=J. Smith", "cn=j. smith+ou=sales",
+            "OU=Sales+CN=J. Smith" },
+        { "CN=James \\\"Jim\\\" Smith\\, III",
+            "cn=james \\\"jim\\\" smith\\, iii",
+            "CN=James \\\"Jim\\\" Smith\\, III" },
+        // \0d is a hex representation of Carriage return. It is mapped
+        // to a SPACE as defined in the MAP ( RFC 4518)
+        { "CN=Before\\0dAfter", "cn=before after", "CN=Before\\0dAfter" },
+        { "cn=#04024869",
+        // Unicode codepoints from 0000-0008 are mapped to nothing.
+            "cn=hi", "cn=\\04\\02Hi" },
+        { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107", "CN=Lu\u010di\u0107" },
+        { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8", "ou=\u55b6\u696d\u90e8",
+            "ou=\u55b6\u696d\u90e8" },
+        { "photo=\\ john \\ ", "photo=\\ john \\ ", "photo=\\ john \\ " },
+        { "AB-global=", "ab-global=", "AB-global=" },
+        { "cn=John+a=", "a=+cn=john", "cn=John+a=" },
+        { "O=\"Sue, Grabbit and Runn\"", "o=sue\\, grabbit and runn",
+            "O=Sue\\, Grabbit and Runn" }, };
+  }
+
+
+
+  /**
+   * Illegal RDN test data provider.
+   *
+   * @return The array of illegal test RDN strings.
+   */
+  @DataProvider(name = "illegalRDNs")
+  public Object[][] createIllegalData()
+  {
+    return new Object[][] { { null }, { "" }, { " " }, { "=" }, { "manager" },
+        { "manager " }, { "cn+" },
+        { "cn+Jim" },
+        { "cn=Jim+" },
+        { "cn=Jim +" },
+        { "cn=Jim+ " },
+        { "cn=Jim+sn" },
+        { "cn=Jim+sn " },
+        { "cn=Jim+sn equals" },// { "cn=Jim," }, { "cn=Jim;" }, { "cn=Jim,  " },
+        // { "cn=Jim+sn=a," }, { "cn=Jim, sn=Jam " }, { "cn+uid=Jim" },
+        { "-cn=Jim" }, { "/tmp=a" }, { "\\tmp=a" }, { "cn;lang-en=Jim" },
+        { "@cn=Jim" }, { "_name_=Jim" }, { "\u03c0=pi" }, { "v1.0=buggy" },
+        { "cn=Jim+sn=Bob++" }, { "cn=Jim+sn=Bob+," },
+        { "1.3.6.1.4.1.1466..0=#04024869" }, };
+  }
+
+
+
+  /**
+   * RDN equality test data provider.
+   *
+   * @return The array of test RDN strings.
+   */
+  @DataProvider(name = "createRDNEqualityData")
+  public Object[][] createRDNEqualityData()
+  {
+    return new Object[][] {
+        { "cn=hello world", "cn=hello world", 0 },
+        { "cn=hello world", "CN=hello world", 0 },
+        { "cn=hello   world", "cn=hello world", 0 },
+        { "  cn =  hello world  ", "cn=hello world", 0 },
+        { "cn=hello world\\ ", "cn=hello world", 0 },
+        { "cn=HELLO WORLD", "cn=hello world", 0 },
+        { "cn=HELLO+sn=WORLD", "sn=world+cn=hello", 0 },
+        { "cn=HELLO+sn=WORLD", "cn=hello+sn=nurse", 1 },
+        { "cn=HELLO+sn=WORLD", "cn=howdy+sn=yall", -1 },
+        { "cn=hello", "cn=hello+sn=world", -1 },
+        { "cn=hello+sn=world", "cn=hello", 1 },
+        { "cn=hello+sn=world", "cn=hello+description=world", 1 },
+        { "cn=hello", "sn=world", -1 },
+        { "sn=hello", "cn=world", 1 },
+        // { "x-test-integer-type=10", "x-test-integer-type=9", 1 },
+        // { "x-test-integer-type=999", "x-test-integer-type=1000", -1 },
+        // { "x-test-integer-type=-1", "x-test-integer-type=0", -1 },
+        // { "x-test-integer-type=0", "x-test-integer-type=-1", 1 },
+        { "cn=aaa", "cn=aaaa", -1 }, { "cn=AAA", "cn=aaaa", -1 },
+        { "cn=aaa", "cn=AAAA", -1 }, { "cn=aaaa", "cn=aaa", 1 },
+        { "cn=AAAA", "cn=aaa", 1 }, { "cn=aaaa", "cn=AAA", 1 },
+        { "cn=aaab", "cn=aaaa", 1 }, { "cn=aaaa", "cn=aaab", -1 } };
+  }
+
+
+
+  /**
+   * Set up the environment for performing the tests in this suite.
+   *
+   * @throws Exception
+   *           If the environment could not be set up.
+   */
+  @BeforeClass
+  public void setUp() throws Exception
+  {
+    AT_DC = Schema.getCoreSchema().getAttributeType("dc");
+    AT_CN = Schema.getCoreSchema().getAttributeType("cn");
+    // Set the avas.
+    AV_DC_ORG = new AVA(AT_DC, ByteString.valueOf("org"));
+  }
+
+
+
+  /**
+   * Test RDN compareTo
+   *
+   * @param first
+   *          First RDN to compare.
+   * @param second
+   *          Second RDN to compare.
+   * @param result
+   *          Expected comparison result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createRDNEqualityData")
+  public void testCompareTo(final String first, final String second,
+      final int result) throws Exception
+  {
+    final RDN rdn1 = RDN.valueOf(first);
+    final RDN rdn2 = RDN.valueOf(second);
+
+    int rc = rdn1.compareTo(rdn2);
+
+    // Normalize the result.
+    if (rc < 0)
+    {
+      rc = -1;
+    }
+    else if (rc > 0)
+    {
+      rc = 1;
+    }
+
+    assertEquals(rc, result, "Comparison for <" + first + "> and <" + second
+        + ">.");
+  }
+
+
+
+  /**
+   * Test RDN construction with single AVA.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructor() throws Exception
+  {
+    final RDN rdn = new RDN(AT_DC, ORG);
+
+    assertEquals(rdn.size(), 1);
+    assertEquals(rdn.isMultiValued(), false);
+    assertEquals(rdn.getFirstAVA().getAttributeType(), AT_DC);
+    assertEquals(rdn.getFirstAVA().getAttributeType().getNameOrOID(), AT_DC
+        .getNameOrOID());
+    assertEquals(rdn.getFirstAVA(), AV_DC_ORG);
+  }
+
+
+
+  /**
+   * Test RDN construction with String attribute type and value.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorWithString() throws Exception
+  {
+    final RDN rdn = new RDN("dc", "org");
+    assertEquals(rdn.size(), 1);
+    assertEquals(rdn.getFirstAVA().getAttributeType(), AT_DC);
+    assertEquals(rdn.getFirstAVA().getAttributeType().getNameOrOID(), "dc");
+    assertEquals(rdn.getFirstAVA(), AV_DC_ORG);
+  }
+
+
+
+  /**
+   * Test RDN string decoder against illegal strings.
+   *
+   * @param rawRDN
+   *          Illegal RDN string representation.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "illegalRDNs", expectedExceptions = {
+      NullPointerException.class, LocalizedIllegalArgumentException.class,
+      StringIndexOutOfBoundsException.class })
+  public void testDecodeIllegalString(final String rawRDN) throws Exception
+  {
+    RDN.valueOf(rawRDN);
+
+    fail("Expected exception for value \"" + rawRDN + "\"");
+  }
+
+
+
+  /**
+   * Test RDN string decoder.
+   *
+   * @param rawRDN
+   *          Raw RDN string representation.
+   * @param normRDN
+   *          Normalized RDN string representation.
+   * @param stringRDN
+   *          String representation.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  /**
+   * @Test(dataProvider = "testRDNs") public void testToString(String rawRDN,
+   *                    String normRDN, String stringRDN) throws Exception { RDN
+   *                    rdn = RDN.valueOf(rawRDN); assertEquals(rdn.toString(),
+   *                    stringRDN); }
+   **/
+
+  /**
+   * Test RDN string decoder.
+   *
+   * @param rawRDN
+   *          Raw RDN string representation.
+   * @param normRDN
+   *          Normalized RDN string representation.
+   * @param stringRDN
+   *          String representation.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "testRDNs")
+  public void testDecodeString(final String rawRDN, final String normRDN,
+      final String stringRDN) throws Exception
+  {
+    final RDN rdn = RDN.valueOf(rawRDN);
+    final RDN string = RDN.valueOf(stringRDN);
+    assertEquals(rdn, string);
+  }
+
+
+
+  /**
+   * Tests the valueof with ctor.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testDuplicateSingle()
+  {
+    final RDN rdn1 = new RDN(AT_DC, ORG);
+    final RDN rdn2 = RDN.valueOf("dc=org");
+
+    assertFalse(rdn1 == rdn2);
+    assertEquals(rdn1, rdn2);
+  }
+
+
+
+  /**
+   * Test RDN equality
+   *
+   * @param first
+   *          First RDN to compare.
+   * @param second
+   *          Second RDN to compare.
+   * @param result
+   *          Expected comparison result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createRDNEqualityData")
+  public void testEquality(final String first, final String second,
+      final int result) throws Exception
+  {
+    final RDN rdn1 = RDN.valueOf(first);
+    final RDN rdn2 = RDN.valueOf(second);
+
+    if (result == 0)
+    {
+      assertTrue(rdn1.equals(rdn2), "RDN equality for <" + first + "> and <"
+          + second + ">");
+    }
+    else
+    {
+      assertFalse(rdn1.equals(rdn2), "RDN equality for <" + first + "> and <"
+          + second + ">");
+    }
+  }
+
+
+
+  /**
+   * Tests the equals method with a non-RDN argument.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testEqualityNonRDN()
+  {
+    final RDN rdn = new RDN(AT_DC, ORG);
+
+    assertFalse(rdn.equals("this isn't an RDN"));
+  }
+
+
+
+  /**
+   * Tests the equals method with a null argument.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testEqualityNull()
+  {
+    final RDN rdn = new RDN(AT_DC, ORG);
+
+    assertFalse(rdn.equals(null));
+  }
+
+
+
+  /**
+   * Test getAttributeName.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetAttributeName() throws Exception
+  {
+    final RDN rdn = RDN.valueOf("dc=opends+cn=org");
+    assertTrue(rdn.isMultiValued());
+    assertEquals(rdn.size(), 2);
+    final Iterator<AVA> it = rdn.iterator();
+    assertEquals(it.next().getAttributeType().getNameOrOID(), AT_DC
+        .getNameOrOID());
+    assertEquals(it.next().getAttributeType().getNameOrOID(), AT_CN
+        .getNameOrOID());
+  }
+
+
+
+  /**
+   * Test RDN hashCode
+   *
+   * @param first
+   *          First RDN to compare.
+   * @param second
+   *          Second RDN to compare.
+   * @param result
+   *          Expected comparison result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "createRDNEqualityData")
+  public void testHashCode(final String first, final String second,
+      final int result) throws Exception
+  {
+    final RDN rdn1 = RDN.valueOf(first);
+    final RDN rdn2 = RDN.valueOf(second);
+
+    final int h1 = rdn1.hashCode();
+    final int h2 = rdn2.hashCode();
+
+    if (result == 0)
+    {
+      if (h1 != h2)
+      {
+        fail("Hash codes for <" + first + "> and <" + second
+            + "> should be the same.");
+      }
+    }
+    else
+    {
+      if (h1 == h2)
+      {
+        fail("Hash codes for <" + first + "> and <" + second
+            + "> should be the same.");
+      }
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SdkTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SdkTestCase.java
new file mode 100644
index 0000000..92da12a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SdkTestCase.java
@@ -0,0 +1,43 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all types unit tests should extend. A type represents
+ * the classes found directly under the package org.opends.sdk.
+ */
+
+@Test(groups = { "precommit", "types", "sdk" }, sequential = true)
+public abstract class SdkTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SuiteRunner.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SuiteRunner.java
new file mode 100755
index 0000000..1e9fd98
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SuiteRunner.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import org.testng.TestNG;
+
+
+
+/**
+ * This class wraps TestNG so that we can force the process to exit if there is
+ * an uncaught exception (e.g. OutOfMemoryError).
+ */
+public class SuiteRunner
+{
+  public static void main(final String[] args)
+  {
+    try
+    {
+      TestNG.main(args);
+    }
+    catch (final Throwable e)
+    {
+      System.err.println("TestNG.main threw an expected exception:");
+      e.printStackTrace(System.err);
+      System.exit(TestNG.HAS_FAILURE);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SynchronousConnectionTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SynchronousConnectionTestCase.java
new file mode 100644
index 0000000..2a6bba7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/SynchronousConnectionTestCase.java
@@ -0,0 +1,182 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.NoSuchElementException;
+
+import org.opends.sdk.ldif.ConnectionEntryReader;
+import org.opends.sdk.requests.Requests;
+import org.opends.sdk.responses.BindResult;
+import org.opends.sdk.responses.CompareResult;
+import org.opends.sdk.responses.Result;
+import org.opends.sdk.responses.SearchResultEntry;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class tests the Synchronous Connection API.
+ */
+public class SynchronousConnectionTestCase extends TypesTestCase
+{
+  private AsynchronousConnection asyncCon;
+
+
+
+  /**
+   * Ensures that the LDAP Server is running.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer() throws Exception
+  {
+    TestCaseUtils.startServer();
+    final ConnectionFactory factory = Connections.newInternalConnectionFactory(
+        LDAPServer.getInstance(), null);
+    asyncCon = factory.getAsynchronousConnection(null).get();
+  }
+
+
+
+  /**
+   * Ensures that the LDAP server is stopped.
+   */
+  @AfterClass()
+  public void stopServer()
+  {
+    asyncCon.close();
+    // Don't stop the server as some futures might get stuck.
+    // TestCaseUtils.stopServer();
+  }
+
+
+
+  /**
+   * Tests the ADD request.
+   *
+   * @throws Exception
+   */
+  @Test()
+  public void testAddRequest() throws Exception
+  {
+    final SynchronousConnection con = new SynchronousConnection(asyncCon);
+    final Result result = con.add(Requests.newAddRequest(DN.valueOf(""
+        + "uid=syncconnectiontestcase,ou=people,o=test")));
+    assertTrue(result.isSuccess());
+  }
+
+
+
+  /**
+   * Tests the BIND request.
+   *
+   * @throws Exception
+   */
+  @Test()
+  public void testBindRequest() throws Exception
+  {
+    final SynchronousConnection con = new SynchronousConnection(asyncCon);
+    final BindResult result = con.bind(Requests.newSimpleBindRequest());
+    assertTrue(result.isSuccess());
+  }
+
+
+
+  /**
+   * Tests the COMPARE request.
+   *
+   * @throws Exception
+   */
+  @Test()
+  public void testCompareRequest() throws Exception
+  {
+    final SynchronousConnection con = new SynchronousConnection(asyncCon);
+    final CompareResult result = con.compare("uid=user.0,ou=people,o=test",
+        "uid", "user.0");
+    assertTrue(result.matched());
+  }
+
+
+
+  /**
+   * Tests the ctor.
+   *
+   * @throws Exception
+   */
+  @Test()
+  public void testCtor() throws Exception
+  {
+    final SynchronousConnection con = new SynchronousConnection(asyncCon);
+    assertFalse(con.isClosed());
+  }
+
+
+
+  /**
+   * Tests the SEARCH request.
+   *
+   * @throws Exception
+   */
+  @Test()
+  public void testSearchRequest() throws Exception
+  {
+    final SynchronousConnection con = new SynchronousConnection(asyncCon);
+    final ConnectionEntryReader reader = con.search(
+        "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT,
+        "objectclass=*", "cn");
+    Assert.assertTrue(reader.hasNext());
+    Assert.assertFalse(reader.isReference());
+    Assert.assertTrue(reader.hasNext());
+    SearchResultEntry entry = reader.readEntry();
+    Assert.assertEquals(entry.getName(),
+        DN.valueOf("uid=user.0,ou=people,o=test"));
+    Assert.assertFalse(reader.hasNext());
+    try
+    {
+      reader.readEntry();
+      Assert
+          .fail("reader.readEntry() should have thrown NoSuchElementException");
+    }
+    catch (NoSuchElementException e)
+    {
+      // This is expected.
+    }
+    Assert.assertFalse(reader.hasNext());
+  }
+  // TODO: add more tests.
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestCaseUtils.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestCaseUtils.java
new file mode 100644
index 0000000..4d8fc28
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestCaseUtils.java
@@ -0,0 +1,175 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk;
+
+
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+
+
+
+/**
+ * This class defines some utility functions which can be used by test cases.
+ */
+public final class TestCaseUtils
+{
+  /**
+   * The name of the system property that specifies the ldap port. Set this
+   * property when running the server if you want to use a given port number,
+   * otherwise a port is chosen randomly at test startup time.
+   */
+  public static final String PROPERTY_LDAP_PORT = "org.opends.server.LdapPort";
+
+  /**
+   * Port number that's used by the server. Need to be used by the test cases to
+   * create connections.
+   */
+  public static int port;
+
+  static
+  {
+    final String ldapPort = System.getProperty(PROPERTY_LDAP_PORT);
+    if (ldapPort != null)
+    {
+      port = Integer.valueOf(ldapPort);
+    }
+    else
+    {
+      port = findFreePort();
+    }
+  }
+
+
+
+  /**
+   * Creates a temporary text file with the specified contents. It will be
+   * marked for automatic deletion when the JVM exits.
+   *
+   * @param lines
+   *          The file contents.
+   * @return The absolute path to the file that was created.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  public static String createTempFile(final String... lines) throws Exception
+  {
+    final File f = File.createTempFile("LDIFBasedTestCase", ".txt");
+    f.deleteOnExit();
+
+    final FileWriter w = new FileWriter(f);
+    for (final String s : lines)
+    {
+      w.write(s + System.getProperty("line.separator"));
+    }
+
+    w.close();
+
+    return f.getAbsolutePath();
+  }
+
+
+
+  /**
+   * Finds a free server socket port on the local host.
+   *
+   * @return The free port.
+   */
+  public static int findFreePort()
+  {
+    int port;
+    try
+    {
+      ServerSocket serverLdapSocket = new ServerSocket();
+      serverLdapSocket.setReuseAddress(true);
+      serverLdapSocket.bind(new InetSocketAddress("127.0.0.1", 0));
+      port = serverLdapSocket.getLocalPort();
+      serverLdapSocket.close();
+    }
+    catch (IOException e)
+    {
+      throw new RuntimeException(e);
+    }
+    return port;
+  }
+
+
+
+  /**
+   * Returns an internal client connection to the running ldap server.
+   *
+   * @return The internal client connection.
+   * @throws Exception
+   *           When an error occurs.
+   */
+  public static Connection getInternalConnection() throws Exception
+  {
+    startServer();
+    final ConnectionFactory factory = Connections.newInternalConnectionFactory(
+        LDAPServer.getInstance(), null);
+    return factory.getConnection();
+  }
+
+
+
+  /**
+   * Returns the port which the test server listens on.
+   *
+   * @return The LDAP port.
+   */
+  public static int getLdapPort()
+  {
+    return port;
+  }
+
+
+
+  /**
+   * Starts the test ldap server.
+   *
+   * @throws Exception
+   *           If an error occurs when starting the server.
+   */
+  public static void startServer() throws Exception
+  {
+    LDAPServer.getInstance().start(port);
+  }
+
+
+
+  /**
+   * Stops the test ldap server.
+   */
+  public static void stopServer()
+  {
+    LDAPServer.getInstance().stop();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestListener.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestListener.java
new file mode 100755
index 0000000..a95a92b
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TestListener.java
@@ -0,0 +1,1429 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2008 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import static com.sun.opends.sdk.util.StaticUtils.EOL;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import org.testng.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.xml.XmlSuite;
+
+
+
+/**
+ * This class is our replacement for the test results that TestNG generates. It
+ * prints out test to the console as they happen.
+ */
+public class TestListener extends TestListenerAdapter implements IReporter
+{
+
+  /**
+   *
+   */
+  private static class TestClassResults
+  {
+    private final IClass _cls;
+
+    private final LinkedHashMap<ITestNGMethod, TestMethodResults> _methods = new LinkedHashMap<ITestNGMethod, TestMethodResults>();
+
+    private int _totalInvocations = 0;
+
+    private long _totalDurationMs = 0;
+
+    // Indexed by SUCCESS, FAILURE, SKIP, SUCCESS_PERCENTAGE_FAILURE
+    private final int[] _resultCounts = new int[STATUSES.length];
+
+
+
+    public TestClassResults(final IClass cls)
+    {
+      _cls = cls;
+    }
+
+
+
+    synchronized void addTestResult(final ITestResult result)
+    {
+      _totalInvocations++;
+      _totalDurationMs += result.getEndMillis() - result.getStartMillis();
+
+      getResultsForMethod(result.getMethod()).addTestResult(result);
+      int status = result.getStatus();
+      if (status < 0 || status >= _resultCounts.length)
+      {
+        status = 0;
+      }
+      _resultCounts[status]++;
+    }
+
+
+
+    synchronized Collection<TestMethodResults> getAllMethodResults()
+    {
+      return _methods.values();
+    }
+
+
+
+    synchronized void getSummaryTimingInfo(final StringBuilder timingOutput)
+    {
+      timingOutput.append(_cls.getRealClass().getName() + "    ");
+      timingOutput.append(getTotalDurationMs() + " ms" + " ("
+          + getTotalInvocations() + ")");
+    }
+
+
+
+    synchronized void getTimingInfo(final StringBuilder timingOutput)
+    {
+      getSummaryTimingInfo(timingOutput);
+      timingOutput.append(EOL);
+      for (final TestMethodResults results : getAllMethodResults())
+      {
+        results.getTimingInfo(timingOutput, false);
+      }
+
+      timingOutput.append(EOL);
+    }
+
+
+
+    long getTotalDurationMs()
+    {
+      return _totalDurationMs;
+    }
+
+
+
+    int getTotalInvocations()
+    {
+      return _totalInvocations;
+    }
+
+
+
+    private TestMethodResults getResultsForMethod(final ITestNGMethod method)
+    {
+      TestMethodResults results = _methods.get(method);
+      if (results == null)
+      {
+        results = new TestMethodResults(method);
+        _methods.put(method, results);
+      }
+      return results;
+    }
+  }
+
+
+
+  /**
+   *
+   */
+  private static class TestMethodResults
+  {
+    private final ITestNGMethod _method;
+
+    int _totalInvocations = 0;
+
+    long _totalDurationMs = 0;
+
+    // Indexed by SUCCESS, FAILURE, SKIP, SUCCESS_PERCENTAGE_FAILURE
+    private final int[] _resultCounts = new int[STATUSES.length];
+
+
+
+    public TestMethodResults(final ITestNGMethod method)
+    {
+      _method = method;
+    }
+
+
+
+    synchronized void addTestResult(final ITestResult result)
+    {
+      _totalInvocations++;
+      _totalDurationMs += result.getEndMillis() - result.getStartMillis();
+
+      int status = result.getStatus();
+      if (status < 0 || status >= _resultCounts.length)
+      {
+        status = 0;
+      }
+      _resultCounts[status]++;
+    }
+
+
+
+    synchronized void getTimingInfo(final StringBuilder timingOutput,
+        final boolean includeClassName)
+    {
+      timingOutput.append("    ");
+      if (includeClassName)
+      {
+        timingOutput.append(_method.getRealClass().getName()).append("#");
+      }
+      timingOutput.append(_method.getMethodName() + "  ");
+      timingOutput.append(_totalDurationMs + " ms" + " (" + _totalInvocations
+          + ")");
+      if (_resultCounts[ITestResult.FAILURE] > 0)
+      {
+        timingOutput.append(" " + _resultCounts[ITestResult.FAILURE]
+            + " failure(s)");
+      }
+      timingOutput.append(EOL);
+    }
+  }
+
+
+
+  public static final String REPORT_FILE_NAME = "results.txt";
+
+  // This is used to communicate with build.xml. So that even when a
+  // test
+  // fails, we can do the coverage report before failing the build.
+  public static final String ANT_TESTS_FAILED_FILE_NAME = ".tests-failed-marker";
+
+  private final StringBuilder _bufferedTestFailures = new StringBuilder();
+
+  public static final String PROPERTY_TEST_PROGRESS = "test.progress";
+
+  public static final String TEST_PROGRESS_NONE = "none";
+
+  public static final String TEST_PROGRESS_ALL = "all";
+
+  public static final String TEST_PROGRESS_DEFAULT = "default";
+
+  public static final String TEST_PROGRESS_TIME = "time";
+
+  public static final String TEST_PROGRESS_TEST_COUNT = "count";
+
+  // for
+  // now,
+  // since
+  // it's
+  // not
+  // useful
+  // to
+  // most
+  // developers
+
+  public static final String TEST_PROGRESS_MEMORY = "memory";
+
+  public static final String TEST_PROGRESS_MEMORY_GCS = "gcs"; // Hidden
+
+  public static final String TEST_PROGRESS_THREAD_COUNT = "threadcount";
+
+  public static final String TEST_PROGRESS_THREAD_CHANGES = "threadchanges";
+
+  private boolean doProgressNone = false;
+
+  private boolean doProgressTime = true;
+
+  private boolean doProgressTestCount = true;
+
+  private boolean doProgressMemory = false;
+
+  private boolean doProgressMemoryGcs = false;
+
+  private boolean doProgressThreadCount = false;
+
+  private boolean doProgressThreadChanges = false;
+
+  private static final String DIVIDER_LINE = "-------------------------------------------------------------------------------"
+      + EOL;
+
+  private final static int PAGE_WIDTH = 80;
+
+
+
+  public static void pauseOnFailure()
+  {
+    File tempFile = null;
+    try
+    {
+      tempFile = File.createTempFile("testfailure", "watchdog");
+      tempFile.deleteOnExit();
+      System.err.println("**** Pausing test execution until file "
+          + tempFile.getCanonicalPath() + " is removed.");
+    }
+    catch (final Exception e)
+    {
+      System.err.println("**** ERROR:  Could not create a watchdog "
+          + "file.  Pausing test execution indefinitely.");
+      System.err.println("**** You will have to manually kill the "
+          + "JVM when you're done investigating the problem.");
+    }
+
+    while ((tempFile != null) && tempFile.exists())
+    {
+      try
+      {
+        Thread.sleep(100);
+      }
+      catch (final Exception e)
+      {
+      }
+    }
+
+    System.err.println("**** Watchdog file removed.  Resuming test "
+        + "case execution.");
+  }
+
+
+
+  /**
+   * Return a String representation of all of the current threads.
+   *
+   * @return a dump of all Threads on the server
+   */
+  public static String threadStacksToString()
+  {
+    final Map<Thread, StackTraceElement[]> threadStacks = Thread
+        .getAllStackTraces();
+
+    // Re-arrange all of the elements by thread ID so that there is some
+    // logical
+    // order.
+    final TreeMap<Long, Map.Entry<Thread, StackTraceElement[]>> orderedStacks = new TreeMap<Long, Map.Entry<Thread, StackTraceElement[]>>();
+    for (final Map.Entry<Thread, StackTraceElement[]> e : threadStacks
+        .entrySet())
+    {
+      orderedStacks.put(e.getKey().getId(), e);
+    }
+
+    final StringBuilder buffer = new StringBuilder();
+    for (final Map.Entry<Thread, StackTraceElement[]> e : orderedStacks
+        .values())
+    {
+      final Thread t = e.getKey();
+      final StackTraceElement[] stackElements = e.getValue();
+
+      final long id = t.getId();
+
+      buffer.append("id=");
+      buffer.append(id);
+      buffer.append(" ---------- ");
+      buffer.append(t.getName());
+      buffer.append(" ----------");
+      buffer.append(EOL);
+
+      if (stackElements != null)
+      {
+        for (final StackTraceElement stackElement : stackElements)
+        {
+          buffer.append("   ").append(stackElement.getClassName());
+          buffer.append(".");
+          buffer.append(stackElement.getMethodName());
+          buffer.append("(");
+          buffer.append(stackElement.getFileName());
+          buffer.append(":");
+          if (stackElement.isNativeMethod())
+          {
+            buffer.append("native");
+          }
+          else
+          {
+            buffer.append(stackElement.getLineNumber());
+          }
+          buffer.append(")").append(EOL);
+        }
+      }
+      buffer.append(EOL);
+    }
+
+    return buffer.toString();
+  }
+
+
+
+  private static String center(final String header)
+  {
+    final StringBuilder buffer = new StringBuilder();
+    final int indent = (PAGE_WIDTH - header.length()) / 2;
+    for (int i = 0; i < indent; i++)
+    {
+      buffer.append(" ");
+    }
+    buffer.append(header);
+    return buffer.toString();
+  }
+
+
+
+  private final Set<Class<?>> _checkedForTypeAndAnnotations = new HashSet<Class<?>>();
+
+  private final LinkedHashSet<Class<?>> _classesWithTestsRunInterleaved = new LinkedHashSet<Class<?>>();
+
+  private Object _lastTestObject = null;
+
+  private final IdentityHashMap<Object, Object> _previousTestObjects = new IdentityHashMap<Object, Object>();
+
+  private final Set<Method> _checkedForAnnotation = new HashSet<Method>();
+
+  private boolean statusHeaderPrinted = false;
+
+  private final long startTimeMs = System.currentTimeMillis();
+
+  private long prevTimeMs = System.currentTimeMillis();
+
+  private List<String> prevThreads = new ArrayList<String>();
+
+  private long prevMemInUse = 0;
+
+  private long maxMemInUse = 0;
+
+  private final LinkedHashMap<IClass, TestClassResults> _classResults = new LinkedHashMap<IClass, TestClassResults>();
+
+  private static final int NUM_SLOWEST_METHODS = 100;
+
+  private final static String[] STATUSES = { "<<invalid>>", "Success",
+      "Failure", "Skip", "Success Percentage Failure" };
+
+
+
+  public TestListener() throws Exception
+  {
+    initializeProgressVars();
+  }
+
+
+
+  public void generateReport(final List<XmlSuite> xmlSuites,
+      final List<ISuite> suites, final String outputDirectory)
+  {
+    final File reportFile = new File(outputDirectory, REPORT_FILE_NAME);
+
+    writeReportToFile(reportFile);
+    writeReportToScreen(reportFile);
+    writeAntTestsFailedMarker(outputDirectory);
+  }
+
+
+
+  public void onConfigurationFailure(final ITestResult tr)
+  {
+    super.onConfigurationFailure(tr);
+
+    final IClass cls = tr.getTestClass();
+    final ITestNGMethod method = tr.getMethod();
+
+    final String fqMethod = cls.getName() + "#" + method.getMethodName();
+
+    final StringBuilder failureInfo = new StringBuilder();
+    failureInfo.append("Failed Test:  ").append(fqMethod).append(EOL);
+    // Object[] parameters = tr.getParameters();
+
+    final Throwable cause = tr.getThrowable();
+    if (cause != null)
+    {
+      failureInfo.append("Failure Cause:  ").append(getTestngLessStack(cause));
+    }
+
+    failureInfo.append(EOL + EOL);
+    System.err.print(EOL + EOL + EOL
+        + "         C O N F I G U R A T I O N   F A I L U R E ! ! !" + EOL
+        + EOL);
+    System.err.print(failureInfo);
+    System.err.print(DIVIDER_LINE + EOL + EOL);
+
+    _bufferedTestFailures.append(failureInfo);
+  }
+
+
+
+  public void onStart(final ITestContext testContext)
+  {
+    super.onStart(testContext);
+
+    // Delete the previous report if it's there.
+    new File(testContext.getOutputDirectory(), REPORT_FILE_NAME).delete();
+  }
+
+
+
+  public void onTestFailedButWithinSuccessPercentage(final ITestResult tr)
+  {
+    super.onTestFailedButWithinSuccessPercentage(tr);
+    onTestFinished(tr);
+  }
+
+
+
+  public void onTestFailure(final ITestResult tr)
+  {
+    super.onTestFailure(tr);
+
+    final IClass cls = tr.getTestClass();
+    final ITestNGMethod method = tr.getMethod();
+
+    final String fqMethod = cls.getName() + "#" + method.getMethodName();
+
+    final StringBuilder failureInfo = new StringBuilder();
+    failureInfo.append("Failed Test:  ").append(fqMethod).append(EOL);
+    final Object[] parameters = tr.getParameters();
+
+    final Throwable cause = tr.getThrowable();
+    if (cause != null)
+    {
+      failureInfo.append("Failure Cause:  ").append(getTestngLessStack(cause));
+    }
+
+    for (int i = 0; (parameters != null) && (i < parameters.length); i++)
+    {
+      final Object parameter = parameters[i];
+      failureInfo.append("parameter[" + i + "]: ").append(parameter)
+          .append(EOL);
+    }
+
+    failureInfo.append(EOL + EOL);
+    System.err.print(EOL + EOL + EOL
+        + "                 T E S T   F A I L U R E ! ! !" + EOL + EOL);
+    System.err.print(failureInfo);
+    System.err.print(DIVIDER_LINE + EOL + EOL);
+
+    _bufferedTestFailures.append(failureInfo);
+
+    final String pauseStr = System
+        .getProperty("org.opends.test.pauseOnFailure");
+    if ((pauseStr != null) && pauseStr.equalsIgnoreCase("true"))
+    {
+      pauseOnFailure();
+    }
+
+    onTestFinished(tr);
+  }
+
+
+
+  public void onTestSkipped(final ITestResult tr)
+  {
+    super.onTestSkipped(tr);
+    onTestFinished(tr);
+  }
+
+
+
+  public void onTestStart(final ITestResult tr)
+  {
+    super.onTestStart(tr);
+
+    enforceTestClassTypeAndAnnotations(tr);
+    checkForInterleavedBetweenClasses(tr);
+    enforceMethodHasAnnotation(tr);
+  }
+
+
+
+  public void onTestSuccess(final ITestResult tr)
+  {
+    super.onTestSuccess(tr);
+    onTestFinished(tr);
+  }
+
+
+
+  synchronized StringBuilder getTimingInfo()
+  {
+    final StringBuilder timingOutput = new StringBuilder();
+    timingOutput.append(center("TESTS RUN BY CLASS")).append(EOL);
+    timingOutput.append(center("[method-name total-time (total-invocations)]"))
+        .append(EOL + EOL);
+    for (final TestClassResults results : _classResults.values())
+    {
+      results.getTimingInfo(timingOutput);
+    }
+
+    timingOutput.append(EOL + DIVIDER_LINE + DIVIDER_LINE + EOL);
+
+    getSlowestTestsOutput(timingOutput);
+    return timingOutput;
+  }
+
+
+
+  private void addTestResult(final ITestResult result)
+  {
+    getResultsForClass(result.getTestClass()).addTestResult(result);
+
+    // Read the comments in DirectoryServerTestCase to understand what's
+    // going on here.
+    final Object[] testInstances = result.getMethod().getInstances();
+    for (final Object testInstance : testInstances)
+    {
+      if (testInstance instanceof OpenDSTestCase)
+      {
+        final OpenDSTestCase openDSTestCase = (OpenDSTestCase) testInstance;
+        final Object[] parameters = result.getParameters();
+        if (result.getStatus() == ITestResult.SUCCESS)
+        {
+          openDSTestCase.addParamsFromSuccessfulTests(parameters);
+          // This can eat up a bunch of memory for tests that are
+          // expected to throw
+          result.setThrowable(null);
+        }
+        else
+        {
+          openDSTestCase.addParamsFromFailedTest(parameters);
+
+          // When the test finishes later on, we might not have
+          // everything
+          // that we need to print the result (e.g. the Schema for an
+          // Entry
+          // or DN), so go ahead and convert it to a String now.
+          result.setParameters(convertToStringParameters(parameters));
+        }
+      }
+      else
+      {
+        // We already warned about it.
+      }
+    }
+  }
+
+
+
+  private void checkForInterleavedBetweenClasses(final ITestResult tr)
+  {
+    final Object[] testInstances = tr.getMethod().getInstances();
+    // This will almost always have a single element. If it doesn't,
+    // just
+    // skip it.
+    if (testInstances.length != 1)
+    {
+      return;
+    }
+
+    final Object testInstance = testInstances[0];
+
+    // We're running another test on the same test object. Everything is
+    // fine.
+    if (_lastTestObject == testInstance)
+    {
+      return;
+    }
+
+    // Otherwise, we're running a new test, so save the old one.
+    if (_lastTestObject != null)
+    {
+      _previousTestObjects.put(_lastTestObject, _lastTestObject);
+    }
+
+    // Output progress info since we're running a new class
+    outputTestProgress(_lastTestObject);
+
+    // And make sure we don't have a test object that we already ran
+    // tests with.
+    if (_previousTestObjects.containsKey(testInstance))
+    {
+      _classesWithTestsRunInterleaved.add(testInstance.getClass());
+    }
+
+    _lastTestObject = testInstance;
+  }
+
+
+
+  private String[] convertToStringParameters(final Object[] parameters)
+  {
+    if (parameters == null)
+    {
+      return null;
+    }
+
+    final String[] strParams = new String[parameters.length];
+    for (int i = 0; i < parameters.length; i++)
+    {
+      strParams[i] = String.valueOf(parameters[i]).intern();
+    }
+
+    return strParams;
+  }
+
+
+
+  private int countTestMethods()
+  {
+    int count = 0;
+    for (final TestClassResults results : _classResults.values())
+    {
+      count += results._methods.size();
+    }
+    return count;
+  }
+
+
+
+  private int countTestsWithStatus(final int status)
+  {
+    int count = 0;
+    for (final TestClassResults results : _classResults.values())
+    {
+      count += results._resultCounts[status];
+    }
+    return count;
+  }
+
+
+
+  private int countTotalInvocations()
+  {
+    int count = 0;
+    for (final TestClassResults results : _classResults.values())
+    {
+      count += results._totalInvocations;
+    }
+    return count;
+  }
+
+
+
+  private void enforceMethodHasAnnotation(final ITestResult tr)
+  {
+    // Only warn once per method.
+    final Method testMethod = tr.getMethod().getMethod();
+    if (_checkedForAnnotation.contains(testMethod))
+    {
+      return;
+    }
+    _checkedForAnnotation.add(testMethod);
+
+    final Annotation testAnnotation = testMethod.getAnnotation(Test.class);
+    final Annotation dataProviderAnnotation = testMethod
+        .getAnnotation(DataProvider.class);
+
+    if ((testAnnotation == null) && (dataProviderAnnotation == null))
+    {
+      final String errorMessage = "The test method "
+          + testMethod
+          + " does not have a @Test annotation.  "
+          + "However, TestNG assumes it is a test method because it's a public method "
+          + "in a class with a class-level @Test annotation.  You can remove this warning by either "
+          + "marking the method with @Test or by making it non-public.";
+      System.err.println("\n\nWARNING: " + errorMessage + "\n\n");
+    }
+  }
+
+
+
+  private void enforceTestClassTypeAndAnnotations(final ITestResult tr)
+  {
+    Class<?> testClass = null;
+    testClass = tr.getMethod().getRealClass();
+
+    // Only warn once per class.
+    if (_checkedForTypeAndAnnotations.contains(testClass))
+    {
+      return;
+    }
+    _checkedForTypeAndAnnotations.add(testClass);
+
+    if (!OpenDSTestCase.class.isAssignableFrom(testClass))
+    {
+      final String errorMessage = "The test class " + testClass.getName()
+          + " must inherit (directly or indirectly) "
+          + "from DirectoryServerTestCase.";
+      System.err.println("\n\nERROR: " + errorMessage + "\n\n");
+      throw new RuntimeException(errorMessage);
+    }
+
+    final Class<?> classWithTestAnnotation = findClassWithTestAnnotation(testClass);
+
+    if (classWithTestAnnotation == null)
+    {
+      final String errorMessage = "The test class "
+          + testClass.getName()
+          + " does not have a @Test annotation.  "
+          + "All test classes must have a @Test annotation, and this annotation must have "
+          + "sequential=true set to ensure that tests for a single class are run together.";
+      System.err.println("\n\nERROR: " + errorMessage + "\n\n");
+      throw new RuntimeException(errorMessage);
+    }
+
+    final Test testAnnotation = classWithTestAnnotation
+        .getAnnotation(Test.class);
+    if (!testAnnotation.sequential())
+    {
+      // Give an error message that is as specific as possible.
+      final String errorMessage = "The @Test annotation for class "
+          + testClass.getName()
+          + (classWithTestAnnotation.equals(testClass) ? " "
+              : (", which is declared by class "
+                  + classWithTestAnnotation.getName() + ", "))
+          + "must include sequential=true to ensure that tests for a single class are run together.";
+      System.err.println("\n\nERROR: " + errorMessage + "\n\n");
+      throw new RuntimeException(errorMessage);
+    }
+  }
+
+
+
+  // Return the class in cls's inheritence hierarchy that has the @Test
+  // annotation defined.
+  private Class<?> findClassWithTestAnnotation(Class<?> cls)
+  {
+    while (cls != null)
+    {
+      if (cls.getAnnotation(Test.class) != null)
+      {
+        return cls;
+      }
+      else
+      {
+        cls = cls.getSuperclass();
+      }
+    }
+    return null;
+  }
+
+
+
+  synchronized private List<TestMethodResults> getAllMethodResults()
+  {
+    final List<TestMethodResults> allResults = new ArrayList<TestMethodResults>();
+    for (final TestClassResults results : _classResults.values())
+    {
+      allResults.addAll(results.getAllMethodResults());
+    }
+    return allResults;
+  }
+
+
+
+  private List<TestClassResults> getClassesDescendingSortedByDuration()
+  {
+    final List<TestClassResults> allClasses = new ArrayList<TestClassResults>(
+        _classResults.values());
+    Collections.sort(allClasses, new Comparator<TestClassResults>()
+    {
+      public int compare(final TestClassResults o1, final TestClassResults o2)
+      {
+        if (o1._totalDurationMs > o2._totalDurationMs)
+        {
+          return -1;
+        }
+        else if (o1._totalDurationMs < o2._totalDurationMs)
+        {
+          return 1;
+        }
+        else
+        {
+          return 0;
+        }
+      }
+    });
+    return allClasses;
+  }
+
+
+
+  private String getFqMethod(final ITestResult result)
+  {
+    final IClass cls = result.getTestClass();
+    final ITestNGMethod method = result.getMethod();
+
+    return cls.getName() + "#" + method.getMethodName();
+  }
+
+
+
+  private List<TestMethodResults> getMethodsDescendingSortedByDuration()
+  {
+    final List<TestMethodResults> allMethods = getAllMethodResults();
+    Collections.sort(allMethods, new Comparator<TestMethodResults>()
+    {
+      public int compare(final TestMethodResults o1, final TestMethodResults o2)
+      {
+        if (o1._totalDurationMs > o2._totalDurationMs)
+        {
+          return -1;
+        }
+        else if (o1._totalDurationMs < o2._totalDurationMs)
+        {
+          return 1;
+        }
+        else
+        {
+          return 0;
+        }
+      }
+    });
+    return allMethods;
+  }
+
+
+
+  private TestClassResults getResultsForClass(final IClass cls)
+  {
+    TestClassResults results = _classResults.get(cls);
+    if (results == null)
+    {
+      results = new TestClassResults(cls);
+      _classResults.put(cls, results);
+    }
+    return results;
+  }
+
+
+
+  private void getSlowestTestsOutput(final StringBuilder timingOutput)
+  {
+    timingOutput.append(center("CLASS SUMMARY SORTED BY DURATION")).append(EOL);
+    timingOutput.append(center("[class-name total-time (total-invocations)]"))
+        .append(EOL + EOL);
+    final List<TestClassResults> sortedClasses = getClassesDescendingSortedByDuration();
+    for (int i = 0; i < sortedClasses.size(); i++)
+    {
+      final TestClassResults results = sortedClasses.get(i);
+      timingOutput.append("  ");
+      results.getSummaryTimingInfo(timingOutput);
+      timingOutput.append(EOL);
+    }
+
+    timingOutput.append(EOL + DIVIDER_LINE + EOL + EOL);
+    timingOutput.append(center("SLOWEST METHODS")).append(EOL);
+    timingOutput.append(center("[method-name total-time (total-invocations)]"))
+        .append(EOL + EOL);
+    final List<TestMethodResults> sortedMethods = getMethodsDescendingSortedByDuration();
+    for (int i = 0; i < Math.min(sortedMethods.size(), NUM_SLOWEST_METHODS); i++)
+    {
+      final TestMethodResults results = sortedMethods.get(i);
+      results.getTimingInfo(timingOutput, true);
+    }
+  }
+
+
+
+  private String getTestngLessStack(final Throwable t)
+  {
+    final StackTraceElement[] elements = t.getStackTrace();
+
+    int lowestOpenDSFrame;
+    for (lowestOpenDSFrame = elements.length - 1; lowestOpenDSFrame >= 0; lowestOpenDSFrame--)
+    {
+      final StackTraceElement element = elements[lowestOpenDSFrame];
+      final String clsName = element.getClassName();
+      if (clsName.startsWith("org.opends.")
+          && !clsName.equals("org.opends.server.SuiteRunner"))
+      {
+        break;
+      }
+    }
+
+    final StringBuilder buffer = new StringBuilder();
+    buffer.append(t).append(EOL);
+    for (int i = 0; i <= lowestOpenDSFrame; i++)
+    {
+      buffer.append("    ").append(elements[i]).append(EOL);
+    }
+
+    final Throwable cause = t.getCause();
+    if (cause instanceof InvocationTargetException)
+    {
+      final InvocationTargetException invocation = ((InvocationTargetException) cause);
+      buffer.append("Invocation Target Exception: "
+          + getTestngLessStack(invocation));
+    }
+
+    return buffer.toString();
+  }
+
+
+
+  private void initializeProgressVars()
+  {
+    String prop = System.getProperty(PROPERTY_TEST_PROGRESS);
+    if (prop == null)
+    {
+      return;
+    }
+
+    prop = prop.toLowerCase();
+    final List<String> progressValues = Arrays.asList(prop
+        .split("\\s*\\W+\\s*"));
+
+    if ((prop.length() == 0) || progressValues.isEmpty())
+    {
+      // Accept the defaults
+    }
+    else if (progressValues.contains(TEST_PROGRESS_NONE))
+    {
+      doProgressNone = true;
+      doProgressTime = false;
+      doProgressTestCount = false;
+      doProgressMemory = false;
+      doProgressMemoryGcs = false;
+      doProgressThreadCount = false;
+      doProgressThreadChanges = false;
+    }
+    else if (progressValues.contains(TEST_PROGRESS_ALL))
+    {
+      doProgressNone = false;
+      doProgressTime = true;
+      doProgressTestCount = true;
+      doProgressMemory = true;
+      doProgressMemoryGcs = true;
+      doProgressThreadCount = true;
+      doProgressThreadChanges = true;
+    }
+    else
+    {
+      doProgressNone = false;
+      doProgressTime = progressValues.contains(TEST_PROGRESS_TIME);
+      doProgressTestCount = progressValues.contains(TEST_PROGRESS_TEST_COUNT);
+      doProgressMemory = progressValues.contains(TEST_PROGRESS_MEMORY);
+      doProgressMemoryGcs = progressValues.contains(TEST_PROGRESS_MEMORY_GCS);
+      doProgressThreadCount = progressValues
+          .contains(TEST_PROGRESS_THREAD_COUNT);
+      doProgressThreadChanges = progressValues
+          .contains(TEST_PROGRESS_THREAD_CHANGES);
+
+      // If we were asked to do the defaults, then restore anything
+      // that's on by default
+      if (progressValues.contains(TEST_PROGRESS_DEFAULT))
+      {
+        doProgressTime = true;
+        doProgressTestCount = true;
+      }
+    }
+  }
+
+
+
+  private List<String> listAllThreadNames()
+  {
+    final Thread currentThread = Thread.currentThread();
+    ThreadGroup topGroup = currentThread.getThreadGroup();
+    while (topGroup.getParent() != null)
+    {
+      topGroup = topGroup.getParent();
+    }
+
+    final Thread threads[] = new Thread[topGroup.activeCount() * 2];
+    final int numThreads = topGroup.enumerate(threads);
+
+    final List<String> activeThreads = new ArrayList<String>();
+    for (int i = 0; i < numThreads; i++)
+    {
+      final Thread thread = threads[i];
+      if (thread.isAlive())
+      {
+        final String fullName = thread.getName();
+        activeThreads.add(fullName);
+      }
+    }
+
+    Collections.sort(activeThreads);
+    return activeThreads;
+  }
+
+
+
+  private void onTestFinished(final ITestResult tr)
+  {
+    // Clear when a test finishes instead before the next one starts
+    // so that we get the output generated by any @BeforeClass method
+    // etc.
+    addTestResult(tr);
+  }
+
+
+
+  private void outputTestProgress(final Object finishedTestObject)
+  {
+    if (doProgressNone)
+    {
+      return;
+    }
+
+    printStatusHeaderOnce();
+
+    if (doProgressTime)
+    {
+      final long curTimeMs = System.currentTimeMillis();
+      final long durationSec = (curTimeMs - startTimeMs) / 1000;
+      final long durationLastMs = curTimeMs - prevTimeMs;
+      System.err.printf("{%2d:%02d (%3.0fs)}  ", (durationSec / 60),
+          (durationSec % 60), (durationLastMs / 1000.0));
+      prevTimeMs = curTimeMs;
+    }
+
+    if (doProgressTestCount)
+    {
+      System.err.printf("{%3dc %4dm %5di %df}  ", _classResults.size(),
+          countTestMethods(), countTotalInvocations(),
+          countTestsWithStatus(ITestResult.FAILURE));
+    }
+
+    if (doProgressMemory)
+    {
+      final Runtime runtime = Runtime.getRuntime();
+      final long beforeGc = System.currentTimeMillis();
+      final int gcs = runGc();
+      final long gcDuration = System.currentTimeMillis() - beforeGc;
+
+      final long totalMemory = runtime.totalMemory();
+      final long freeMemory = runtime.freeMemory();
+      final long curMemInUse = totalMemory - freeMemory;
+      final long memDelta = curMemInUse - prevMemInUse;
+      final double perMegaByte = 1.0 / (1024.0 * 1024.0);
+
+      maxMemInUse = Math.max(maxMemInUse, curMemInUse);
+
+      System.err.printf("{%5.1fMB  %+5.1fMB}  ", curMemInUse * perMegaByte,
+          memDelta * perMegaByte);
+
+      if (doProgressMemoryGcs)
+      {
+        System.err.printf("{%2d gcs  %4.1fs}  ", gcs, gcDuration / 1000.0);
+      }
+      prevMemInUse = curMemInUse;
+    }
+
+    if (doProgressThreadCount)
+    {
+      System.err.printf("{#td %3d}  ", Thread.activeCount());
+    }
+
+    if (finishedTestObject == null)
+    {
+      System.err.println(": starting");
+    }
+    else
+    {
+      final String abbrClass = packageLessClass(finishedTestObject);
+      System.err.printf(": %s ", abbrClass).flush();
+      System.err.println();
+    }
+
+    if (doProgressThreadChanges)
+    {
+      final List<String> currentThreads = listAllThreadNames();
+      final List<String> newThreads = removeExactly(prevThreads, currentThreads);
+      final List<String> oldThreads = removeExactly(currentThreads, prevThreads);
+
+      if (!newThreads.isEmpty())
+      {
+        System.err.println("  Thread changes:");
+        for (int i = 0; i < oldThreads.size(); i++)
+        {
+          final String threadName = oldThreads.get(i);
+          System.err.println("    + " + threadName);
+        }
+        for (int i = 0; i < newThreads.size(); i++)
+        {
+          final String threadName = newThreads.get(i);
+          System.err.println("    - " + threadName);
+        }
+      }
+
+      prevThreads = currentThreads;
+    }
+  }
+
+
+
+  private String packageLessClass(final Object obj)
+  {
+    return obj.getClass().getName().replaceAll(".*\\.", "");
+  }
+
+
+
+  private synchronized void printStatusHeaderOnce()
+  {
+    if (statusHeaderPrinted)
+    {
+      return;
+    }
+    statusHeaderPrinted = true;
+
+    if (doProgressNone)
+    {
+      return;
+    }
+
+    System.err.println();
+    System.err.println("How to read the progressive status info:");
+
+    if (doProgressTime)
+    {
+      System.err
+          .println("  Test duration status: {Total min:sec.  Since last status sec.}");
+    }
+
+    if (doProgressTestCount)
+    {
+      System.err
+          .println("  Test count status:  {# test classes  # test methods  # test method invocations  # test failures}.");
+    }
+
+    if (doProgressMemory)
+    {
+      System.err
+          .println("  Memory usage status: {MB in use  +/-change since last status}");
+    }
+
+    if (doProgressMemoryGcs)
+    {
+      System.err
+          .println("  GCs during status:  {GCs done to settle used memory   time to do it}");
+    }
+
+    if (doProgressThreadCount)
+    {
+      System.err
+          .println("  Thread count status:  {#td number of active threads}");
+    }
+
+    if (doProgressThreadChanges)
+    {
+      System.err
+          .println("  Thread change status: +/- thread name for new or finished threads since last status");
+    }
+
+    System.err.println("  TestClass (the class that just completed)");
+    System.err.println();
+  }
+
+
+
+  /**
+   * Removes toRemove from base. If there are duplicate items in base, then only
+   * one is removed for each item in toRemove.
+   *
+   * @return a new List with base with toRemove items removed from it
+   */
+  private List<String> removeExactly(final List<String> base,
+      final List<String> toRemove)
+  {
+    final List<String> diff = new ArrayList<String>(base);
+    for (int i = 0; i < toRemove.size(); i++)
+    {
+      final String item = toRemove.get(i);
+      diff.remove(item);
+    }
+    return diff;
+  }
+
+
+
+  private int runGc()
+  {
+    final Runtime runtime = Runtime.getRuntime();
+    int numGcs;
+    long curMem = usedMemory();
+    long prevMem = Long.MAX_VALUE;
+    final StringBuilder gcConvergence = new StringBuilder();
+    for (numGcs = 0; (prevMem > curMem) && numGcs < 100; numGcs++)
+    {
+      runtime.runFinalization();
+      runtime.gc();
+      Thread.yield();
+      Thread.yield();
+
+      prevMem = curMem;
+      curMem = usedMemory();
+
+      gcConvergence.append("[" + numGcs + "]: " + (prevMem - curMem)).append(
+          "  ");
+    }
+    return numGcs;
+  }
+
+
+
+  private long usedMemory()
+  {
+    final Runtime runtime = Runtime.getRuntime();
+    return runtime.totalMemory() - runtime.freeMemory();
+  }
+
+
+
+  private void writeAntTestsFailedMarker(final String outputDirectory)
+  {
+    // Signal 'ant' that all of the tests passed by removing this
+    // special file.
+    if ((countTestsWithStatus(ITestResult.FAILURE) == 0)
+        && (countTestsWithStatus(ITestResult.SKIP) == 0))
+    {
+      new File(outputDirectory, ANT_TESTS_FAILED_FILE_NAME).delete();
+    }
+  }
+
+
+
+  private void writeReportToFile(final File reportFile)
+  {
+    PrintStream reportStream = null;
+    try
+    {
+      reportStream = new PrintStream(new FileOutputStream(reportFile));
+    }
+    catch (final FileNotFoundException e)
+    {
+      System.err
+          .println("Could not open "
+              + reportFile
+              + " for writing.  Will write the unit test report to the console instead.");
+      e.printStackTrace(System.err);
+      reportStream = System.err;
+    }
+
+    reportStream.println(center("UNIT TEST REPORT"));
+    reportStream.println(center("----------------") + EOL);
+    reportStream.println("Finished at: " + (new Date()));
+    reportStream.println("# Test classes: " + _classResults.size());
+    reportStream.println("# Test classes interleaved: "
+        + _classesWithTestsRunInterleaved.size());
+    reportStream.println("# Test methods: " + countTestMethods());
+    reportStream.println("# Tests passed: "
+        + countTestsWithStatus(ITestResult.SUCCESS));
+    reportStream.println("# Tests failed: "
+        + countTestsWithStatus(ITestResult.FAILURE));
+    reportStream.println(EOL + DIVIDER_LINE + DIVIDER_LINE + EOL + EOL);
+    reportStream.println(center("TEST CLASSES RUN INTERLEAVED"));
+    reportStream.println(EOL + EOL);
+    for (final Class<?> cls : _classesWithTestsRunInterleaved)
+    {
+      reportStream.println("  " + cls.getName());
+    }
+
+    reportStream.println(EOL + DIVIDER_LINE + DIVIDER_LINE + EOL + EOL);
+    reportStream.println(center("FAILED TESTS"));
+    reportStream.println(EOL + EOL);
+    reportStream.println(_bufferedTestFailures);
+
+    reportStream.println(EOL + DIVIDER_LINE + DIVIDER_LINE + EOL);
+
+    reportStream.println(getTimingInfo());
+
+    reportStream.close();
+
+    if ((countTestsWithStatus(ITestResult.FAILURE) == 0)
+        && (countTestsWithStatus(ITestResult.SKIP) != 0))
+    {
+      System.err
+          .println("There were no explicit test failures, but some tests were skipped (possibly due to errors in @Before* or @After* methods).");
+      System.exit(-1);
+    }
+  }
+
+
+
+  private void writeReportToScreen(final File reportFile)
+  {
+    // HACK: print out status for the last test object
+    outputTestProgress(_lastTestObject);
+
+    final List<ITestResult> failedTests = getFailedTests();
+    final StringBuilder failed = new StringBuilder();
+    for (int i = 0; i < failedTests.size(); i++)
+    {
+      final ITestResult failedTest = failedTests.get(i);
+      final String fqMethod = getFqMethod(failedTest);
+      int numFailures = 1;
+      // Peek ahead to see if we had multiple failures for the same
+      // method
+      // In which case, we list it once with a count of the failures.
+      while (((i + 1) < failedTests.size())
+          && fqMethod.equals(getFqMethod(failedTests.get(i + 1))))
+      {
+        numFailures++;
+        i++;
+      }
+
+      failed.append("  ").append(fqMethod);
+
+      if (numFailures > 1)
+      {
+        failed.append(" (x " + numFailures + ")");
+      }
+
+      failed.append(EOL);
+    }
+
+    if (failed.length() > 0)
+    {
+      System.err.println("The following unit tests failed: ");
+      System.err.println(failed);
+      System.err.println();
+      System.err
+          .println("Include the ant option '-Dtest.failures=true' to rerun only the failed tests.");
+    }
+    else
+    {
+      System.err.println("All of the tests passed.");
+    }
+
+    System.err.println();
+    System.err.println("Wrote full test report to:");
+    System.err.println(reportFile.getAbsolutePath());
+    System.err.println("Test classes run interleaved: "
+        + _classesWithTestsRunInterleaved.size());
+
+    // Try to hard to reclaim as much memory as possible.
+    runGc();
+
+    System.err.printf("Final amount of memory in use: %.1f MB",
+        (usedMemory() / (1024.0 * 1024.0))).println();
+    if (doProgressMemory)
+    {
+      System.err.printf("Maximum amount of memory in use: %.1f MB",
+          (maxMemInUse / (1024.0 * 1024.0))).println();
+    }
+    System.err.println("Final number of threads: " + Thread.activeCount());
+
+    System.err.println();
+
+    if (doProgressThreadChanges)
+    {
+      System.err.print(threadStacksToString());
+    }
+
+    if (_classesWithTestsRunInterleaved.size() > 0)
+    {
+      System.err
+          .println("WARNING:  Some of the test methods for multiple classes "
+              + "were run out of order (i.e. interleaved with other classes).  Either "
+              + "a class doesn't have the sequential=true annotation, which should "
+              + "have been reported already or there has been a regression with TestNG.");
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TypesTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TypesTestCase.java
new file mode 100644
index 0000000..d78ba50
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/TypesTestCase.java
@@ -0,0 +1,156 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk;
+
+
+
+import static org.testng.Assert.assertTrue;
+
+import org.opends.sdk.schema.Schema;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all types unit tests should extend. A type represents
+ * the classes found directly under the package org.opends.sdk.
+ */
+
+@Test(groups = { "precommit", "types", "sdk" }, sequential = true)
+public class TypesTestCase extends SdkTestCase
+{
+  /**
+   * Data provider for attribute descriptions.
+   *
+   * @return
+   */
+  @DataProvider(name = "dataForAttributeDescriptions")
+  public Object[][] dataForAttributeDescriptions()
+  {
+    // Value, type, options, containsOptions("foo")
+    return new Object[][] { { "cn" }, { "CN" }, { "objectClass" },
+        { "cn;foo" }, { "cn;FOO" }, { "cn;bar" }, { "cn;BAR" },
+        { "cn;foo;bar" }, { "cn;FOO;bar" }, };
+  }
+
+
+
+  /**
+   * Data provider for old and new attributes
+   *
+   * @return
+   */
+  @DataProvider(name = "dataForAttributeRename")
+  public Object[][] dataForAttributeRename()
+  {
+    return new Object[][] { { "cn", "cn", true }, { "CN", "cn", true },
+        { "objectClass", "cn", false }, { "cn;foo", "cn", true } };
+  }
+
+
+
+  /**
+   * Tests the attribute renaming method.
+   *
+   * @throws Exception
+   */
+  @Test(dataProvider = "dataForAttributeRename")
+  public void testAttributeRename(final String attr, final String desc,
+      final boolean valid) throws Exception
+  {
+    final AttributeDescription desc1 = AttributeDescription.valueOf(attr,
+        Schema.getCoreSchema());
+    final AttributeDescription desc2 = AttributeDescription.valueOf(desc,
+        Schema.getCoreSchema());
+    final Attribute attr1 = Attributes.emptyAttribute(desc1);
+    try
+    {
+      Attributes.renameAttribute(attr1, desc2);
+    }
+    catch (final Exception e)
+    {
+      if (valid)
+      {
+        // shouldn't have come here.
+        throw e;
+      }
+    }
+  }
+
+
+
+  /**
+   * Tests the empty attribute method.
+   *
+   * @throws Exception
+   */
+  @Test(dataProvider = "dataForAttributeDescriptions")
+  public void testEmptyAttribute(final String attrDesc) throws Exception
+  {
+    final AttributeDescription desc = AttributeDescription.valueOf(attrDesc,
+        Schema.getCoreSchema());
+    final Attribute attr = Attributes.emptyAttribute(desc);
+    assertTrue(attr.isEmpty());
+  }
+
+
+
+  /**
+   * Tests the unmodifiable attribute method.
+   *
+   * @throws Exception
+   */
+  @Test(dataProvider = "dataForAttributeDescriptions", expectedExceptions = UnsupportedOperationException.class)
+  public void testUnmodifiableAttribute(final String attrDesc) throws Exception
+  {
+    final AttributeDescription desc = AttributeDescription.valueOf(attrDesc,
+        Schema.getCoreSchema());
+    final Attribute attr = Attributes.emptyAttribute(desc);
+    attr.add("test"); // should go through.
+    // Make it unmodifiable.
+    final Attribute attr1 = Attributes.unmodifiableAttribute(attr);
+    attr1.add("test");
+  }
+
+
+
+  /**
+   * Tests the unmodifiable entry method.
+   *
+   * @throws Exception
+   */
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testUnmodifiableEntry() throws Exception
+  {
+    final Entry entry = new LinkedHashMapEntry("cn=test");
+    // add a value.
+    entry.clearAttributes();
+    final Entry entry1 = Entries.unmodifiableEntry(entry);
+    entry1.clearAttributes();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ByteSequenceReaderTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ByteSequenceReaderTestCase.java
new file mode 100644
index 0000000..8444b38
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ByteSequenceReaderTestCase.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.asn1;
+
+
+
+import org.opends.sdk.ByteSequenceReader;
+import org.opends.sdk.ByteString;
+
+
+
+/**
+ * Test class for ASN1ByteSequenceReaderTestCase
+ */
+public class ASN1ByteSequenceReaderTestCase extends ASN1ReaderTestCase
+{
+  @Override
+  protected ASN1Reader getReader(final byte[] b, final int maxElementSize)
+  {
+    final ByteSequenceReader reader = ByteString.wrap(b).asReader();
+    return ASN1.getReader(reader, maxElementSize);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1InputStreamReaderTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1InputStreamReaderTestCase.java
new file mode 100644
index 0000000..36db156
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1InputStreamReaderTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+import java.io.ByteArrayInputStream;
+
+
+
+/**
+ * Test class for ASN1InputStreamReader
+ */
+public class ASN1InputStreamReaderTestCase extends ASN1ReaderTestCase
+{
+  @Override
+  protected ASN1Reader getReader(final byte[] b, final int maxElementSize)
+  {
+    final ByteArrayInputStream inStream = new ByteArrayInputStream(b);
+    return new ASN1InputStreamReader(inStream, maxElementSize);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1OutputStreamWriterTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1OutputStreamWriterTestCase.java
new file mode 100644
index 0000000..16ab7fe
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1OutputStreamWriterTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+
+
+/**
+ * Test class for ASN1OutputStreamWriter
+ */
+public class ASN1OutputStreamWriterTestCase extends ASN1WriterTestCase
+{
+  private final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+  private final ASN1Writer writer = new ASN1OutputStreamWriter(outStream);
+
+
+
+  @Override
+  protected byte[] getEncodedBytes()
+  {
+    return outStream.toByteArray();
+  }
+
+
+
+  @Override
+  protected ASN1Reader getReader(final byte[] encodedBytes)
+  {
+    final ByteArrayInputStream inStream = new ByteArrayInputStream(encodedBytes);
+    return new ASN1InputStreamReader(inStream, 0);
+  }
+
+
+
+  @Override
+  protected ASN1Writer getWriter()
+  {
+    outStream.reset();
+    return writer;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ReaderTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ReaderTestCase.java
new file mode 100644
index 0000000..0299f79
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1ReaderTestCase.java
@@ -0,0 +1,922 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract base class for all ASN1Reader test cases.
+ */
+@Test(groups = { "precommit", "asn1", "sdk" }, sequential = true)
+public abstract class ASN1ReaderTestCase extends OpenDSTestCase
+{
+
+  /**
+   * Retrieves the set of byte array values that may be used for testing.
+   *
+   * @return The set of byte array values that may be used for testing.
+   */
+  @DataProvider(name = "byteValues")
+  public Object[][] getByteValues()
+  {
+    final Object[][] array = new Object[256][1];
+    for (int i = 0; i < 256; i++)
+    {
+      array[i] = new Object[] { new byte[] { (byte) (i & 0xFF) } };
+    }
+
+    return array;
+  }
+
+
+
+  /**
+   * Create byte arrays with encoded ASN.1 elements to test decoding them as
+   * octet strings.
+   *
+   * @return A list of byte arrays with encoded ASN.1 elements that can be
+   *         decoded as octet strings.
+   */
+  @DataProvider(name = "elementArrays")
+  public Object[][] getElementArrays()
+  {
+    return new Object[][] {
+        new Object[] { new byte[] { 0x04, 0x00 } },
+        new Object[] { new byte[] { (byte) 0x50, 0x00 } },
+        new Object[] { new byte[] { 0x04, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F } },
+        new Object[] { new byte[] { 0x01, 0x01, 0x00 } },
+        new Object[] { new byte[] { 0x01, 0x01, (byte) 0xFF } },
+        new Object[] { new byte[] { 0x0A, 0x01, 0x00 } },
+        new Object[] { new byte[] { 0x0A, 0x01, 0x01 } },
+        new Object[] { new byte[] { 0x0A, 0x01, 0x7F } },
+        new Object[] { new byte[] { 0x0A, 0x01, (byte) 0x80 } },
+        new Object[] { new byte[] { 0x0A, 0x01, (byte) 0xFF } },
+        new Object[] { new byte[] { 0x0A, 0x02, 0x01, 0x00 } },
+        new Object[] { new byte[] { 0x02, 0x01, 0x00 } },
+        new Object[] { new byte[] { 0x02, 0x01, 0x01 } },
+        new Object[] { new byte[] { 0x02, 0x01, 0x7F } },
+        new Object[] { new byte[] { 0x02, 0x02, 0x00, (byte) 0x80 } },
+        new Object[] { new byte[] { 0x02, 0x02, 0x00, (byte) 0xFF } },
+        new Object[] { new byte[] { 0x02, 0x02, 0x01, 0x00 } },
+        new Object[] { new byte[] { 0x05, 0x00 } },
+        new Object[] { new byte[] { 0x30, 0x00 } },
+        new Object[] { new byte[] { 0x31, 0x00 } },
+        new Object[] { new byte[] { 0x05, (byte) 0x81, 0x00 } },
+        new Object[] { new byte[] { 0x05, (byte) 0x82, 0x00, 0x00 } },
+        new Object[] { new byte[] { 0x05, (byte) 0x83, 0x00, 0x00, 0x00 } },
+        new Object[] { new byte[] { 0x05, (byte) 0x84, 0x00, 0x00, 0x00, 0x00 } }, };
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
+   * with an arry with a zero length that takes multiple bytes to encode.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeExtendedZeroLengthArrayAsNull() throws Exception
+  {
+    final byte[] b = new byte[] { 0x05, (byte) 0x81, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with an array that has less bytes than indicated by the length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLengthMismatchArrayAsBoolean() throws Exception
+  {
+    final byte[] b = { 0x01, 0x01 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * Tests the <CODE>readEnumerated</CODE> method that takes a byte array with a
+   * length mismatch.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLengthMismatchArrayAsEnumerated() throws Exception
+  {
+    final byte[] b = { 0x02, (byte) 0x81, 0x01 };
+    getReader(b, 0).readEnumerated();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a length mismatch.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLengthMismatchArrayAsInteger() throws Exception
+  {
+    final byte[] b = { 0x02, (byte) 0x81, 0x01 };
+    getReader(b, 0).readInteger();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
+   * using an array whose actual length doesn't match with the decoded length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLengthMismatchArrayAsOctetString() throws Exception
+  {
+    final byte[] b = { 0x04, 0x02, 0x00 };
+    getReader(b, 0).readOctetString();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with an array that takes too many bytes to expressthe length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLongLengthArrayAsBoolean() throws Exception
+  {
+    final byte[] b = { 0x01, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * Tests the <CODE>readEnumerated</CODE> method that takes a byte array with a
+   * long length array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLongLengthArrayAsEnumerated() throws Exception
+  {
+    final byte[] b = { 0x02, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
+    getReader(b, 0).readEnumerated();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a long length array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLongLengthArrayAsInteger() throws Exception
+  {
+    final byte[] b = { 0x02, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 };
+    getReader(b, 0).readInteger();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
+   * with an array with a long length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLongLengthArrayAsNull() throws Exception
+  {
+    final byte[] b = new byte[] { 0x05, (byte) 0x85, 0x00, 0x00, 0x00, 0x00,
+        0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
+   * using an array that indicates it takes more than four bytes to encode the
+   * length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLongLengthArrayAsOctetString() throws Exception
+  {
+    final byte[] b = { 0x04, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    getReader(b, 0).readOctetString();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
+   * argument with an array that takes too many bytes to encode the length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLongLengthArrayAsSequence() throws Exception
+  {
+    final byte[] b = { 0x30, (byte) 0x85, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    getReader(b, 0).readStartSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with an array that has an invalid number of bytes in the value.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeLongValueArrayAsBoolean() throws Exception
+  {
+    final byte[] b = { 0x01, 0x02, 0x00, 0x00 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
+   * with an arry with a nonzero length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeNonZeroLengthArrayAsNull() throws Exception
+  {
+    final byte[] b = new byte[] { 0x05, 0x01, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * Tests the <CODE>readOctetString</CODE> method when the max element size is
+   * exceeded.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeOctetStringExceedMaxSize() throws Exception
+  {
+    final byte[] b = new byte[] { 0x04, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F };
+    getReader(b, 3).readOctetString();
+  }
+
+
+
+  /**
+   * Tests the <CODE>readOctetString</CODE> method when the max element size is
+   * exceeded.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeSequenceExceedMaxSize() throws Exception
+  {
+    final byte[] b = new byte[] { 0x30, 0x07, 0x04, 0x05, 0x48, 0x65, 0x6C,
+        0x6C, 0x6F };
+    getReader(b, 3).readOctetString();
+  }
+
+
+
+  /**
+   * Tests to make sure trailing components are ignored if not used.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test
+  public void testDecodeSequenceIncompleteRead() throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    final byte[] b = new byte[] { 0x30, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01,
+        0x01, 0x01, 0x01, 0x00 };
+    final ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    reader.readEndSequence();
+    assertFalse(reader.readBoolean());
+  }
+
+
+
+  /**
+   * Tests to make sure a premature EOF while reading a sub sequence can be
+   * detected.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeSequencePrematureEof() throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    final byte[] b = new byte[] { 0x30, 0x09, 0x01, 0x01, 0x00, 0x01, 0x01,
+        0x00 };
+    final ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    while (reader.hasNextElement())
+    {
+      reader.readBoolean();
+    }
+    reader.readEndSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with a short array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeShortArrayAsBoolean() throws Exception
+  {
+    final byte[] b = new byte[1];
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * Tests the <CODE>readEnumerated</CODE> method that takes a byte array with a
+   * short array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeShortArrayAsEnumerated() throws Exception
+  {
+    final byte[] b = new byte[0];
+    getReader(b, 0).readEnumerated();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a short array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeShortArrayAsInteger() throws Exception
+  {
+    final byte[] b = new byte[0];
+    getReader(b, 0).readInteger();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
+   * with a short array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeShortArrayAsNull() throws Exception
+  {
+    final byte[] b = new byte[1];
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
+   * using a short array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeShortArrayAsOctetString() throws Exception
+  {
+    final byte[] b = new byte[1];
+    getReader(b, 0).readOctetString();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
+   * argument with a short array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeShortArrayAsSequence() throws Exception
+  {
+    final byte[] b = new byte[1];
+    getReader(b, 0).readStartSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with an array that has an invalid number of bytes in the value.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeShortValueArrayAsBoolean() throws Exception
+  {
+    final byte[] b = { 0x01, 0x00, 0x00, 0x00 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with an array that doesn't contain a full length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeTruncatedLengthArrayAsBoolean() throws Exception
+  {
+    final byte[] b = { 0x01, (byte) 0x82, 0x00 };
+    getReader(b, 0).readBoolean();
+  }
+
+
+
+  /**
+   * Tests the <CODE>readEnumerated</CODE> method that takes a byte array with a
+   * truncated length array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeTruncatedLengthArrayAsEnumerated() throws Exception
+  {
+    final byte[] b = { 0x02, (byte) 0x82, 0x00 };
+    getReader(b, 0).readEnumerated();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsInteger</CODE> method that takes a byte array with
+   * a truncated length array.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeTruncatedLengthArrayAsInteger() throws Exception
+  {
+    final byte[] b = { 0x02, (byte) 0x82, 0x00 };
+    getReader(b, 0).readInteger();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
+   * with an array with a truncated length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeTruncatedLengthArrayAsNull() throws Exception
+  {
+    final byte[] b = new byte[] { 0x05, (byte) 0x82, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
+   * using an array that doesn't fully contain the length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeTruncatedLengthArrayAsOctetString() throws Exception
+  {
+    final byte[] b = { 0x04, (byte) 0x82, 0x00 };
+    getReader(b, 0).readOctetString();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
+   * argument with an array that doesn't fully describe the length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testDecodeTruncatedLengthArrayAsSequence() throws Exception
+  {
+    final byte[] b = { 0x30, (byte) 0x82, 0x00 };
+    getReader(b, 0).readStartSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with valid arrays.
+   *
+   * @param b
+   *          The byte array to use for the element values.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "byteValues")
+  public void testDecodeValidArrayAsBoolean(final byte[] b) throws Exception
+  {
+    // First, test with the standard Boolean type.
+    final byte[] elementArray = new byte[] { 0x01, 0x01, b[0] };
+    assertEquals(getReader(elementArray, 0).readBoolean(), (b[0] != 0x00));
+
+    // Next, test with a nonstandard Boolean type.
+    elementArray[0] = (byte) 0x50;
+    assertEquals(getReader(elementArray, 0).readBoolean(), (b[0] != 0x00));
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetString</CODE> method that takes a byte array
+   * using a valid array.
+   *
+   * @param b
+   *          The byte array to decode.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "elementArrays")
+  public void testDecodeValidArrayAsOctetString(final byte[] b)
+      throws Exception
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    bsb.appendBERLength(b.length);
+    bsb.append(b);
+
+    assertEquals(getReader(bsb.toByteArray(), 0).readOctetString(), ByteString
+        .wrap(b));
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetStringAsString</CODE> method that takes a byte
+   * array using a valid array.
+   *
+   * @param b
+   *          The byte array to decode.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "elementArrays")
+  public void testDecodeValidArrayAsOctetStringAsString(final byte[] b)
+      throws Exception
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    bsb.appendBERLength(b.length);
+    bsb.append(b);
+
+    assertEquals(getReader(bsb.toByteArray(), 0).readOctetStringAsString(),
+        new String(b, "UTF-8"));
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetStringAsString</CODE> method that takes a byte
+   * array using a valid array.
+   *
+   * @param b
+   *          The byte array to decode.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "elementArrays")
+  public void testDecodeValidArrayAsOctetStringAsStringCharSet(final byte[] b)
+      throws Exception
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    bsb.appendBERLength(b.length);
+    bsb.append(b);
+
+    assertEquals(getReader(bsb.toByteArray(), 0).readOctetStringAsString(),
+        new String(b, "UTF-8"));
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsOctetStringBuilder</CODE> method that takes a byte
+   * array using a valid array.
+   *
+   * @param b
+   *          The byte array to decode.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "elementArrays")
+  public void testDecodeValidArrayAsOctetStringBuilder(final byte[] b)
+      throws Exception
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    bsb.appendBERLength(b.length);
+    bsb.append(b);
+
+    final ByteStringBuilder bsb2 = new ByteStringBuilder();
+    getReader(bsb.toByteArray(), 0).readOctetString(bsb2);
+    assertEquals(bsb2.toByteString(), ByteString.wrap(b));
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsSequence</CODE> method that takes a byte array
+   * argument with valid arrays.
+   *
+   * @param encodedElements
+   *          Byte arrays that may be used as valid values for encoded elements.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "elementArrays")
+  public void testDecodeValidArrayAsSequence(final byte[] encodedElements)
+      throws Exception
+  {
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+    bsb.append(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
+    bsb.appendBERLength(encodedElements.length + 2);
+    bsb.append(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    bsb.appendBERLength(encodedElements.length);
+    bsb.append(encodedElements);
+
+    final ASN1Reader reader = getReader(bsb.toByteArray(), 0);
+    assertEquals(reader.peekLength(), encodedElements.length + 2);
+    reader.readStartSequence();
+    assertEquals(reader.peekType(), ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
+    assertEquals(reader.peekLength(), encodedElements.length);
+    reader.readOctetString().equals(ByteString.wrap(encodedElements));
+    reader.readEndSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsBoolean</CODE> method that takes a byte array
+   * argument with valid arrays using extended lengths.
+   *
+   * @param b
+   *          The byte array to use for the element values.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "byteValues")
+  public void testDecodeValidExtendedArrayAsBoolean(final byte[] b)
+      throws Exception
+  {
+    // First, test with the standard Boolean type.
+    final byte[] elementArray = new byte[] { 0x01, (byte) 0x81, 0x01, b[0] };
+    assertEquals(getReader(elementArray, 0).readBoolean(), (b[0] != 0x00));
+
+    // Next, test with a nonstandard Boolean type.
+    elementArray[0] = (byte) 0x50;
+    assertEquals(getReader(elementArray, 0).readBoolean(), (b[0] != 0x00));
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeAsNull</CODE> method that takes a byte array argument
+   * with an arry with a zero length.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeZeroLengthArrayAsNull() throws Exception
+  {
+    final byte[] b = new byte[] { 0x05, 0x00 };
+    getReader(b, 0).readNull();
+  }
+
+
+
+  /**
+   * Tests the <CODE>elementAvailable</CODE> method.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test
+  public void testElementAvailable() throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    byte[] b = new byte[] { 0x30, 0x06, 0x02, 0x01, 0x00, 0x02 };
+    ASN1Reader reader = getReader(b, 0);
+    assertFalse(reader.elementAvailable());
+
+    b = new byte[] { 0x30, 0x03, 0x02, 0x01, 0x00 };
+    reader = getReader(b, 0);
+    assertTrue(reader.elementAvailable());
+    reader.readStartSequence();
+    assertTrue(reader.elementAvailable());
+    reader.readInteger();
+    assertFalse(reader.elementAvailable());
+  }
+
+
+
+  /**
+   * Tests the <CODE>hasNextElement</CODE> method.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test
+  public void testHasNextElement() throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    byte[] b = new byte[] { 0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x00, 0x03 };
+    ASN1Reader reader = getReader(b, 0);
+    assertTrue(reader.hasNextElement());
+    reader.readStartSequence();
+    assertTrue(reader.hasNextElement());
+    reader.readInteger();
+    assertTrue(reader.hasNextElement());
+
+    b = new byte[] { 0x30, 0x03, 0x02, 0x01, 0x00 };
+    reader = getReader(b, 0);
+    assertTrue(reader.hasNextElement());
+    reader.readStartSequence();
+    assertTrue(reader.hasNextElement());
+    reader.readInteger();
+    assertFalse(reader.hasNextElement());
+  }
+
+
+
+  /**
+   * Tests the <CODE>readEndSequence</CODE> method without first calling
+   * readStartSequence.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { IllegalStateException.class, IOException.class })
+  public void testReadEndSequenceNoStartSequence() throws Exception
+  {
+    final byte[] b = { 0x30, 0x01, 0x00 };
+    getReader(b, 0).readEndSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>skipElement</CODE> method.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test
+  public void testSkipElement() throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    final byte[] b = new byte[] { 0x30, 0x09, 0x02, 0x01, 0x00, 0x02, 0x01,
+        0x01, 0x02, 0x01, 0x02 };
+    final ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    reader.readInteger();
+    reader.skipElement();
+    assertEquals(reader.readInteger(), 2);
+    reader.readEndSequence();
+  }
+
+
+
+  /**
+   * Tests the <CODE>skipElement</CODE> method.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DecodeException.class, IOException.class })
+  public void testSkipElementIncompleteRead() throws Exception
+  {
+    // An ASN.1 sequence of booleans missing one boolean element at the end
+    final byte[] b = new byte[] { 0x30, 0x09, 0x01, 0x01, 0x00, 0x01, 0x02 };
+    final ASN1Reader reader = getReader(b, 0);
+    reader.readStartSequence();
+    reader.readBoolean();
+    reader.skipElement();
+    reader.readEndSequence();
+  }
+
+
+
+  /**
+   * Gets the reader to be use for the unit tests.
+   *
+   * @param b
+   *          The array of bytes to be read.
+   * @param maxElementSize
+   *          The max element size.
+   * @return The reader to be use for the unit tests.
+   * @throws IOException
+   *           In an unexpected IO exception occurred.
+   */
+  protected abstract ASN1Reader getReader(byte[] b, int maxElementSize)
+      throws IOException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1WriterTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1WriterTestCase.java
new file mode 100644
index 0000000..f43f9f7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/asn1/ASN1WriterTestCase.java
@@ -0,0 +1,742 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.asn1;
+
+
+
+import static org.opends.sdk.asn1.ASN1Constants.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ByteStringBuilder;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.sun.opends.sdk.util.StaticUtils;
+
+
+
+/**
+ * An abstract base class for all ASN1Writer test cases.
+ */
+@Test(groups = { "precommit", "asn1", "sdk" }, sequential = true)
+public abstract class ASN1WriterTestCase extends OpenDSTestCase
+{
+
+  // Create an array with all of the valid single-byte types. We don't
+  // support multi-byte types, so this should be a comprehensive data set.
+  private final byte[] testTypes = new byte[0xFF];
+  {
+    for (int i = 0x00; i < 0xFF; i++)
+    {
+      testTypes[i] = (byte) (i & 0xFF);
+    }
+  }
+
+
+
+  /**
+   * Create byte arrays to use for element values.
+   *
+   * @return A list of byte arrays that can be used as element values.
+   */
+  @DataProvider(name = "binaryValues")
+  public Object[][] getBinaryValues()
+  {
+    // NOTE -- Don't make these arrays too big since they consume memory.
+    return new Object[][] { new Object[] { new byte[0x00] }, // The zero-byte
+        // value
+        new Object[] { new byte[0x01] }, // The single-byte value
+        new Object[] { new byte[0x7F] }, // The largest 1-byte length encoding
+        new Object[] { new byte[0x80] }, // The smallest 2-byte length encoding
+        new Object[] { new byte[0xFF] }, // The largest 2-byte length encoding
+        new Object[] { new byte[0x0100] }, // The smallest 3-byte length
+        // encoding
+        new Object[] { new byte[0xFFFF] }, // The largest 3-byte length encoding
+        new Object[] { new byte[0x010000] } // The smallest 4-byte length
+    // encoding
+    };
+  }
+
+
+
+  /**
+   * Retrieves the set of boolean values that may be used for testing.
+   *
+   * @return The set of boolean values that may be used for testing.
+   */
+  @DataProvider(name = "booleanValues")
+  public Object[][] getBooleanValues()
+  {
+    return new Object[][] { new Object[] { false }, new Object[] { true } };
+  }
+
+
+
+  /**
+   * Retrieves the set of int values that should be used for testing.
+   *
+   * @return The set of int values that should be used for testing.
+   */
+  @DataProvider(name = "intValues")
+  public Object[][] getIntValues()
+  {
+    return new Object[][] { new Object[] { 0x00000000, 1 },
+        new Object[] { 0x00000001, 1 }, new Object[] { 0x0000000F, 1 },
+        new Object[] { 0x00000010, 1 }, new Object[] { 0x0000007F, 1 },
+        new Object[] { 0x00000080, 2 }, new Object[] { 0x000000FF, 2 },
+        new Object[] { 0x00000100, 2 }, new Object[] { 0x00000FFF, 2 },
+        new Object[] { 0x00001000, 2 }, new Object[] { 0x0000FFFF, 3 },
+        new Object[] { 0x00010000, 3 }, new Object[] { 0x000FFFFF, 3 },
+        new Object[] { 0x00100000, 3 }, new Object[] { 0x00FFFFFF, 4 },
+        new Object[] { 0x01000000, 4 }, new Object[] { 0x0FFFFFFF, 4 },
+        new Object[] { 0x10000000, 4 }, new Object[] { 0x7FFFFFFF, 4 },
+        new Object[] { -0x00000001, 1 }, new Object[] { -0x0000000F, 1 },
+        new Object[] { -0x00000010, 1 }, new Object[] { -0x0000007F, 1 },
+        new Object[] { -0x00000080, 1 }, new Object[] { -0x000000FF, 2 },
+        new Object[] { -0x00000100, 2 }, new Object[] { -0x00000FFF, 2 },
+        new Object[] { -0x00001000, 2 }, new Object[] { -0x0000FFFF, 3 },
+        new Object[] { -0x00010000, 3 }, new Object[] { -0x000FFFFF, 3 },
+        new Object[] { -0x00100000, 3 }, new Object[] { -0x00FFFFFF, 4 },
+        new Object[] { -0x01000000, 4 }, new Object[] { -0x0FFFFFFF, 4 },
+        new Object[] { -0x10000000, 4 }, new Object[] { -0x7FFFFFFF, 4 },
+        new Object[] { 0x80000000, 4 } };
+  }
+
+
+
+  /**
+   * Retrieves the set of long values that should be used for testing.
+   *
+   * @return The set of long values that should be used for testing.
+   */
+  @DataProvider(name = "longValues")
+  public Object[][] getLongValues()
+  {
+    return new Object[][] { new Object[] { 0x0000000000000000L, 1 },
+        new Object[] { 0x0000000000000001L, 1 },
+        new Object[] { 0x000000000000007FL, 1 },
+        new Object[] { 0x0000000000000080L, 2 },
+        new Object[] { 0x00000000000000FFL, 2 },
+        new Object[] { 0x0000000000000100L, 2 },
+        new Object[] { 0x000000000000FFFFL, 3 },
+        new Object[] { 0x0000000000010000L, 3 },
+        new Object[] { 0x0000000000FFFFFFL, 4 },
+        new Object[] { 0x0000000001000000L, 4 },
+        new Object[] { 0x00000000FFFFFFFFL, 5 },
+        new Object[] { 0x0000000100000000L, 5 },
+        new Object[] { 0x000000FFFFFFFFFFL, 6 },
+        new Object[] { 0x0000010000000000L, 6 },
+        new Object[] { 0x0000FFFFFFFFFFFFL, 7 },
+        new Object[] { 0x0001000000000000L, 7 },
+        new Object[] { 0x00FFFFFFFFFFFFFFL, 8 },
+        new Object[] { 0x0100000000000000L, 8 },
+        new Object[] { 0x7FFFFFFFFFFFFFFFL, 8 },
+        new Object[] { -0x0000000000000001L, 1 },
+        new Object[] { -0x000000000000007FL, 1 },
+        new Object[] { -0x0000000000000080L, 1 },
+        new Object[] { -0x00000000000000FFL, 2 },
+        new Object[] { -0x0000000000000100L, 2 },
+        new Object[] { -0x000000000000FFFFL, 3 },
+        new Object[] { -0x0000000000010000L, 3 },
+        new Object[] { -0x0000000000FFFFFFL, 4 },
+        new Object[] { -0x0000000001000000L, 4 },
+        new Object[] { -0x00000000FFFFFFFFL, 5 },
+        new Object[] { -0x0000000100000000L, 5 },
+        new Object[] { -0x000000FFFFFFFFFFL, 6 },
+        new Object[] { -0x0000010000000000L, 6 },
+        new Object[] { -0x0000FFFFFFFFFFFFL, 7 },
+        new Object[] { -0x0001000000000000L, 7 },
+        new Object[] { -0x00FFFFFFFFFFFFFFL, 8 },
+        new Object[] { -0x0100000000000000L, 8 },
+        new Object[] { -0x7FFFFFFFFFFFFFFFL, 8 },
+        new Object[] { 0x8000000000000000L, 8 } };
+  }
+
+
+
+  /**
+   * Create strings to use for element values.
+   *
+   * @return A list of strings that can be used as element values.
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @DataProvider(name = "stringValues")
+  public Object[][] getStringValues() throws Exception
+  {
+    return new Object[][] { new Object[] { null }, new Object[] { "" },
+        new Object[] { "\u0000" }, new Object[] { "\t" },
+        new Object[] { "\n" }, new Object[] { "\r\n" }, new Object[] { " " },
+        new Object[] { "a" }, new Object[] { "Test1\tTest2\tTest3" },
+        new Object[] { "Test1\nTest2\nTest3" },
+        new Object[] { "Test1\r\nTest2\r\nTest3" },
+        new Object[] { "The Quick Brown Fox Jumps Over The Lazy Dog" },
+        new Object[] { "\u00BFD\u00F3nde est\u00E1 el ba\u00F1o?" } };
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readBoolean</CODE> methods.
+   *
+   * @param b
+   *          The boolean value to use in the test.
+   */
+  @Test(dataProvider = "booleanValues")
+  public void testEncodeDecodeBoolean(final boolean b) throws Exception
+  {
+    getWriter().writeBoolean(b);
+
+    final ASN1Reader r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), 1);
+    assertEquals(r.peekType(), UNIVERSAL_BOOLEAN_TYPE);
+    assertEquals(r.readBoolean(), b);
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readBoolean</CODE> methods.
+   *
+   * @param b
+   *          The boolean value to use in the test.
+   */
+  @Test(dataProvider = "booleanValues")
+  public void testEncodeDecodeBooleanType(final boolean b) throws Exception
+  {
+    for (final byte type : testTypes)
+    {
+      getWriter().writeBoolean(type, b);
+
+      final ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), 1);
+      assertEquals(r.peekType(), type);
+      assertEquals(r.readBoolean(), b);
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readInteger</CODE> methods with Java ints.
+   *
+   * @param i
+   *          The integer value to use for the test.
+   */
+  @Test(dataProvider = "intValues")
+  public void testEncodeDecodeEnuerated(final int i, final int length)
+      throws Exception
+  {
+    getWriter().writeEnumerated(i);
+
+    final ASN1Reader r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), length);
+    assertEquals(r.peekType(), UNIVERSAL_ENUMERATED_TYPE);
+    assertEquals(r.readInteger(), i);
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readInteger</CODE> methods with Java ints.
+   *
+   * @param i
+   *          The integer value to use for the test.
+   */
+  @Test(dataProvider = "intValues")
+  public void testEncodeDecodeInteger(final int i, final int length)
+      throws Exception
+  {
+    getWriter().writeInteger(i);
+
+    final ASN1Reader r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), length);
+    assertEquals(r.peekType(), UNIVERSAL_INTEGER_TYPE);
+    assertEquals(r.readInteger(), i);
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readInteger</CODE> methods with Java longs.
+   *
+   * @param l
+   *          The long value to use for the test.
+   */
+  @Test(dataProvider = "longValues")
+  public void testEncodeDecodeInteger(final long l, final int length)
+      throws Exception
+  {
+    getWriter().writeInteger(l);
+
+    final ASN1Reader r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), length);
+    assertEquals(r.peekType(), UNIVERSAL_INTEGER_TYPE);
+    assertEquals(r.readInteger(), l);
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readInteger</CODE> methods with Java ints.
+   *
+   * @param i
+   *          The integer value to use for the test.
+   */
+  @Test(dataProvider = "intValues")
+  public void testEncodeDecodeIntegerType(final int i, final int length)
+      throws Exception
+  {
+    for (final byte type : testTypes)
+    {
+      getWriter().writeInteger(type, i);
+
+      final ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), length);
+      assertEquals(r.peekType(), type);
+      assertEquals(r.readInteger(), i);
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readInteger</CODE> methods wiht JavaLongs.
+   *
+   * @param l
+   *          The long value to use for the test.
+   */
+  @Test(dataProvider = "longValues")
+  public void testEncodeDecodeIntegerType(final long l, final int length)
+      throws Exception
+  {
+    for (final byte type : testTypes)
+    {
+      getWriter().writeInteger(type, l);
+
+      final ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), length);
+      assertEquals(r.peekType(), type);
+      assertEquals(r.readInteger(), l);
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readNull</CODE> methods.
+   */
+  @Test
+  public void testEncodeDecodeNull() throws Exception
+  {
+    getWriter().writeNull();
+
+    final ASN1Reader r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), 0);
+    assertEquals(r.peekType(), UNIVERSAL_NULL_TYPE);
+    r.readNull();
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readNull</CODE> methods.
+   */
+  @Test
+  public void testEncodeDecodeNullType() throws Exception
+  {
+    for (final byte type : testTypes)
+    {
+      getWriter().writeNull(type);
+
+      final ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), 0);
+      assertEquals(r.peekType(), type);
+      r.readNull();
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readOctetString</CODE> methods.
+   */
+  @Test(dataProvider = "binaryValues")
+  public void testEncodeDecodeOctetString(final byte[] b) throws Exception
+  {
+    final ByteString bs = ByteString.wrap(b);
+
+    getWriter().writeOctetString(bs);
+
+    ASN1Reader r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), b.length);
+    assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
+    assertTrue(bs.equals(r.readOctetString()));
+
+    getWriter().writeOctetString(b, 0, b.length);
+
+    r = getReader(getEncodedBytes());
+    assertEquals(r.peekLength(), b.length);
+    assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
+    assertTrue(bs.equals(r.readOctetString()));
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readOctetString</CODE> methods.
+   */
+  @Test(dataProvider = "stringValues")
+  public void testEncodeDecodeOctetString(final String s) throws Exception
+  {
+    getWriter().writeOctetString(s);
+
+    final ASN1Reader r = getReader(getEncodedBytes());
+    if (s == null)
+    {
+      assertEquals(r.peekLength(), 0);
+    }
+    else
+    {
+      assertEquals(r.peekLength(), StaticUtils.getBytes(s).length);
+    }
+    assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
+    if (s == null)
+    {
+      assertTrue(r.readOctetStringAsString().equals(""));
+    }
+    else
+    {
+      assertTrue(s.equals(r.readOctetStringAsString()));
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readOctetString</CODE> methods.
+   */
+  @Test
+  public void testEncodeDecodeOctetStringOffLen() throws Exception
+  {
+    final byte[] b = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+
+    for (int i = 0; i < 5; i += 2)
+    {
+      final byte[] bsb = new byte[3];
+      System.arraycopy(b, i, bsb, 0, 3);
+      final ByteString bs = ByteString.wrap(bsb);
+      getWriter().writeOctetString(b, i, 3);
+
+      final ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), 3);
+      assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
+      assertTrue(bs.equals(r.readOctetString()));
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readOctetString</CODE> methods.
+   */
+  @Test(dataProvider = "binaryValues")
+  public void testEncodeDecodeOctetStringType(final byte[] b) throws Exception
+  {
+    final ByteString bs = ByteString.wrap(b);
+    final ByteStringBuilder bsb = new ByteStringBuilder();
+
+    for (final byte type : testTypes)
+    {
+      bsb.clear();
+      getWriter().writeOctetString(type, bs);
+
+      ASN1Reader r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), b.length);
+      assertEquals(r.peekType(), type);
+      r.readOctetString(bsb);
+      assertTrue(bs.equals(bsb));
+
+      bsb.clear();
+      getWriter().writeOctetString(type, b, 0, b.length);
+
+      r = getReader(getEncodedBytes());
+      assertEquals(r.peekLength(), b.length);
+      assertEquals(r.peekType(), type);
+      r.readOctetString(bsb);
+      assertTrue(bs.equals(bsb));
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>write/readOctetString</CODE> methods.
+   */
+  @Test(dataProvider = "stringValues")
+  public void testEncodeDecodeOctetStringType(final String s) throws Exception
+  {
+    for (final byte type : testTypes)
+    {
+      getWriter().writeOctetString(type, s);
+
+      final ASN1Reader r = getReader(getEncodedBytes());
+      if (s == null)
+      {
+        assertEquals(r.peekLength(), 0);
+      }
+      else
+      {
+        assertEquals(r.peekLength(), StaticUtils.getBytes(s).length);
+      }
+      assertEquals(r.peekType(), type);
+      if (s == null)
+      {
+        assertTrue(r.readOctetStringAsString().equals(""));
+      }
+      else
+      {
+        assertTrue(s.equals(r.readOctetStringAsString()));
+      }
+    }
+  }
+
+
+
+  @Test
+  public void testEncodeDecodeSequence() throws Exception
+  {
+    final ASN1Writer writer = getWriter();
+
+    writer.writeStartSequence();
+
+    writer.writeBoolean(true);
+    writer.writeBoolean(false);
+    writer.writeInteger(0);
+    writer.writeInteger(10L);
+    writer.writeNull();
+    writer.writeOctetString("test value");
+    writer.writeOctetString("skip value");
+
+    writer.writeStartSequence();
+    writer.writeOctetString("nested sequence");
+    writer.writeEndSequence();
+
+    writer.writeStartSet();
+    writer.writeOctetString("nested set");
+    writer.writeEndSet();
+
+    writer.writeEndSequence();
+
+    final ASN1Reader reader = getReader(getEncodedBytes());
+    assertEquals(reader.peekType(), UNIVERSAL_SEQUENCE_TYPE);
+    assertEquals(reader.peekLength(), 71);
+
+    assertTrue(reader.hasNextElement());
+    reader.readStartSequence();
+    assertTrue(reader.hasNextElement());
+
+    assertEquals(true, reader.readBoolean());
+    assertEquals(false, reader.readBoolean());
+    assertEquals(0, reader.readInteger());
+    assertEquals(10, reader.readInteger());
+    reader.readNull();
+    assertEquals("test value", reader.readOctetStringAsString());
+    reader.skipElement();
+
+    assertEquals(reader.peekLength(), 17);
+    assertEquals(reader.peekType(), UNIVERSAL_SEQUENCE_TYPE);
+    reader.readStartSequence();
+    assertEquals("nested sequence", reader.readOctetStringAsString());
+    reader.readEndSequence();
+
+    assertEquals(reader.peekLength(), 12);
+    assertEquals(reader.peekType(), UNIVERSAL_SET_TYPE);
+    reader.readStartSequence();
+    assertEquals("nested set", reader.readOctetStringAsString());
+    reader.readEndSequence();
+
+    assertFalse(reader.hasNextElement());
+    reader.readEndSequence();
+    assertFalse(reader.elementAvailable());
+  }
+
+
+
+  /**
+   * Tests that negative integers are encoded according to ASN.1 BER
+   * specification.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test()
+  public void testNegativeIntEncoding() throws Exception
+  {
+    // Some negative integers of interest
+    // to test specific ranges/boundaries.
+    getWriter().writeInteger(-1);
+    byte[] value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+
+    getWriter().writeInteger(-2);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFE);
+
+    getWriter().writeInteger(-127);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x81);
+
+    getWriter().writeInteger(-128);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x80);
+
+    getWriter().writeInteger(-255);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x01);
+
+    getWriter().writeInteger(-256);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x00);
+
+    getWriter().writeInteger(-65535);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x01);
+
+    getWriter().writeInteger(-65536);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x00);
+
+    getWriter().writeInteger(-2147483647);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x80);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x00);
+    assertEquals(value[5], (byte) 0x01);
+
+    getWriter().writeInteger(-2147483648);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x80);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x00);
+    assertEquals(value[5], (byte) 0x00);
+  }
+
+
+
+  /**
+   * Tests that negative integers are encoded according to ASN.1 BER
+   * specification.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test()
+  public void testNegativeLongEncoding() throws Exception
+  {
+    // Some negative integers of interest
+    // to test specific ranges/boundaries.
+    getWriter().writeInteger(-1L);
+    byte[] value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+
+    getWriter().writeInteger(-2L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFE);
+
+    getWriter().writeInteger(-127L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x81);
+
+    getWriter().writeInteger(-128L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x80);
+
+    getWriter().writeInteger(-255L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x01);
+
+    getWriter().writeInteger(-256L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x00);
+
+    getWriter().writeInteger(-65535L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x01);
+
+    getWriter().writeInteger(-65536L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0xFF);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x00);
+
+    getWriter().writeInteger(-2147483647L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x80);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x00);
+    assertEquals(value[5], (byte) 0x01);
+
+    getWriter().writeInteger(-2147483648L);
+    value = getEncodedBytes();
+    assertEquals(value[2], (byte) 0x80);
+    assertEquals(value[3], (byte) 0x00);
+    assertEquals(value[4], (byte) 0x00);
+    assertEquals(value[5], (byte) 0x00);
+  }
+
+
+
+  protected abstract byte[] getEncodedBytes() throws IOException,
+      DecodeException;
+
+
+
+  protected abstract ASN1Reader getReader(byte[] encodedBytes)
+      throws DecodeException, IOException;
+
+
+
+  protected abstract ASN1Writer getWriter() throws IOException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/controls/ControlsTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/controls/ControlsTestCase.java
new file mode 100644
index 0000000..6f0ec5e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/controls/ControlsTestCase.java
@@ -0,0 +1,60 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.controls;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.opends.sdk.TestCaseUtils;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all controls unit tests should extend. A control
+ * represents the classes found directly under the package
+ * org.opends.sdk.controls.
+ */
+
+@Test(groups = { "precommit", "controls", "sdk" }, sequential = true)
+public abstract class ControlsTestCase extends OpenDSTestCase
+{
+  /**
+   * Set up the environment for performing the tests in this suite.
+   *
+   * @throws Exception
+   *           If the environment could not be set up.
+   */
+  @BeforeClass
+  public void setUp() throws Exception
+  {
+    // This test suite depends on having the schema available.
+    TestCaseUtils.startServer();
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryReaderTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryReaderTestCase.java
new file mode 100644
index 0000000..e4e345a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryReaderTestCase.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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import static org.testng.Assert.assertNotNull;
+
+import java.io.FileInputStream;
+import java.util.NoSuchElementException;
+
+import org.opends.sdk.DN;
+import org.opends.sdk.Entry;
+import org.opends.sdk.TestCaseUtils;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class tests the LDIFEntryReader functionality.
+ */
+public final class LDIFEntryReaderTestCase extends LDIFTestCase
+{
+  /**
+   * Tests readEntry method of LDIFEntryReader class.See
+   * https://opends.dev.java.net/issues/show_bug.cgi?id=4545 for more details.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test()
+  public void testEmpty() throws Exception
+  {
+    final String path = TestCaseUtils.createTempFile("");
+    final FileInputStream in = new FileInputStream(path);
+    final LDIFEntryReader reader = new LDIFEntryReader(in);
+    try
+    {
+      reader.setValidateSchema(false);
+
+      Assert.assertFalse(reader.hasNext());
+      Assert.assertFalse(reader.hasNext());
+      try
+      {
+        reader.readEntry();
+        Assert
+            .fail("reader.readEntry() should have thrown NoSuchElementException");
+      }
+      catch (NoSuchElementException e)
+      {
+        // This is expected.
+      }
+      Assert.assertFalse(reader.hasNext());
+    }
+    finally
+    {
+      reader.close();
+    }
+  }
+
+
+
+  /**
+   * Tests readEntry method of LDIFEntryReader class.See
+   * https://opends.dev.java.net/issues/show_bug.cgi?id=4545 for more details.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test()
+  public void testReadEntry() throws Exception
+  {
+    final String path = TestCaseUtils
+        .createTempFile(
+            "dn: uid=1,ou=people,dc=ucsf,dc=edu",
+            "objectClass: top",
+            "objectClass: person",
+            "objectClass: organizationalperson",
+            "objectClass: inetorgperson",
+            "givenName: Aaccf",
+            "sn: Amar",
+            "cn: Aaccf Amar",
+            "initials: ASA",
+            "employeeNumber: 020000001",
+            "uid: 1",
+            "mail: Aaccf.Amar@ucsf.edu",
+            "userPassword: password",
+            "telephoneNumber: +1 685 622 6202",
+            "homePhone: +1 225 216 5900",
+            "pager: +1 779 041 6341",
+            "mobile: +1 010 154 3228",
+            "street: 01251 Chestnut Street",
+            "l: Panama City",
+            "st: DE",
+            "postalCode: 50369",
+            "postalAddress: Aaccf Amar$01251 Chestnut Street$Panama City, DE  50369",
+            "description: This is the description for Aaccf Amar.");
+    final FileInputStream in = new FileInputStream(path);
+    final LDIFEntryReader reader = new LDIFEntryReader(in);
+    try
+    {
+      reader.setValidateSchema(false);
+
+      Assert.assertTrue(reader.hasNext());
+      final Entry entry = reader.readEntry();
+      assertNotNull(entry);
+      Assert.assertEquals(entry.getName(),
+          DN.valueOf("uid=1,ou=people,dc=ucsf,dc=edu"));
+      Assert.assertFalse(reader.hasNext());
+      try
+      {
+        reader.readEntry();
+        Assert
+            .fail("reader.readEntry() should have thrown NoSuchElementException");
+      }
+      catch (NoSuchElementException e)
+      {
+        // This is expected.
+      }
+    }
+    finally
+    {
+      reader.close();
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryWriterTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryWriterTestCase.java
new file mode 100644
index 0000000..bba7e3c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFEntryWriterTestCase.java
@@ -0,0 +1,96 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.ldif;
+
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opends.sdk.Entry;
+import org.opends.sdk.LinkedHashMapEntry;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * This class tests the LDIFEntryWriter functionality.
+ */
+public final class LDIFEntryWriterTestCase extends LDIFTestCase
+{
+
+  /**
+   * Tests writeEntry method of LDIFEntryWriter class.See
+   * https://opends.dev.java.net/issues/show_bug.cgi?id=4545 for more details.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test()
+  public void testWriteEntry() throws Exception
+  {
+    final Entry entry = new LinkedHashMapEntry(
+        "cn=John Doe,ou=people,dc=example,dc=com");
+    entry.addAttribute("objectClass", "top", "person", "inetOrgPerson");
+    entry.addAttribute("cn", "John Doe");
+    entry.addAttribute("sn", "Doe");
+    entry.addAttribute("givenName", "John");
+    entry.addAttribute("description", "one two", "three four", "five six");
+    entry.addAttribute("typeOnly");
+    entry.addAttribute("localized;lang-fr", "\u00e7edilla");
+
+    final List<String> actual = new ArrayList<String>();
+    final LDIFEntryWriter writer = new LDIFEntryWriter(actual);
+    writer.writeEntry(entry);
+    writer.close();
+
+    final String[] expected = new String[] {
+        "dn: cn=John Doe,ou=people,dc=example,dc=com",
+        "objectClass: top",
+        "objectClass: person",
+        "objectClass: inetOrgPerson",
+        "cn: John Doe",
+        "sn: Doe",
+        "givenName: John",
+        "description: one two",
+        "description: three four",
+        "description: five six",
+        "typeOnly: ",
+        "localized;lang-fr:: w6dlZGlsbGE=",
+        "",
+        };
+
+    Assert.assertEquals(actual.size(), expected.length);
+    for (int i = 0; i < expected.length; i++)
+    {
+      Assert.assertEquals(actual.get(i), expected[i], "LDIF output was "
+          + actual);
+    }
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFTestCase.java
new file mode 100644
index 0000000..e656589
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/ldif/LDIFTestCase.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.ldif;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all LDIF unit tests should extend. LDIF represents the
+ * classes found directly under the package org.opends.sdk.ldif.
+ */
+
+@Test(groups = { "precommit", "types", "sdk" }, sequential = true)
+public abstract class LDIFTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AbandonRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AbandonRequestTestCase.java
new file mode 100644
index 0000000..2270531
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AbandonRequestTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests Abandon requests.
+ */
+public class AbandonRequestTestCase extends RequestTestCase
+{
+  @DataProvider(name = "abandonRequests")
+  public Object[][] getAbandonRequests() throws Exception
+  {
+    final AbandonRequest[] requests = { Requests.newAbandonRequest(-1),
+        Requests.newAbandonRequest(0), Requests.newAbandonRequest(1) };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected AbandonRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getAbandonRequests();
+    final AbandonRequest[] ops = new AbandonRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (AbandonRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AddRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AddRequestTestCase.java
new file mode 100644
index 0000000..e3166ae
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AddRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.DN;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests ADD requests.
+ */
+public class AddRequestTestCase extends RequestTestCase
+{
+  @DataProvider(name = "addRequests")
+  public Object[][] getAddRequests() throws Exception
+  {
+    final AddRequest[] requests = {
+        Requests.newAddRequest(DN.valueOf("uid=addrequest1")),
+        Requests.newAddRequest("cn=addrequesttestcase"),
+        Requests.newAddRequest("dn: ou=People,o=test", "objectClass: top",
+            "objectClass: organizationalUnit", "ou: People") };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected AddRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getAddRequests();
+    final AddRequest[] ops = new AddRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (AddRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AnonymousSASLBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AnonymousSASLBindRequestTestCase.java
new file mode 100644
index 0000000..db46a6e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/AnonymousSASLBindRequestTestCase.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests anonymous SASL bind requests.
+ */
+public class AnonymousSASLBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "anonymousSASLBindRequests")
+  public Object[][] getAnonymousSASLBindRequests() throws Exception
+  {
+    final AnonymousSASLBindRequest[] requests = {
+        Requests.newAnonymousSASLBindRequest(""),
+        Requests.newAnonymousSASLBindRequest("test") };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected AnonymousSASLBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getAnonymousSASLBindRequests();
+    final AnonymousSASLBindRequest[] ops = new AnonymousSASLBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (AnonymousSASLBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/BindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/BindRequestTestCase.java
new file mode 100644
index 0000000..bb3f49a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/BindRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static org.testng.Assert.assertNotNull;
+
+import org.testng.annotations.Test;
+
+import com.sun.opends.sdk.ldap.LDAPConstants;
+
+
+
+/**
+ * Tests the BIND requests.
+ */
+public abstract class BindRequestTestCase extends RequestTestCase
+{
+  @Test(dataProvider = "testRequests")
+  public void testAuthType(final BindRequest request) throws Exception
+  {
+    final byte b = request.getAuthenticationType();
+    if (!(b == LDAPConstants.TYPE_AUTHENTICATION_SASL || b == LDAPConstants.TYPE_AUTHENTICATION_SIMPLE))
+    {
+      throw new Exception("Invalid bind type");
+    }
+  }
+
+
+
+  @Test(dataProvider = "testRequests")
+  public void testBindClient(final BindRequest request) throws Exception
+  {
+    final BindClient client = request.createBindClient("localhost");
+    assertNotNull(client);
+  }
+
+
+
+  @Test(dataProvider = "testRequests")
+  public void testName(final BindRequest request) throws Exception
+  {
+    assertNotNull(request.getName());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestTestCase.java
new file mode 100644
index 0000000..437625f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CRAMMD5SASLBindRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests CRAM MD5 SASL bind requests.
+ */
+public class CRAMMD5SASLBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "CRAMMD5SASLBindRequests")
+  public Object[][] getCRAMMD5SASLBindRequests() throws Exception
+  {
+    final CRAMMD5SASLBindRequest[] requests = {
+        Requests.newCRAMMD5SASLBindRequest("id1", ByteString.empty()),
+        Requests.newCRAMMD5SASLBindRequest("id2", ByteString.valueOf("test")) };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected CRAMMD5SASLBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getCRAMMD5SASLBindRequests();
+    final CRAMMD5SASLBindRequest[] ops = new CRAMMD5SASLBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (CRAMMD5SASLBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CompareRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CompareRequestTestCase.java
new file mode 100644
index 0000000..8f006a8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/CompareRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * @author sin
+ */
+public class CompareRequestTestCase extends RequestTestCase
+{
+  @DataProvider(name = "CompareRequests")
+  public Object[][] getCompareRequests() throws Exception
+  {
+    final CompareRequest[] requests = {
+        Requests.newCompareRequest("uid=user.0,ou=people,o=test", "cn",
+            "user.0"),
+        Requests.newCompareRequest("uid=user.0,ou=people,o=test", "uid",
+            "user.0") };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected CompareRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getCompareRequests();
+    final CompareRequest[] ops = new CompareRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (CompareRequest) objs[i][0];
+    }
+    return ops;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DeleteRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DeleteRequestTestCase.java
new file mode 100644
index 0000000..c3e73e5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DeleteRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.DN;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests the delete request.
+ */
+public class DeleteRequestTestCase extends RequestTestCase
+{
+  @DataProvider(name = "DeleteRequests")
+  public Object[][] getDeleteRequests() throws Exception
+  {
+    final DeleteRequest[] requests = {
+        Requests.newDeleteRequest(DN.valueOf("uid=Deleterequest1")),
+        Requests.newDeleteRequest("cn=Deleterequesttestcase"),
+        Requests.newDeleteRequest("uid=user.999,ou=people,o=test") };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected DeleteRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getDeleteRequests();
+    final DeleteRequest[] ops = new DeleteRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (DeleteRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DigestMD5SASLBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DigestMD5SASLBindRequestTestCase.java
new file mode 100644
index 0000000..52629a6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/DigestMD5SASLBindRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+import static org.testng.Assert.assertEquals;
+
+
+/**
+ * Tests Digest MD5 SASL requests.
+ */
+public class DigestMD5SASLBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "DigestMD5SASLBindRequests")
+  public Object[][] getDigestMD5SASLBindRequests() throws Exception
+  {
+    final DigestMD5SASLBindRequest[] requests = {
+        Requests.newDigestMD5SASLBindRequest("id1", ByteString.empty()),
+        Requests.newDigestMD5SASLBindRequest("id2", ByteString
+            .valueOf("password")) };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected DigestMD5SASLBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getDigestMD5SASLBindRequests();
+    final DigestMD5SASLBindRequest[] ops = new DigestMD5SASLBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (DigestMD5SASLBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+
+  @Test(dataProvider = "DigestMD5SASLBindRequests")
+  public void testQOP(DigestMD5SASLBindRequest request) throws Exception
+  {
+    String[] options = new String[] {
+        DigestMD5SASLBindRequest.QOP_AUTH,
+        DigestMD5SASLBindRequest.QOP_AUTH_INT,
+        DigestMD5SASLBindRequest.QOP_AUTH_CONF };
+    request.addQOP(options);
+    assertEquals(request.getQOPs(), Arrays.asList(options));
+  }
+
+  @Test(dataProvider = "DigestMD5SASLBindRequests" )
+  public void testStrength(DigestMD5SASLBindRequest request) throws Exception
+  {
+    request.setCipher(DigestMD5SASLBindRequest.CIPHER_3DES);
+    assertEquals(request.getCipher(), DigestMD5SASLBindRequest.CIPHER_3DES);
+
+    request.setCipher(DigestMD5SASLBindRequest.CIPHER_MEDIUM);
+    assertEquals(request.getCipher(), DigestMD5SASLBindRequest.CIPHER_MEDIUM);
+  }
+
+  @Test(dataProvider = "DigestMD5SASLBindRequests")
+  public void testServerAuth(DigestMD5SASLBindRequest request) throws Exception
+  {
+    request.setServerAuth(true);
+    assertEquals(request.isServerAuth(), true);
+  }
+
+  @Test(dataProvider = "DigestMD5SASLBindRequests")
+  public void testSendBuffer(DigestMD5SASLBindRequest request) throws Exception
+  {
+    request.setMaxSendBufferSize(1024);
+    assertEquals(request.getMaxSendBufferSize(), 1024);
+  }
+
+  @Test(dataProvider = "DigestMD5SASLBindRequests")
+  public void testRecieveBuffer(DigestMD5SASLBindRequest request) throws Exception
+  {;
+    request.setMaxReceiveBufferSize(1024);
+    assertEquals(request.getMaxReceiveBufferSize(), 1024);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExtendedRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExtendedRequestTestCase.java
new file mode 100644
index 0000000..2c6f851
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExtendedRequestTestCase.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static org.testng.Assert.assertNotNull;
+
+import org.opends.sdk.responses.ExtendedResultDecoder;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests various extended requests.
+ */
+public abstract class ExtendedRequestTestCase extends RequestTestCase
+{
+  @Test(dataProvider = "testRequests")
+  public void testDecoder(final ExtendedRequest<?> request) throws Exception
+  {
+    final ExtendedResultDecoder<?> decoder = request.getResultDecoder();
+    assertNotNull(decoder);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExternalSASLBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExternalSASLBindRequestTestCase.java
new file mode 100644
index 0000000..427205d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ExternalSASLBindRequestTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests the external SASL Bind requests.
+ */
+public class ExternalSASLBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "ExternalSASLBindRequests")
+  public Object[][] getExternalSASLBindRequests() throws Exception
+  {
+    final ExternalSASLBindRequest[] requests = { Requests
+        .newExternalSASLBindRequest() };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected ExternalSASLBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getExternalSASLBindRequests();
+    final ExternalSASLBindRequest[] ops = new ExternalSASLBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (ExternalSASLBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GSSAPISASLBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GSSAPISASLBindRequestTestCase.java
new file mode 100644
index 0000000..eadef95
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GSSAPISASLBindRequestTestCase.java
@@ -0,0 +1,111 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Tests GSSAPI SASL Bind requests.
+ */
+public class GSSAPISASLBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "GSSAPISASLBindRequests")
+  public Object[][] getGSSAPISASLBindRequests() throws Exception
+  {
+    final GSSAPISASLBindRequest[] requests = {
+        Requests.newGSSAPISASLBindRequest("id1", ByteString.empty()),
+        Requests
+            .newGSSAPISASLBindRequest("id2", ByteString.valueOf("password")) };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected GSSAPISASLBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getGSSAPISASLBindRequests();
+    final GSSAPISASLBindRequest[] ops = new GSSAPISASLBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (GSSAPISASLBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+
+  @Test(enabled = false)
+  public void testBindClient(BindRequest request) throws Exception {
+    // Should setup a test krb server...
+    super.testBindClient(request);
+  }
+
+  @Test(dataProvider = "GSSAPISASLBindRequests")
+  public void testQOP(GSSAPISASLBindRequest request) throws Exception
+  {
+    String[] options = new String[] {
+        GSSAPISASLBindRequest.QOP_AUTH,
+        GSSAPISASLBindRequest.QOP_AUTH_INT,
+        GSSAPISASLBindRequest.QOP_AUTH_CONF };
+    request.addQOP(options);
+    assertEquals(request.getQOPs(), Arrays.asList(options));
+  }
+
+  @Test(dataProvider = "GSSAPISASLBindRequests")
+  public void testServerAuth(GSSAPISASLBindRequest request) throws Exception
+  {
+    request.setServerAuth(true);
+    assertEquals(request.isServerAuth(), true);
+  }
+
+  @Test(dataProvider = "GSSAPISASLBindRequests")
+  public void testSendBuffer(GSSAPISASLBindRequest request) throws Exception
+  {
+    request.setMaxSendBufferSize(512);
+    assertEquals(request.getMaxSendBufferSize(), 512);
+  }
+
+  @Test(dataProvider = "GSSAPISASLBindRequests")
+  public void testRecieveBuffer(GSSAPISASLBindRequest request) throws Exception
+  {
+    request.setMaxReceiveBufferSize(512);
+    assertEquals(request.getMaxReceiveBufferSize(), 512);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GenericBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GenericBindRequestTestCase.java
new file mode 100644
index 0000000..ca8b60e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/GenericBindRequestTestCase.java
@@ -0,0 +1,77 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.testng.annotations.DataProvider;
+
+import com.sun.opends.sdk.ldap.LDAPConstants;
+
+
+
+/**
+ * Tests Generic Bind requests.
+ */
+public class GenericBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "GenericBindRequests")
+  public Object[][] getGenericBindRequests() throws Exception
+  {
+    final GenericBindRequest[] requests = {
+        Requests.newGenericBindRequest(LDAPConstants.TYPE_AUTHENTICATION_SASL,
+            ByteString.empty()),
+        Requests.newGenericBindRequest(
+            LDAPConstants.TYPE_AUTHENTICATION_SIMPLE, ByteString
+                .valueOf("password")),
+        Requests.newGenericBindRequest("username",
+            LDAPConstants.TYPE_AUTHENTICATION_SIMPLE, ByteString
+                .valueOf("password")) };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected GenericBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getGenericBindRequests();
+    final GenericBindRequest[] ops = new GenericBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (GenericBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyDNRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyDNRequestTestCase.java
new file mode 100644
index 0000000..e8e1e77
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyDNRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests the Modify DN requests.
+ */
+public class ModifyDNRequestTestCase extends RequestTestCase
+{
+  @DataProvider(name = "ModifyDNRequests")
+  public Object[][] getModifyDNRequests() throws Exception
+  {
+    final ModifyDNRequest[] requests = {
+        Requests.newModifyDNRequest("uid=user.100,ou=people,o=test",
+            "uid=100.user,ou=people,o=testl"),
+        Requests.newModifyDNRequest("cn=ModifyDNrequesttestcase", "cn=xyz"), };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected ModifyDNRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getModifyDNRequests();
+    final ModifyDNRequest[] ops = new ModifyDNRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (ModifyDNRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyRequestTestCase.java
new file mode 100644
index 0000000..57e9e7d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/ModifyRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.DN;
+import org.opends.sdk.ModificationType;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests the modify request.
+ */
+public class ModifyRequestTestCase extends RequestTestCase
+{
+  @DataProvider(name = "ModifyRequests")
+  public Object[][] getModifyRequests() throws Exception
+  {
+    final ModifyRequest[] requests = {
+        Requests.newModifyRequest(DN.valueOf("uid=Modifyrequest1"))
+            .addModification(ModificationType.ADD, "userpassword", "password"),
+        Requests.newModifyRequest("cn=Modifyrequesttestcase").addModification(
+            ModificationType.ADD, "userpassword", "password"),
+        Requests.newModifyRequest("dn: ou=People,o=test", "changetype: modify",
+            "add: userpassword", "userpassword: password") };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected ModifyRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getModifyRequests();
+    final ModifyRequest[] ops = new ModifyRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (ModifyRequest) objs[i][0];
+    }
+    return ops;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/PlainSASLBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/PlainSASLBindRequestTestCase.java
new file mode 100644
index 0000000..8f6a5d0
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/PlainSASLBindRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.ByteString;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests Plain SASL Bind requests.
+ */
+public class PlainSASLBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "plainSASLBindRequests")
+  public Object[][] getPlainSASLBindRequests() throws Exception
+  {
+    final PlainSASLBindRequest[] requests = {
+        Requests.newPlainSASLBindRequest("id1", ByteString.empty()),
+        Requests.newPlainSASLBindRequest("id2", ByteString.valueOf("password")) };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected PlainSASLBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getPlainSASLBindRequests();
+    final PlainSASLBindRequest[] ops = new PlainSASLBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (PlainSASLBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestTestCase.java
new file mode 100644
index 0000000..71ef291
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestTestCase.java
@@ -0,0 +1,136 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.opends.sdk.Connection;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.DecodeOptions;
+import org.opends.sdk.TestCaseUtils;
+import org.opends.sdk.controls.Control;
+import org.opends.sdk.controls.ControlDecoder;
+import org.opends.sdk.controls.GenericControl;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests the Request class.
+ */
+public abstract class RequestTestCase extends RequestsTestCase
+{
+  // Dummy decoder which does nothing.
+  private static class MyDecoder implements ControlDecoder<Control>
+  {
+    public Control decodeControl(final Control control,
+        final DecodeOptions options) throws DecodeException
+    {
+      // do nothing.
+      return control;
+    }
+
+
+
+    public String getOID()
+    {
+      return "1.2.3".intern();
+    }
+  }
+
+
+
+  // Connection used for sedning requests.
+  protected Connection con;
+
+
+
+  /**
+   * Request data to be validated.
+   *
+   * @return An array of requests.
+   * @throws Exception
+   */
+  @DataProvider(name = "testRequests")
+  public Object[][] getTestRequests() throws Exception
+  {
+    final Request[] requestArray = createTestRequests();
+    final Object[][] objectArray = new Object[requestArray.length][1];
+
+    for (int i = 0; i < requestArray.length; i++)
+    {
+      objectArray[i][0] = requestArray[i];
+    }
+    return objectArray;
+  }
+
+
+
+  /**
+   * Ensures that the LDAP Server is running.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer() throws Exception
+  {
+    TestCaseUtils.startServer();
+    con = TestCaseUtils.getInternalConnection();
+  }
+
+
+
+  @Test(dataProvider = "testRequests")
+  public void testControls(final Request request) throws Exception
+  {
+    // Add an arbitrary control and see if it is present.
+    Control control = GenericControl.newControl("1.2.3".intern());
+    request.addControl(control);
+    assertTrue(request.getControls().size() > 0);
+    final MyDecoder decoder = new MyDecoder();
+    control = request.getControl(decoder, new DecodeOptions());
+    assertNotNull(control);
+  }
+
+
+
+  /**
+   * Creates the test requests.
+   *
+   * @param <T>
+   * @return
+   * @throws Exception
+   */
+  protected abstract Request[] createTestRequests() throws Exception;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestsTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestsTestCase.java
new file mode 100644
index 0000000..81be811
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/RequestsTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all requests unit tests should extend. Requests
+ * represents the classes found directly under the package
+ * org.opends.sdk.requests.
+ */
+
+@Test(groups = { "precommit", "requests", "sdk" }, sequential = true)
+public abstract class RequestsTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/SimpleBindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/SimpleBindRequestTestCase.java
new file mode 100644
index 0000000..bd3bdc3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/SimpleBindRequestTestCase.java
@@ -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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests Simple Bind requests.
+ */
+public class SimpleBindRequestTestCase extends BindRequestTestCase
+{
+  @DataProvider(name = "simpleBindRequests")
+  public Object[][] getSimpleBindRequests() throws Exception
+  {
+    final SimpleBindRequest[] requests = { Requests.newSimpleBindRequest(),// anonymous;
+        Requests.newSimpleBindRequest("username", "password".toCharArray()) };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected SimpleBindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getSimpleBindRequests();
+    final SimpleBindRequest[] ops = new SimpleBindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (SimpleBindRequest) objs[i][0];
+    }
+    return ops;
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/UnbindRequestTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/UnbindRequestTestCase.java
new file mode 100644
index 0000000..f4a0dec
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/requests/UnbindRequestTestCase.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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.requests;
+
+
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Tests the unbind requests.
+ */
+public class UnbindRequestTestCase extends RequestTestCase
+{
+  @DataProvider(name = "UnbindRequests")
+  public Object[][] getUnbindRequests() throws Exception
+  {
+    final UnbindRequest[] requests = { Requests.newUnbindRequest(), };
+    final Object[][] objArray = new Object[requests.length][1];
+    for (int i = 0; i < requests.length; i++)
+    {
+      objArray[i][0] = requests[i];
+    }
+    return objArray;
+  }
+
+
+
+  @Override
+  protected UnbindRequest[] createTestRequests() throws Exception
+  {
+    final Object[][] objs = getUnbindRequests();
+    final UnbindRequest[] ops = new UnbindRequest[objs.length];
+    for (int i = 0; i < objs.length; i++)
+    {
+      ops[i] = (UnbindRequest) objs[i][0];
+    }
+    return ops;
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/responses/ResponsesTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/responses/ResponsesTestCase.java
new file mode 100644
index 0000000..7261a24
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/responses/ResponsesTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.responses;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all responses unit tests should extend. Responses
+ * represents the classes found directly under the package
+ * org.opends.sdk.responses.
+ */
+
+@Test(groups = { "precommit", "responses", "sdk" }, sequential = true)
+public abstract class ResponsesTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AbstractSchemaElementTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AbstractSchemaElementTestCase.java
new file mode 100644
index 0000000..bafa766
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AbstractSchemaElementTestCase.java
@@ -0,0 +1,197 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.opends.sdk.DecodeException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Abstract schema element tests.
+ */
+public abstract class AbstractSchemaElementTestCase extends SchemaTestCase
+{
+  protected static final Map<String, List<String>> EMPTY_PROPS = Collections
+      .emptyMap();
+  protected static final List<String> EMPTY_NAMES = Collections.emptyList();
+
+
+
+  @DataProvider(name = "equalsTestData")
+  public abstract Object[][] createEqualsTestData() throws SchemaException,
+      DecodeException;
+
+
+
+  /**
+   * Check that the equals operator works as expected.
+   *
+   * @param e1
+   *          The first element
+   * @param e2
+   *          The second element
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "equalsTestData")
+  public final void testEquals(final SchemaElement e1, final SchemaElement e2,
+      final boolean result) throws Exception
+  {
+
+    Assert.assertEquals(e1.equals(e2), result);
+    Assert.assertEquals(e2.equals(e1), result);
+  }
+
+
+
+  /**
+   * Check that the {@link SchemaElement#getDescription()} method returns a
+   * description.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetDescription() throws Exception
+  {
+    final SchemaElement e = getElement("hello", EMPTY_PROPS);
+    Assert.assertEquals(e.getDescription(), "hello");
+  }
+
+
+
+  /**
+   * Check that the {@link SchemaElement#getDescription()} method returns
+   * <code>null</code> when there is no description.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetDescriptionDefault() throws Exception
+  {
+    final SchemaElement e = getElement("", EMPTY_PROPS);
+    Assert.assertEquals(e.getDescription(), "");
+  }
+
+
+
+  /**
+   * Check that the {@link SchemaElement#getExtraProperty(String)} method
+   * returns values.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetExtraProperty() throws Exception
+  {
+    final List<String> values = new ArrayList<String>();
+    values.add("one");
+    values.add("two");
+    final Map<String, List<String>> props = Collections.singletonMap("test",
+        values);
+    final SchemaElement e = getElement("", props);
+
+    int i = 0;
+    for (final String value : e.getExtraProperty("test"))
+    {
+      Assert.assertEquals(value, values.get(i));
+      i++;
+    }
+  }
+
+
+
+  /**
+   * Check that the {@link SchemaElement#getExtraProperty(String)} method
+   * returns <code>null</code> when there is no property.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetExtraPropertyDefault() throws Exception
+  {
+    final SchemaElement e = getElement("", EMPTY_PROPS);
+    Assert.assertTrue(e.getExtraProperty("test").isEmpty());
+  }
+
+
+
+  /**
+   * Check that the {@link SchemaElement#getExtraPropertyNames()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetExtraPropertyNames() throws Exception
+  {
+    final SchemaElement e = getElement("", EMPTY_PROPS);
+    Assert.assertTrue(e.getExtraProperty("test").isEmpty());
+  }
+
+
+
+  /**
+   * Check that the hasCode method operator works as expected.
+   *
+   * @param e1
+   *          The first element
+   * @param e2
+   *          The second element
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "equalsTestData")
+  public final void testHashCode(final SchemaElement e1,
+      final SchemaElement e2, final boolean result) throws Exception
+  {
+
+    Assert.assertEquals(e1.hashCode() == e2.hashCode(), result);
+  }
+
+
+
+  protected abstract SchemaElement getElement(String description,
+      Map<String, List<String>> extraProperties) throws SchemaException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/ApproximateMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/ApproximateMatchingRuleTest.java
new file mode 100644
index 0000000..a8ce15a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/ApproximateMatchingRuleTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.AMR_DOUBLE_METAPHONE_NAME;
+import static org.testng.Assert.assertEquals;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Approximate matching rule tests.
+ */
+public class ApproximateMatchingRuleTest extends SchemaTestCase
+{
+  MatchingRule metaphone = Schema.getCoreSchema().getMatchingRule(
+      AMR_DOUBLE_METAPHONE_NAME);
+
+
+
+  /**
+   * Test the normalization and the approximate comparison.
+   */
+  @Test(dataProvider = "approximatematchingrules")
+  public void approximateMatchingRules(final MatchingRule rule,
+      final String value1, final String value2, final ConditionResult result)
+      throws Exception
+  {
+    // normalize the 2 provided values
+    final ByteString normalizedValue1 = rule.normalizeAttributeValue(ByteString
+        .valueOf(value1));
+
+    // check that the approximatelyMatch return the expected result.
+    final ConditionResult liveResult = rule.getAssertion(
+        ByteString.valueOf(value2)).matches(normalizedValue1);
+    assertEquals(result, liveResult);
+  }
+
+
+
+  /**
+   * Build the data for the approximateMatchingRules test.
+   */
+  @DataProvider(name = "approximatematchingrules")
+  public Object[][] createapproximateMatchingRuleTest()
+  {
+    // fill this table with tables containing :
+    // - the name of the approxiamtematchingrule to test
+    // - 2 values that must be tested for matching
+    // - a boolean indicating if the values match or not
+    return new Object[][] {
+        { metaphone, "celebre", "selebre", ConditionResult.TRUE },
+        { metaphone, "cygale", "sigale", ConditionResult.TRUE },
+        { metaphone, "cigale", "sigale", ConditionResult.TRUE },
+        { metaphone, "accacia", "akacia", ConditionResult.TRUE },
+        { metaphone, "cigale", "sigale", ConditionResult.TRUE },
+        { metaphone, "bertucci", "bertuchi", ConditionResult.TRUE },
+        { metaphone, "manger", "manjer", ConditionResult.TRUE },
+        { metaphone, "gyei", "kei", ConditionResult.TRUE },
+        { metaphone, "agnostique", "aknostic", ConditionResult.TRUE },
+        { metaphone, "ghang", "kang", ConditionResult.TRUE },
+        { metaphone, "affiche", "afiche", ConditionResult.TRUE },
+        { metaphone, "succeed", "sukid", ConditionResult.TRUE },
+        { metaphone, "McCarthur", "macarthur", ConditionResult.TRUE },
+        { metaphone, "czet", "set", ConditionResult.TRUE },
+        { metaphone, "re\u00C7u", "ressu", ConditionResult.TRUE },
+        { metaphone, "ni\u00D1o", "nino", ConditionResult.TRUE },
+        { metaphone, "bateaux", "bateau", ConditionResult.TRUE },
+        { metaphone, "witz", "wits", ConditionResult.TRUE },
+        { metaphone, "barre", "bare", ConditionResult.TRUE },
+        { metaphone, "write", "rite", ConditionResult.TRUE },
+        { metaphone, "the", "ze", ConditionResult.FALSE },
+        { metaphone, "motion", "mochion", ConditionResult.TRUE },
+        { metaphone, "bois", "boi", ConditionResult.TRUE },
+        { metaphone, "schi", "chi", ConditionResult.TRUE },
+        { metaphone, "escalier", "eskalier", ConditionResult.TRUE },
+        { metaphone, "science", "sience", ConditionResult.TRUE },
+        { metaphone, "school", "skool", ConditionResult.TRUE },
+        { metaphone, "swap", "sap", ConditionResult.TRUE },
+        { metaphone, "szize", "size", ConditionResult.TRUE },
+        { metaphone, "shoek", "choek", ConditionResult.FALSE },
+        { metaphone, "sugar", "chugar", ConditionResult.TRUE },
+        { metaphone, "isle", "ile", ConditionResult.TRUE },
+        { metaphone, "yle", "ysle", ConditionResult.TRUE },
+        { metaphone, "focaccia", "focashia", ConditionResult.TRUE },
+        { metaphone, "machine", "mashine", ConditionResult.TRUE },
+        { metaphone, "michael", "mikael", ConditionResult.TRUE },
+        { metaphone, "abba", "aba", ConditionResult.TRUE },
+        { metaphone, "caesar", "saesar", ConditionResult.TRUE },
+        { metaphone, "femme", "fame", ConditionResult.TRUE },
+        { metaphone, "panne", "pane", ConditionResult.TRUE },
+        { metaphone, "josa", "josa", ConditionResult.TRUE },
+        { metaphone, "jose", "hose", ConditionResult.TRUE },
+        { metaphone, "hello", "hello", ConditionResult.TRUE },
+        { metaphone, "hello", "ello", ConditionResult.FALSE },
+        { metaphone, "bag", "bak", ConditionResult.TRUE },
+        { metaphone, "bagg", "bag", ConditionResult.TRUE },
+        { metaphone, "tagliaro", "takliaro", ConditionResult.TRUE },
+        { metaphone, "biaggi", "biaji", ConditionResult.TRUE },
+        { metaphone, "bioggi", "bioji", ConditionResult.TRUE },
+        { metaphone, "rough", "rouf", ConditionResult.TRUE },
+        { metaphone, "ghislane", "jislane", ConditionResult.TRUE },
+        { metaphone, "ghaslane", "kaslane", ConditionResult.TRUE },
+        { metaphone, "odd", "ot", ConditionResult.TRUE },
+        { metaphone, "edgar", "etkar", ConditionResult.TRUE },
+        { metaphone, "edge", "eje", ConditionResult.TRUE },
+        { metaphone, "accord", "akord", ConditionResult.TRUE },
+        { metaphone, "noize", "noise", ConditionResult.TRUE },
+        { metaphone, "orchid", "orkid", ConditionResult.TRUE },
+        { metaphone, "chemistry", "kemistry", ConditionResult.TRUE },
+        { metaphone, "chianti", "kianti", ConditionResult.TRUE },
+        { metaphone, "bacher", "baker", ConditionResult.TRUE },
+        { metaphone, "achtung", "aktung", ConditionResult.TRUE },
+        { metaphone, "Writing", "riting", ConditionResult.TRUE },
+        { metaphone, "xeon", "zeon", ConditionResult.TRUE },
+        { metaphone, "lonely", "loneli", ConditionResult.TRUE },
+        { metaphone, "bellaton", "belatton", ConditionResult.TRUE },
+        { metaphone, "pate", "patte", ConditionResult.TRUE },
+        { metaphone, "voiture", "vouatur", ConditionResult.TRUE },
+        { metaphone, "garbage", "garbedge", ConditionResult.TRUE },
+        { metaphone, "algorithme", "algorizm", ConditionResult.TRUE },
+        { metaphone, "testing", "testng", ConditionResult.TRUE },
+        { metaphone, "announce", "annonce", ConditionResult.TRUE },
+        { metaphone, "automaticly", "automatically", ConditionResult.TRUE },
+        { metaphone, "modifyd", "modified", ConditionResult.TRUE },
+        { metaphone, "bouteille", "butaille", ConditionResult.TRUE },
+        { metaphone, "xeon", "zeon", ConditionResult.TRUE },
+        { metaphone, "achtung", "aktung", ConditionResult.TRUE },
+        { metaphone, "throttle", "throddle", ConditionResult.TRUE },
+        { metaphone, "thimble", "thimblle", ConditionResult.TRUE },
+        { metaphone, "", "", ConditionResult.TRUE }, };
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeSyntaxTest.java
new file mode 100644
index 0000000..05c87d2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_ATTRIBUTE_TYPE_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Attribute type syntax tests.
+ */
+public class AttributeTypeSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] {
+        {
+            "(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )", true },
+        {
+            "(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " X-APPROX 'equalLengthApproximateMatch'"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " COLLECTIVE USAGE userApplications )", true },
+        { "(1.2.8.5 NAME 'testtype' DESC 'full type')", true },
+        { "(1.2.8.5 USAGE directoryOperation )", true },
+        {
+            "(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " COLLECTIVE USAGE badUsage )", false },
+        {
+            "(1.2.8.a.b NAME 'testtype' DESC 'full type' OBSOLETE "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " COLLECTIVE USAGE directoryOperation )", false },
+        {
+            "(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " BADTOKEN USAGE directoryOperation )", false },
+        {
+            "1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " NO-USER-MODIFICATION USAGE userApplications", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_ATTRIBUTE_TYPE_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeTest.java
new file mode 100644
index 0000000..110ee16
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/AttributeTypeTest.java
@@ -0,0 +1,648 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.*;
+
+import java.util.*;
+
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizedIllegalArgumentException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Attribute type tests.
+ */
+public class AttributeTypeTest extends AbstractSchemaElementTestCase
+{
+  private final Schema schema;
+
+
+
+  public AttributeTypeTest() throws Exception
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addAttributeType("1.2.1", EMPTY_NAMES, "", true, null, null, null,
+        null, null, "1.3.6.1.4.1.1466.115.121.1.27", true, false, false,
+        AttributeUsage.USER_APPLICATIONS, EMPTY_PROPS, false);
+    builder.addAttributeType(
+        "( 1.2.2 OBSOLETE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE "
+            + " COLLECTIVE X-ORIGIN ( 'Sun Java System Identity Management' "
+            + "'user defined' ) X-SCHEMA-FILE '98sunEmp.ldif')", false);
+    builder.addAttributeType("1.2.3", Collections.singletonList("testType"),
+        "", false, "1.2.2", null, null, null, null,
+        "1.3.6.1.4.1.1466.115.121.1.27", false, true, false,
+        AttributeUsage.USER_APPLICATIONS, EMPTY_PROPS, false);
+    builder.addAttributeType(
+        "( 1.2.4 NAME 'testType' SUP 1.2.3 SINGLE-VALUE COLLECTIVE )", false);
+    final List<String> names = new LinkedList<String>();
+    names.add("testType");
+    names.add("testnamealias");
+    names.add("anothernamealias");
+    builder.addAttributeType("1.2.5", names, "", false, null,
+        EMR_CASE_IGNORE_LIST_OID, null, SMR_CASE_IGNORE_LIST_OID,
+        AMR_DOUBLE_METAPHONE_OID, SYNTAX_INTEGER_OID, false, false, true,
+        AttributeUsage.DSA_OPERATION, EMPTY_PROPS, false);
+    builder.addAttributeType(
+        "( 1.2.6 NAME ( 'testType' 'testnamealias' 'anothernamealias1' ) "
+            + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP anothernamealias"
+            + " USAGE dSAOperation NO-USER-MODIFICATION )", false);
+    schema = builder.toSchema();
+    if (!schema.getWarnings().isEmpty())
+    {
+      throw new Exception("Base schema not valid!");
+    }
+  }
+
+
+
+  @DataProvider(name = "equalsTestData")
+  public Object[][] createEqualsTestData() throws SchemaException,
+      DecodeException
+  {
+    return new Object[][] {
+        { schema.getAttributeType("1.2.3"), schema.getAttributeType("1.2.3"),
+            true },
+        { schema.getAttributeType("1.2.4"), schema.getAttributeType("1.2.3"),
+            false } };
+  }
+
+
+
+  @Test
+  public void testADSyntax() throws Exception
+  {
+    // AD uses single quotes around OIDs
+    final SchemaBuilder builder = new SchemaBuilder(schema);
+    builder
+        .addAttributeType("(1.2.8.5 NAME 'testtype' DESC 'full type' "
+            + " SUP '1.2.5' " + " EQUALITY 'caseIgnoreMatch' "
+            + " SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' USAGE dSAOperation )",
+            false);
+    Assert.assertTrue(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+  public void testADSyntaxQuoteMismatch() throws Exception
+  {
+    // AD uses single quotes around OIDs
+    final SchemaBuilder builder = new SchemaBuilder(schema);
+    builder
+        .addAttributeType("(1.2.8.5 NAME 'testtype' DESC 'full type' "
+            + " SUP '1.2.5 " + " EQUALITY 'caseIgnoreMatch' "
+            + " SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' USAGE dSAOperation )",
+            false);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  @Test
+  public void testCollectiveOperational() throws Exception
+  {
+    // Collective can't be operational
+    final SchemaBuilder builder = new SchemaBuilder(schema);
+    builder.addAttributeType(
+        "(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE "
+            + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+            + " SUBSTR caseIgnoreSubstringsMatch"
+            + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+            + " COLLECTIVE USAGE directoryOperation )", false);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  /**
+   * Check constructor sets the default matching rules correctly.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorDefaultMatchingRules() throws Exception
+  {
+    final AttributeType type = schema.getAttributeType("1.2.1");
+
+    final Syntax syntax = schema.getSyntax("1.3.6.1.4.1.1466.115.121.1.27");
+    Assert.assertEquals(type.getApproximateMatchingRule(), syntax
+        .getApproximateMatchingRule());
+    Assert.assertEquals(type.getEqualityMatchingRule(), syntax
+        .getEqualityMatchingRule());
+    Assert.assertEquals(type.getOrderingMatchingRule(), syntax
+        .getOrderingMatchingRule());
+    Assert.assertEquals(type.getSubstringMatchingRule(), syntax
+        .getSubstringMatchingRule());
+  }
+
+
+
+  /**
+   * Check constructor sets the default usage correctly.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorDefaultUsage() throws Exception
+  {
+    final AttributeType d = schema.getAttributeType("1.2.2");
+
+    Assert.assertEquals(d.getUsage(), AttributeUsage.USER_APPLICATIONS);
+  }
+
+
+
+  /**
+   * Check constructor inherits the matching rules from the parent type when
+   * required.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dependsOnMethods = "testConstructorMatchingRules")
+  public void testConstructorInheritsMatchingRules() throws Exception
+  {
+    final AttributeType parent = schema.getAttributeType("1.2.5");
+
+    final AttributeType child = schema.getAttributeType("1.2.6");
+
+    Assert.assertEquals(parent.getApproximateMatchingRule(), child
+        .getApproximateMatchingRule());
+    Assert.assertEquals(parent.getEqualityMatchingRule(), child
+        .getEqualityMatchingRule());
+    // It should inherit ordering rule from parent's syntax since parent
+    // didn't specify an ordering matching rule.
+    Assert.assertEquals(parent.getSyntax().getOrderingMatchingRule(), child
+        .getOrderingMatchingRule());
+    Assert.assertEquals(parent.getSubstringMatchingRule(), child
+        .getSubstringMatchingRule());
+  }
+
+
+
+  /**
+   * Check constructor inherits the syntax from the parent type when required.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dependsOnMethods = "testConstructorSyntax")
+  public void testConstructorInheritsSyntax() throws Exception
+  {
+    AttributeType parent = schema.getAttributeType("1.2.3");
+
+    AttributeType child = schema.getAttributeType("1.2.4");
+
+    Assert.assertEquals(parent.getSyntax(), child.getSyntax());
+
+    parent = schema.getAttributeType("1.2.2");
+
+    child = schema.getAttributeType("1.2.3");
+    Assert.assertFalse(parent.getSyntax().equals(child.getSyntax()));
+
+    // Make sure paren't s syntax was not inherited in this case
+    child = schema.getAttributeType("1.2.6");
+    Assert
+        .assertEquals(child.getSyntax().getOID(), SYNTAX_DIRECTORY_STRING_OID);
+  }
+
+
+
+  /**
+   * Check constructor sets the matching rules correctly.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorMatchingRules() throws Exception
+  {
+    final AttributeType type = schema.getAttributeType("1.2.5");
+
+    Assert.assertEquals(type.getEqualityMatchingRule().getOID(),
+        EMR_CASE_IGNORE_LIST_OID);
+    Assert.assertEquals(type.getOrderingMatchingRule().getOID(), type
+        .getSyntax().getOrderingMatchingRule().getOID());
+    Assert.assertEquals(type.getSubstringMatchingRule().getOID(),
+        SMR_CASE_IGNORE_LIST_OID);
+    Assert.assertEquals(type.getApproximateMatchingRule().getOID(),
+        AMR_DOUBLE_METAPHONE_OID);
+  }
+
+
+
+  /**
+   * Check that the primary name is added to the set of names.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testConstructorPrimaryName() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.3");
+
+    Assert.assertTrue(d.hasName("testType"));
+    Assert.assertFalse(d.hasName("xxx"));
+
+    d = schema.getAttributeType("1.2.4");
+
+    Assert.assertTrue(d.hasName("testType"));
+    Assert.assertFalse(d.hasName("xxx"));
+
+  }
+
+
+
+  /**
+   * Check constructor sets the syntax correctly.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorSyntax() throws Exception
+  {
+    final AttributeType d = schema.getAttributeType("1.2.2");
+
+    Assert
+        .assertEquals(d.getSyntax().getOID(), "1.3.6.1.4.1.1466.115.121.1.15");
+  }
+
+
+
+  /**
+   * Check that the type names are accessible.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testConstructorTypeNames() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.5");
+
+    Assert.assertTrue(d.hasName("testType"));
+    Assert.assertTrue(d.hasName("testnamealias"));
+    Assert.assertTrue(d.hasName("anothernamealias"));
+
+    d = schema.getAttributeType("1.2.6");
+
+    Assert.assertTrue(d.hasName("testType"));
+    Assert.assertTrue(d.hasName("testnamealias"));
+    Assert.assertTrue(d.hasName("anothernamealias1"));
+  }
+
+
+
+  /**
+   * Check that the {@link AttributeType#getUsage()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetAttributeUsage() throws Exception
+  {
+    AttributeType type = schema.getAttributeType("1.2.1");
+    Assert.assertEquals(type.getUsage(), AttributeUsage.USER_APPLICATIONS);
+    type = schema.getAttributeType("1.2.6");
+    Assert.assertEquals(type.getUsage(), AttributeUsage.DSA_OPERATION);
+  }
+
+
+
+  /**
+   * Check that the {@link CommonSchemaElements#getNameOrOID()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetNameOrOIDReturnsOID() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.1");
+
+    Assert.assertEquals(d.getNameOrOID(), "1.2.1");
+
+    d = schema.getAttributeType("1.2.2");
+
+    Assert.assertEquals(d.getNameOrOID(), "1.2.2");
+  }
+
+
+
+  /**
+   * Check that the {@link CommonSchemaElements#getNameOrOID()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetNameOrOIDReturnsPrimaryName() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.3");
+    Assert.assertEquals(d.getNameOrOID(), "testType");
+    d = schema.getAttributeType("1.2.4");
+    Assert.assertEquals(d.getNameOrOID(), "testType");
+  }
+
+
+
+  /**
+   * Check that the {@link CommonSchemaElements#getNormalizedNames()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetNormalizedNames() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.5");
+    Iterator<String> i = d.getNames().iterator();
+    Assert.assertEquals(i.next(), "testType");
+    Assert.assertEquals(i.next(), "testnamealias");
+    Assert.assertEquals(i.next(), "anothernamealias");
+
+    d = schema.getAttributeType("1.2.6");
+    i = d.getNames().iterator();
+    Assert.assertEquals(i.next(), "testType");
+    Assert.assertEquals(i.next(), "testnamealias");
+    Assert.assertEquals(i.next(), "anothernamealias1");
+  }
+
+
+
+  /**
+   * Check that the {@link CommonSchemaElements#getOID()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testGetOID() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.3");
+    Assert.assertEquals(d.getOID(), "1.2.3");
+    d = schema.getAttributeType("1.2.4");
+    Assert.assertEquals(d.getOID(), "1.2.4");
+
+  }
+
+
+
+  /**
+   * Check that the {@link AttributeType#getSuperiorType()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetSuperiorType() throws Exception
+  {
+    AttributeType type = schema.getAttributeType("1.2.3");
+    Assert.assertEquals(type.getSuperiorType().getOID(), "1.2.2");
+    type = schema.getAttributeType("1.2.4");
+    Assert.assertEquals(type.getSuperiorType().getOID(), "1.2.3");
+  }
+
+
+
+  /**
+   * Check that the {@link CommonSchemaElements#hasNameOrOID(String)} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testHasNameOrOID() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.3");
+
+    Assert.assertTrue(d.hasNameOrOID("testType"));
+    Assert.assertTrue(d.hasNameOrOID("1.2.3"));
+    Assert.assertFalse(d.hasNameOrOID("x.y.z"));
+    d = schema.getAttributeType("1.2.4");
+
+    Assert.assertTrue(d.hasNameOrOID("testType"));
+    Assert.assertTrue(d.hasNameOrOID("1.2.4"));
+    Assert.assertFalse(d.hasNameOrOID("x.y.z"));
+  }
+
+
+
+  @Test
+  public void testInheritFromNonCollective() throws Exception
+  {
+    // Collective can't inherit from non-collective
+    final SchemaBuilder builder = new SchemaBuilder(schema);
+    builder.addAttributeType("(1.2.8.5 NAME 'testtype' DESC 'full type' "
+        + " OBSOLETE SUP 1.2.5 "
+        + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+        + " SUBSTR caseIgnoreSubstringsMatch"
+        + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+        + " COLLECTIVE USAGE userApplications )", false);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  @Test
+  public void testInheritFromUserAppUsage() throws Exception
+  {
+    // directoryOperation can't inherit from userApplications
+    final SchemaBuilder builder = new SchemaBuilder(schema);
+    builder.addAttributeType("(1.2.8.5 NAME 'testtype' DESC 'full type' "
+        + " OBSOLETE SUP 1.2.1 "
+        + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+        + " SUBSTR caseIgnoreSubstringsMatch"
+        + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+        + " NO-USER-MODIFICATION USAGE directoryOperation )", false);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  /**
+   * Check that the {@link AttributeType#isCollective()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testIsCollective() throws Exception
+  {
+    AttributeType type = schema.getAttributeType("1.2.2");
+    Assert.assertTrue(type.isCollective());
+    type = schema.getAttributeType("1.2.3");
+    Assert.assertTrue(type.isCollective());
+    type = schema.getAttributeType("1.2.6");
+    Assert.assertFalse(type.isCollective());
+    type = schema.getAttributeType("1.2.5");
+    Assert.assertFalse(type.isCollective());
+  }
+
+
+
+  /**
+   * Check that the {@link AttributeType#isNoUserModification()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testIsNoUserModification() throws Exception
+  {
+    AttributeType type = schema.getAttributeType("1.2.5");
+    Assert.assertTrue(type.isNoUserModification());
+    type = schema.getAttributeType("1.2.6");
+    Assert.assertTrue(type.isNoUserModification());
+    type = schema.getAttributeType("1.2.3");
+    Assert.assertFalse(type.isNoUserModification());
+    type = schema.getAttributeType("1.2.4");
+    Assert.assertFalse(type.isNoUserModification());
+  }
+
+
+
+  /**
+   * Check that the {@link CommonSchemaElements#isObsolete()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public final void testIsObsolete() throws Exception
+  {
+    AttributeType d = schema.getAttributeType("1.2.3");
+    Assert.assertFalse(d.isObsolete());
+    d = schema.getAttributeType("1.2.4");
+    Assert.assertFalse(d.isObsolete());
+
+    d = schema.getAttributeType("1.2.1");
+    Assert.assertTrue(d.isObsolete());
+    d = schema.getAttributeType("1.2.2");
+    Assert.assertTrue(d.isObsolete());
+  }
+
+
+
+  /**
+   * Check that the {@link AttributeType#isSingleValue()} method.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testIsSingleValue() throws Exception
+  {
+    AttributeType type = schema.getAttributeType("1.2.1");
+    Assert.assertTrue(type.isSingleValue());
+    type = schema.getAttributeType("1.2.2");
+    Assert.assertTrue(type.isSingleValue());
+    type = schema.getAttributeType("1.2.5");
+    Assert.assertFalse(type.isSingleValue());
+    type = schema.getAttributeType("1.2.6");
+    Assert.assertFalse(type.isSingleValue());
+  }
+
+
+
+  /**
+   * Check that the simple constructor throws an NPE when mandatory parameters
+   * are not specified.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void testNoSupNorSyntax1() throws Exception
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addAttributeType("1.2.1", EMPTY_NAMES, "", true, null, null, null,
+        null, null, null, false, false, false, AttributeUsage.DSA_OPERATION,
+        EMPTY_PROPS, false);
+    builder.addAttributeType(
+        "( 1.2.2 OBSOLETE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )",
+        false);
+  }
+
+
+
+  /**
+   * Check that the simple constructor throws an NPE when mandatory parameters
+   * are not specified.
+   *
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void testNoSupNorSyntax2() throws Exception
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addAttributeType("( 1.2.2 OBSOLETE SINGLE-VALUE )", false);
+  }
+
+
+
+  @Test
+  public void testNoUserModNonOperational() throws Exception
+  {
+    // NO-USER-MODIFICATION can't have non-operational usage
+    final SchemaBuilder builder = new SchemaBuilder(schema);
+    builder.addAttributeType(
+        "(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE "
+            + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+            + " SUBSTR caseIgnoreSubstringsMatch"
+            + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+            + " NO-USER-MODIFICATION USAGE userApplications )", false);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  protected SchemaElement getElement(final String description,
+      final Map<String, List<String>> extraProperties) throws SchemaException
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addAttributeType("1.2.3", Collections.singletonList("testType"),
+        description, false, null, null, null, null, null,
+        "1.3.6.1.4.1.1466.115.121.1.27", false, false, false,
+        AttributeUsage.DSA_OPERATION, extraProperties, false);
+    return builder.toSchema().getAttributeType("1.2.3");
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleTest.java
new file mode 100644
index 0000000..0c6df99
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringEqualityMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_BIT_STRING_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the BitStringEqualityMatchingRule.
+ */
+public class BitStringEqualityMatchingRuleTest extends MatchingRuleTest
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "\'a\'B" }, { "0" }, { "010101" }, { "\'10101" },
+        { "\'1010\'A" }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] { { "\'0\'B", "\'0\'B", ConditionResult.TRUE },
+        { "\'1\'B", "\'1\'B", ConditionResult.TRUE },
+        { "\'0\'B", "\'1\'B", ConditionResult.FALSE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_BIT_STRING_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringSyntaxTest.java
new file mode 100644
index 0000000..9c3bcf3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BitStringSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_BIT_STRING_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Bit string syntax tests.
+ */
+public class BitStringSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "'0101'B", true }, { "'1'B", true },
+        { "'0'B", true }, { "invalid", false }, { "1", false },
+        { "'010100000111111010101000'B", true }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_BIT_STRING_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleTest.java
new file mode 100644
index 0000000..0a5c047
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/BooleanEqualityMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_BOOLEAN_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the BooleanEqualityMatchingRule.
+ */
+public class BooleanEqualityMatchingRuleTest extends MatchingRuleTest
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "garbage" }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] { { "TRUE", "true", ConditionResult.TRUE },
+        { "YES", "true", ConditionResult.TRUE },
+        { "ON", "true", ConditionResult.TRUE },
+        { "1", "true", ConditionResult.TRUE },
+        { "FALSE", "false", ConditionResult.TRUE },
+        { "NO", "false", ConditionResult.TRUE },
+        { "OFF", "false", ConditionResult.TRUE },
+        { "0", "false", ConditionResult.TRUE },
+        { "TRUE", "false", ConditionResult.FALSE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_BOOLEAN_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleTest.java
new file mode 100644
index 0000000..25872cb
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactEqualityMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_EXACT_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseExactEqualityMatchingRule.
+ */
+public class CaseExactEqualityMatchingRuleTest extends MatchingRuleTest
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] { { "12345678", "12345678", ConditionResult.TRUE },
+        { "12345678\u2163", "12345678\u2163", ConditionResult.TRUE },
+        { "ABC45678", "ABC45678", ConditionResult.TRUE },
+        { "  ABC45678  ", "ABC45678", ConditionResult.TRUE },
+        { "ABC   45678", "ABC 45678", ConditionResult.TRUE },
+        { "   ", " ", ConditionResult.TRUE }, { "", "", ConditionResult.TRUE },
+        { "ABC45678", "abc45678", ConditionResult.FALSE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_CASE_EXACT_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleTest.java
new file mode 100644
index 0000000..d83123d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5EqualityMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_EXACT_IA5_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseExactIA5EqualityMatchingRule.
+ */
+public class CaseExactIA5EqualityMatchingRuleTest extends MatchingRuleTest
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "12345678\uFFFD" }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] { { "12345678", "12345678", ConditionResult.TRUE },
+        { "ABC45678", "ABC45678", ConditionResult.TRUE },
+        { "ABC45678", "abc45678", ConditionResult.FALSE },
+        { "\u0020foo\u0020bar\u0020\u0020", "foo bar", ConditionResult.TRUE },
+        { "test\u00AD\u200D", "test", ConditionResult.TRUE },
+        { "foo\u000Bbar", "foo\u0020bar", ConditionResult.TRUE },
+        { "foo\u070Fbar", "foobar", ConditionResult.TRUE },
+
+    };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_CASE_EXACT_IA5_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleTest.java
new file mode 100644
index 0000000..72a5cb5
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactIA5SubstringMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_EXACT_IA5_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseExactIA5SubstringMatchingRule.
+ */
+public class CaseExactIA5SubstringMatchingRuleTest extends
+    SubstringMatchingRuleTest
+{
+
+  @Override
+  @DataProvider(name = "substringInvalidAssertionValues")
+  public Object[][] createMatchingRuleInvalidAssertionValues()
+  {
+    return new Object[][] { { "12345678\uFFFD", new String[0], null },
+        { null, new String[] { "12345678\uFFFD" }, null },
+        { null, new String[0], "12345678\uFFFD" }, };
+  }
+
+
+
+  @Override
+  @DataProvider(name = "substringInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "12345678\uFFFD" }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringFinalMatchData")
+  public Object[][] createSubstringFinalMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "value", ConditionResult.TRUE },
+        { "this is a value", "alue", ConditionResult.TRUE },
+        { "this is a value", "ue", ConditionResult.TRUE },
+        { "this is a value", "e", ConditionResult.TRUE },
+        { "this is a value", "valu", ConditionResult.FALSE },
+        { "this is a value", "this", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a value", "VALUE", ConditionResult.FALSE },
+        { "this is a VALUE", "value", ConditionResult.FALSE },
+        { "end with space    ", " ", ConditionResult.FALSE },
+        { "end with space    ", "space", ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringInitialMatchData")
+  public Object[][] createSubstringInitialMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "this", ConditionResult.TRUE },
+        { "this is a value", "th", ConditionResult.TRUE },
+        { "this is a value", "t", ConditionResult.TRUE },
+        { "this is a value", "is", ConditionResult.FALSE },
+        { "this is a value", "a", ConditionResult.FALSE },
+        { "this is a value", "value", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a value", "NOT", ConditionResult.FALSE },
+        { "this is a value", "THIS", ConditionResult.FALSE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringMiddleMatchData")
+  public Object[][] createSubstringMiddleMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", new String[] { "this" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "is" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "a" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "value" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { " " }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "this", "is", "a", "value" },
+            ConditionResult.TRUE },
+        // The matching rule requires ordered non overlapping substrings
+        // Issue #730 was not valid.
+        { "this is a value", new String[] { "value", "this" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "this is" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "his is", "a val", },
+            ConditionResult.TRUE },
+        { "this is a value", new String[] { "not", }, ConditionResult.FALSE },
+        { "this is a value", new String[] { "THIS", }, ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "not" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "    " }, ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(SMR_CASE_EXACT_IA5_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleTest.java
new file mode 100644
index 0000000..e119462
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactOrderingMatchingRuleTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.OMR_CASE_EXACT_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseExactOrderingMatchingRule.
+ */
+public class CaseExactOrderingMatchingRuleTest extends OrderingMatchingRuleTest
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "OrderingMatchingRuleInvalidValues")
+  public Object[][] createOrderingMatchingRuleInvalidValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "Orderingmatchingrules")
+  public Object[][] createOrderingMatchingRuleTestData()
+  {
+    return new Object[][] { { "12345678", "02345678", 1 },
+        { "abcdef", "bcdefa", -1 }, { "abcdef", "abcdef", 0 }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(OMR_CASE_EXACT_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleTest.java
new file mode 100644
index 0000000..70bf2f7
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseExactSubstringMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_EXACT_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseExactSubstringMatchingRule class.
+ */
+public class CaseExactSubstringMatchingRuleTest extends
+    SubstringMatchingRuleTest
+{
+
+  @Override
+  @DataProvider(name = "substringInvalidAssertionValues")
+  public Object[][] createMatchingRuleInvalidAssertionValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  @Override
+  @DataProvider(name = "substringInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringFinalMatchData")
+  public Object[][] createSubstringFinalMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "value", ConditionResult.TRUE },
+        { "this is a value", "alue", ConditionResult.TRUE },
+        { "this is a value", "ue", ConditionResult.TRUE },
+        { "this is a value", "e", ConditionResult.TRUE },
+        { "this is a value", "valu", ConditionResult.FALSE },
+        { "this is a value", "this", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a value", "VALUE", ConditionResult.FALSE },
+        { "this is a VALUE", "value", ConditionResult.FALSE },
+        { "end with space    ", " ", ConditionResult.FALSE },
+        { "end with space    ", "space", ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringInitialMatchData")
+  public Object[][] createSubstringInitialMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "this", ConditionResult.TRUE },
+        { "this is a value", "th", ConditionResult.TRUE },
+        { "this is a value", "t", ConditionResult.TRUE },
+        { "this is a value", "is", ConditionResult.FALSE },
+        { "this is a value", "a", ConditionResult.FALSE },
+        { "this is a value", "value", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a value", "NOT", ConditionResult.FALSE },
+        { "this is a value", "THIS", ConditionResult.FALSE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringMiddleMatchData")
+  public Object[][] createSubstringMiddleMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", new String[] { "this" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "is" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "a" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "value" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { " " }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "this", "is", "a", "value" },
+            ConditionResult.TRUE },
+        // The matching rule requires ordered non overlapping
+        // substrings.
+        // Issue #730 was not valid.
+        { "this is a value", new String[] { "value", "this" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "this is" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "his is", "a val", },
+            ConditionResult.TRUE },
+        { "this is a value", new String[] { "not", }, ConditionResult.FALSE },
+        { "this is a value", new String[] { "THIS", }, ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "not" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "    " }, ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(SMR_CASE_EXACT_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleTest.java
new file mode 100644
index 0000000..322b711
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreEqualityMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseIgnoreEqualityMatchingRule.
+ */
+public class CaseIgnoreEqualityMatchingRuleTest extends MatchingRuleTest
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] {
+        { " string ", "string", ConditionResult.TRUE },
+        { "string ", "string", ConditionResult.TRUE },
+        { " string", "string", ConditionResult.TRUE },
+        { "    ", " ", ConditionResult.TRUE },
+        { "Z", "z", ConditionResult.TRUE },
+        { "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
+            "abcdefghijklmnopqrstuvwxyz1234567890", ConditionResult.TRUE },
+        { "foo\u0020bar\u0020\u0020", "foo bar", ConditionResult.TRUE },
+        { "test\u00AD\u200D", "test", ConditionResult.TRUE },
+        { "foo\u070Fbar", "foobar", ConditionResult.TRUE },
+        // Case-folding data below.
+        { "foo\u0149bar", "foo\u02BC\u006Ebar", ConditionResult.TRUE },
+        { "foo\u017Bbar", "foo\u017Cbar", ConditionResult.TRUE },
+
+    };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_CASE_IGNORE_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleTest.java
new file mode 100644
index 0000000..d5f298f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5EqualityMatchingRuleTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.EMR_CASE_IGNORE_IA5_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseExactIA5EqualityMatchingRule.
+ */
+public class CaseIgnoreIA5EqualityMatchingRuleTest extends MatchingRuleTest
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "12345678\uFFFD" }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] { { "12345678", "12345678", ConditionResult.TRUE },
+        { "ABC45678", "ABC45678", ConditionResult.TRUE },
+        { "ABC45678", "abc45678", ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_CASE_IGNORE_IA5_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleTest.java
new file mode 100644
index 0000000..5757c14
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreIA5SubstringMatchingRuleTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_IA5_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseIgnoreIA5SubstringMatchingRule.
+ */
+public class CaseIgnoreIA5SubstringMatchingRuleTest extends
+    SubstringMatchingRuleTest
+{
+
+  @DataProvider(name = "substringInvalidAssertionValues")
+  public Object[][] createMatchingRuleInvalidAssertionValues()
+  {
+    return new Object[][] { { "12345678\uFFFD", new String[0], null },
+        { null, new String[] { "12345678\uFFFD" }, null },
+        { null, new String[0], "12345678\uFFFD" }, };
+  }
+
+
+
+  @DataProvider(name = "substringInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "12345678\uFFFD" }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringFinalMatchData")
+  public Object[][] createSubstringFinalMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "value", ConditionResult.TRUE },
+        { "this is a value", "alue", ConditionResult.TRUE },
+        { "this is a value", "ue", ConditionResult.TRUE },
+        { "this is a value", "e", ConditionResult.TRUE },
+        { "this is a value", "valu", ConditionResult.FALSE },
+        { "this is a value", "this", ConditionResult.FALSE },
+        { "this is a value", "VALUE", ConditionResult.TRUE },
+        { "this is a value", "AlUe", ConditionResult.TRUE },
+        { "this is a value", "UE", ConditionResult.TRUE },
+        { "this is a value", "E", ConditionResult.TRUE },
+        { "this is a value", "valu", ConditionResult.FALSE },
+        { "this is a value", "THIS", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a VALUE", "value", ConditionResult.TRUE },
+        { "end with space    ", " ", ConditionResult.FALSE },
+        { "end with space    ", "space", ConditionResult.TRUE },
+        { "end with space    ", "SPACE", ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringInitialMatchData")
+  public Object[][] createSubstringInitialMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "this", ConditionResult.TRUE },
+        { "this is a value", "th", ConditionResult.TRUE },
+        { "this is a value", "t", ConditionResult.TRUE },
+        { "this is a value", "is", ConditionResult.FALSE },
+        { "this is a value", "a", ConditionResult.FALSE },
+        { "this is a value", "TH", ConditionResult.TRUE },
+        { "this is a value", "T", ConditionResult.TRUE },
+        { "this is a value", "IS", ConditionResult.FALSE },
+        { "this is a value", "A", ConditionResult.FALSE },
+        { "this is a value", "VALUE", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a value", "NOT", ConditionResult.FALSE },
+        { "this is a value", "THIS", ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringMiddleMatchData")
+  public Object[][] createSubstringMiddleMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", new String[] { "this" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "is" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "a" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "value" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "THIS" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "IS" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "A" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "VALUE" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { " " }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "this", "is", "a", "value" },
+            ConditionResult.TRUE },
+        // The matching rule requires ordered non overlapping
+        // substrings.
+        // Issue #730 was not valid.
+        { "this is a value", new String[] { "value", "this" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "this is" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "IS", "a", "VALue" },
+            ConditionResult.TRUE },
+        { "this is a value", new String[] { "his IS", "A val", },
+            ConditionResult.TRUE },
+        { "this is a value", new String[] { "not", }, ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "not" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "    " }, ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(SMR_CASE_IGNORE_IA5_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleTest.java
new file mode 100644
index 0000000..e9ef68e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreOrderingMatchingRuleTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.OMR_CASE_IGNORE_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseIgnoreOrderingMatchingRule.
+ */
+public class CaseIgnoreOrderingMatchingRuleTest extends
+    OrderingMatchingRuleTest
+{
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "OrderingMatchingRuleInvalidValues")
+  public Object[][] createOrderingMatchingRuleInvalidValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "Orderingmatchingrules")
+  public Object[][] createOrderingMatchingRuleTestData()
+  {
+    return new Object[][] { { "12345678", "02345678", 1 },
+        { "abcdef", "bcdefa", -1 }, { "abcdef", "abcdef", 0 },
+        { "abcdef", "ABCDEF", 0 }, { "abcdef", "aCcdef", -1 },
+        { "aCcdef", "abcdef", 1 },
+        { "foo\u0020bar\u0020\u0020", "foo bar", 0 },
+        { "test\u00AD\u200D", "test", 0 },
+        { "foo\u070Fbar", "foobar", 0 },
+        // Case-folding data below.
+        { "foo\u0149bar", "foo\u02BC\u006Ebar", 0 },
+        { "foo\u017Bbar", "foo\u017Cbar", 0 },
+        { "foo\u017Bbar", "goo\u017Cbar", -1 },
+        // issue# 3583
+        { "a", "\u00f8", -1 }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(OMR_CASE_IGNORE_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleTest.java
new file mode 100644
index 0000000..257a1b8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CaseIgnoreSubstringMatchingRuleTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SMR_CASE_IGNORE_OID;
+
+import org.opends.sdk.ConditionResult;
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Test the CaseIgnoreSubstringMatchingRule.
+ */
+public class CaseIgnoreSubstringMatchingRuleTest extends
+    SubstringMatchingRuleTest
+{
+
+  @DataProvider(name = "substringInvalidAssertionValues")
+  public Object[][] createMatchingRuleInvalidAssertionValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  @DataProvider(name = "substringInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] {};
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringFinalMatchData")
+  public Object[][] createSubstringFinalMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "value", ConditionResult.TRUE },
+        { "this is a value", "alue", ConditionResult.TRUE },
+        { "this is a value", "ue", ConditionResult.TRUE },
+        { "this is a value", "e", ConditionResult.TRUE },
+        { "this is a value", "valu", ConditionResult.FALSE },
+        { "this is a value", "this", ConditionResult.FALSE },
+        { "this is a value", "VALUE", ConditionResult.TRUE },
+        { "this is a value", "AlUe", ConditionResult.TRUE },
+        { "this is a value", "UE", ConditionResult.TRUE },
+        { "this is a value", "E", ConditionResult.TRUE },
+        { "this is a value", "valu", ConditionResult.FALSE },
+        { "this is a value", "THIS", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a VALUE", "value", ConditionResult.TRUE },
+        { "end with space    ", " ", ConditionResult.FALSE },
+        { "end with space    ", "space", ConditionResult.TRUE },
+        { "end with space    ", "SPACE", ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringInitialMatchData")
+  public Object[][] createSubstringInitialMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", "this", ConditionResult.TRUE },
+        { "this is a value", "th", ConditionResult.TRUE },
+        { "this is a value", "t", ConditionResult.TRUE },
+        { "this is a value", "is", ConditionResult.FALSE },
+        { "this is a value", "a", ConditionResult.FALSE },
+        { "this is a value", "TH", ConditionResult.TRUE },
+        { "this is a value", "T", ConditionResult.TRUE },
+        { "this is a value", "IS", ConditionResult.FALSE },
+        { "this is a value", "A", ConditionResult.FALSE },
+        { "this is a value", "VALUE", ConditionResult.FALSE },
+        { "this is a value", " ", ConditionResult.FALSE },
+        { "this is a value", "NOT", ConditionResult.FALSE },
+        { "this is a value", "THIS", ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "substringMiddleMatchData")
+  public Object[][] createSubstringMiddleMatchData()
+  {
+    return new Object[][] {
+        { "this is a value", new String[] { "this" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "is" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "a" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "value" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "THIS" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "IS" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "A" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "VALUE" }, ConditionResult.TRUE },
+        { "this is a value", new String[] { " " }, ConditionResult.TRUE },
+        { "this is a value", new String[] { "this", "is", "a", "value" },
+            ConditionResult.TRUE },
+        // The matching rule requires ordered non overlapping
+        // substrings.
+        // Issue #730 was not valid.
+        { "this is a value", new String[] { "value", "this" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "this is" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "IS", "a", "VALue" },
+            ConditionResult.TRUE },
+        { "this is a value", new String[] { "his IS", "A val", },
+            ConditionResult.TRUE },
+        { "this is a value", new String[] { "not", }, ConditionResult.FALSE },
+        { "this is a value", new String[] { "this", "not" },
+            ConditionResult.FALSE },
+        { "this is a value", new String[] { "    " }, ConditionResult.TRUE }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(SMR_CASE_IGNORE_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CoreSchemaTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CoreSchemaTest.java
new file mode 100644
index 0000000..12720b8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/CoreSchemaTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Core schema tests
+ */
+public class CoreSchemaTest extends SchemaTestCase
+{
+  @Test
+  public final void testCoreSchemaWarnings()
+  {
+    // Make sure core schema doesn't have any warnings.
+    Assert.assertTrue(Schema.getCoreSchema().getWarnings().isEmpty());
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DITContentRuleSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DITContentRuleSyntaxTest.java
new file mode 100644
index 0000000..72fe3e3
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DITContentRuleSyntaxTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_DIT_CONTENT_RULE_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * DIT content rule syntax tests.
+ */
+public class DITContentRuleSyntaxTest extends SyntaxTestCase
+{
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] {
+        {
+            "( 2.5.6.4 DESC 'content rule for organization' NOT "
+                + "( x121Address $ telexNumber ) )", true },
+        {
+            "( 2.5.6.4 NAME 'full rule' DESC 'rule with all possible fields' "
+                + " OBSOLETE" + " AUX ( posixAccount )" + " MUST ( cn $ sn )"
+                + " MAY ( dc )" + " NOT ( x121Address $ telexNumber ) )", true },
+        {
+            "( 2.5.6.4 NAME 'full rule' DESC 'ommit parenthesis' "
+                + " OBSOLETE" + " AUX posixAccount " + " MUST cn " + " MAY dc "
+                + " NOT x121Address )", true },
+        {
+            "( 2.5.6.4 NAME 'full rule' DESC 'use numeric OIDs' " + " OBSOLETE"
+                + " AUX 1.3.6.1.1.1.2.0" + " MUST cn " + " MAY dc "
+                + " NOT x121Address )", true },
+        {
+            "( 2.5.6.4 NAME 'full rule' DESC 'illegal OIDs' " + " OBSOLETE"
+                + " AUX 2.5.6.." + " MUST cn " + " MAY dc "
+                + " NOT x121Address )", false },
+        {
+            "( 2.5.6.4 NAME 'full rule' DESC 'illegal OIDs' " + " OBSOLETE"
+                + " AUX 2.5.6.x" + " MUST cn " + " MAY dc "
+                + " NOT x121Address )", false },
+        {
+            "( 2.5.6.4 NAME 'full rule' DESC 'missing closing parenthesis' "
+                + " OBSOLETE" + " AUX posixAccount" + " MUST cn " + " MAY dc "
+                + " NOT x121Address", false },
+        {
+            "( 2.5.6.4 NAME 'full rule' DESC 'extra parameterss' "
+                + " MUST cn " + " X-name ( 'this is an extra parameter' ) )",
+            true },
+
+    };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_DIT_CONTENT_RULE_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java
new file mode 100644
index 0000000..e2717fc
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+import java.text.Normalizer;
+import java.text.Normalizer.Form;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.ByteString;
+import static org.opends.sdk.schema.SchemaConstants.EMR_DN_OID;
+
+/**
+ * Test the DistinguishedNameEqualityMatchingRule
+ */
+public class DistinguishedNameEqualityMatchingRuleTest extends MatchingRuleTest
+{
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "manager" }, { "manager " }, { "=Jim" },
+        { " =Jim" }, { "= Jim" },
+        { " = Jim" },
+        { "cn+Jim" },
+        { "cn + Jim" },
+        { "cn=Jim+" },
+        { "cn=Jim+manager" },
+        { "cn=Jim+manager " },
+        { "cn=Jim+manager," },// { "cn=Jim," }, { "cn=Jim,  " }, { "c[n]=Jim" },
+        { "_cn=Jim" }, { "c_n=Jim" }, { "cn\"=Jim" }, { "c\"n=Jim" },
+        { "1cn=Jim" }, { "cn+uid=Jim" }, { "-cn=Jim" }, { "/tmp=a" },
+        { "\\tmp=a" }, { "cn;lang-en=Jim" }, { "@cn=Jim" },
+        { "_name_=Jim" },
+        { "\u03c0=pi" },
+        { "v1.0=buggy" },// { "1.=buggy" }, { ".1=buggy" },
+        { "oid.1." }, { "1.3.6.1.4.1.1466..0=#04024869" }, { "cn=#a" },
+        { "cn=#ag" }, { "cn=#ga" }, { "cn=#abcdefgh" },
+        { "cn=a\\b" }, // { "cn=a\\bg" }, { "cn=\"hello" },
+        { "cn=+mail=,dc=example,dc=com" }, { "cn=xyz+sn=,dc=example,dc=com" },
+        { "cn=,dc=example,dc=com" } };
+  }
+
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] {
+        { "", "", ConditionResult.TRUE },
+        { "   ", "", ConditionResult.TRUE },
+        { "cn=", "cn=", ConditionResult.TRUE },
+        { "cn= ", "cn=", ConditionResult.TRUE },
+        { "cn =", "cn=", ConditionResult.TRUE },
+        { "cn = ", "cn=", ConditionResult.TRUE },
+        { "dc=com", "dc=com", ConditionResult.TRUE },
+        { "dc=com+o=com", "dc=com+o=com", ConditionResult.TRUE },
+        { "DC=COM", "dc=com", ConditionResult.TRUE },
+        { "dc = com", "dc=com", ConditionResult.TRUE },
+        { " dc = com ", "dc=com", ConditionResult.TRUE },
+        { "dc=example,dc=com", "dc=example,dc=com", ConditionResult.TRUE },
+        { "dc=example, dc=com", "dc=example,dc=com", ConditionResult.TRUE },
+        { "dc=example ,dc=com", "dc=example,dc=com", ConditionResult.TRUE },
+        { "dc =example , dc  =   com", "dc=example,dc=com",
+          ConditionResult.TRUE },
+        { "givenName=John+cn=Doe,ou=People,dc=example,dc=com",
+            "cn=doe+givenname=john,ou=people,dc=example,dc=com",
+            ConditionResult.TRUE },
+        { "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com",
+            "givenname=john\\+cn\\=doe,ou=people,dc=example,dc=com",
+            ConditionResult.TRUE },
+        { "cn=Doe\\, John,ou=People,dc=example,dc=com",
+            "cn=doe\\, john,ou=people,dc=example,dc=com", ConditionResult.TRUE },
+        { "UID=jsmith,DC=example,DC=net", "uid=jsmith,dc=example,dc=net",
+          ConditionResult.TRUE },
+        { "OU=Sales+CN=J. Smith,DC=example,DC=net",
+            "cn=j. smith+ou=sales,dc=example,dc=net", ConditionResult.TRUE },
+        { "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net",
+            "cn=james \\\"jim\\\" smith\\, iii,dc=example,dc=net",
+            ConditionResult.TRUE },
+        { "CN=John Smith\\2C III,DC=example,DC=net",
+            "cn=john smith\\, iii,dc=example,dc=net", ConditionResult.TRUE },
+        { "CN=\\23John Smith\\20,DC=example,DC=net",
+            "cn=\\#john smith,dc=example,dc=net", ConditionResult.TRUE },
+        {
+            "CN=Before\\0dAfter,DC=example,DC=net",
+            // \0d is a hex representation of Carriage return. It is mapped
+            // to a SPACE as defined in the MAP ( RFC 4518)
+            "cn=before after,dc=example,dc=net", ConditionResult.TRUE },
+        { "2.5.4.3=#04024869",
+        // Unicode codepoints from 0000-0008 are mapped to nothing.
+            "cn=hi", ConditionResult.TRUE },
+        { "1.1.1=", "1.1.1=", ConditionResult.TRUE },
+        { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107",
+          ConditionResult.TRUE },
+        { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius",
+            "ou=\u55b6\u696d\u90e8,o=airius", ConditionResult.TRUE },
+        { "photo=\\ john \\ ,dc=com", "photo=\\ john \\ ,dc=com",
+          ConditionResult.TRUE },
+        { "AB-global=", "ab-global=", ConditionResult.TRUE },
+        { "OU= Sales + CN = J. Smith ,DC=example,DC=net",
+            "cn=j. smith+ou=sales,dc=example,dc=net", ConditionResult.TRUE },
+        { "cn=John+a=Doe", "a=Doe+cn=john", ConditionResult.TRUE },
+        { "O=\"Sue, Grabbit and Runn\",C=US", "o=sue\\, grabbit and runn,c=us",
+          ConditionResult.TRUE }, };
+  }
+
+   /**
+   * DN test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "testDNs")
+  public Object[][] createData()
+  {
+    return new Object[][] {
+        { "", ""},
+        { "   ", ""},
+        { "cn=", "cn="},
+        { "cn= ", "cn="},
+        { "cn =", "cn="},
+        { "cn = ", "cn="},
+        { "dc=com", "dc=com"},
+        { "dc=com+o=com", "dc=com\u0001o=com"},
+        { "DC=COM", "dc=com"},
+        { "dc = com", "dc=com"},
+        { " dc = com ", "dc=com"},
+        { "dc=example,dc=com", "dc=com\u0000dc=example"},
+        { "dc=example, dc=com", "dc=com\u0000dc=example"},
+        { "dc=example ,dc=com", "dc=com\u0000dc=example"},
+        { "dc =example , dc  =   com", "dc=com\u0000dc=example"},
+        { "givenName=John+cn=Doe,ou=People,dc=example,dc=com",
+            "dc=com\u0000dc=example\u0000ou=people\u0000cn=doe\u0001givenname=john"},
+        { "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com",
+            "dc=com\u0000dc=example\u0000ou=people\u0000givenname=john\\+cn\\=doe"},
+        { "cn=Doe\\, John,ou=People,dc=example,dc=com",
+            "dc=com\u0000dc=example\u0000ou=people\u0000cn=doe\\, john"},
+        { "UID=jsmith,DC=example,DC=net", "dc=net\u0000dc=example\u0000uid=jsmith"},
+        { "OU=Sales+CN=J. Smith,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=j. smith\u0001ou=sales"},
+        { "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=james \\\"jim\\\" smith\\, iii"},
+        { "CN=John Smith\\2C III,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=john smith\\, iii"},
+        { "CN=\\23John Smith\\20,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=\\#john smith"},
+        {
+            "CN=Before\\0dAfter,DC=example,DC=net",
+            // \0d is a hex representation of Carriage return. It is mapped
+            // to a SPACE as defined in the MAP ( RFC 4518)
+            "dc=net\u0000dc=example\u0000cn=before after"},
+        { "2.5.4.3=#04024869",
+        // Unicode codepoints from 0000-0008 are mapped to nothing.
+            "cn=hi"},
+        { "1.1.1=", "1.1.1="},
+        { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107"},
+        { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius",
+            "o=airius\u0000ou=\u55b6\u696d\u90e8"},
+        { "photo=\\ john \\ ,dc=com", "dc=com\u0000photo=\\ john \\ "},
+        { "AB-global=", "ab-global="},
+        { "OU= Sales + CN = J. Smith ,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=j. smith\u0001ou=sales"},
+        { "cn=John+a=", "a=\u0001cn=john"},
+        { "O=\"Sue, Grabbit and Runn\",C=US",
+          "c=us\u0000o=sue\\, grabbit and runn" }, };
+  }
+
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_DN_OID);
+  }
+
+
+  /**
+   * Test the normalized values
+   */
+  @Test(dataProvider = "testDNs")
+  public void matchingRules(final String value1, final String value2)
+      throws Exception
+  {
+    final MatchingRule rule = getRule();
+
+    final ByteString normalizedValue1 = rule.normalizeAttributeValue(ByteString
+        .valueOf(value1));
+    final ByteString expectedValue = ByteString.valueOf(Normalizer.normalize(
+        value2, Form.NFKD));
+    assertEquals(normalizedValue1, expectedValue);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/EnumSyntaxTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/EnumSyntaxTestCase.java
new file mode 100644
index 0000000..7999b6d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/EnumSyntaxTestCase.java
@@ -0,0 +1,132 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.OMR_OID_GENERIC_ENUM;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.DecodeException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Enum syntax tests.
+ */
+public class EnumSyntaxTestCase extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "arbit-day", false }, { "wednesday", true }, };
+  }
+
+
+
+  @Test
+  public void testDecode() throws SchemaException, DecodeException
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax("( 3.3.3  DESC 'Day Of The Week' "
+        + " X-ENUM  ( 'monday' 'tuesday'   'wednesday'  'thursday'  'friday' "
+        + " 'saturday' 'sunday') )", true);
+    final Schema schema = builder.toSchema();
+    final Syntax syntax = schema.getSyntax("3.3.3");
+    final MatchingRule rule = syntax.getOrderingMatchingRule();
+    Assert.assertEquals(rule.getGreaterOrEqualAssertion(
+        ByteString.valueOf("monday")).matches(
+        rule.normalizeAttributeValue(ByteString.valueOf("thursday"))),
+        ConditionResult.TRUE);
+    Assert.assertEquals(rule.getLessOrEqualAssertion(
+        ByteString.valueOf("monday")).matches(
+        rule.normalizeAttributeValue(ByteString.valueOf("thursday"))),
+        ConditionResult.FALSE);
+    Assert.assertEquals(rule.getGreaterOrEqualAssertion(
+        ByteString.valueOf("tuesday")).matches(
+        rule.normalizeAttributeValue(ByteString.valueOf("monday"))),
+        ConditionResult.FALSE);
+    Assert.assertEquals(rule.getLessOrEqualAssertion(
+        ByteString.valueOf("tuesday")).matches(
+        rule.normalizeAttributeValue(ByteString.valueOf("monday"))),
+        ConditionResult.TRUE);
+    Assert.assertEquals(rule.getGreaterOrEqualAssertion(
+        ByteString.valueOf("tuesday")).matches(
+        rule.normalizeAttributeValue(ByteString.valueOf("tuesday"))),
+        ConditionResult.TRUE);
+    Assert.assertEquals(rule.getLessOrEqualAssertion(
+        ByteString.valueOf("tuesday")).matches(
+        rule.normalizeAttributeValue(ByteString.valueOf("tuesday"))),
+        ConditionResult.TRUE);
+    Assert.assertEquals(rule.getAssertion(ByteString.valueOf("tuesday"))
+        .matches(rule.normalizeAttributeValue(ByteString.valueOf("monday"))),
+        ConditionResult.TRUE);
+    Assert.assertEquals(rule.getAssertion(ByteString.valueOf("monday"))
+        .matches(rule.normalizeAttributeValue(ByteString.valueOf("thursday"))),
+        ConditionResult.FALSE);
+    Assert.assertEquals(rule.getAssertion(ByteString.valueOf("tuesday"))
+        .matches(rule.normalizeAttributeValue(ByteString.valueOf("tuesday"))),
+        ConditionResult.FALSE);
+    Assert.assertNotNull(schema
+        .getMatchingRule(OMR_OID_GENERIC_ENUM + ".3.3.3"));
+  }
+
+
+
+  @Test
+  public void testDuplicateEnum() throws SchemaException, DecodeException
+  {
+    // This should be handled silently.
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax("( 3.3.3  DESC 'Day Of The Week' "
+        + " X-ENUM  ( 'monday' 'tuesday'   'wednesday'  'thursday'  'friday' "
+        + " 'saturday' 'monday') )", true);
+    builder.toSchema();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule() throws SchemaException, DecodeException
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addEnumerationSyntax("3.3.3", "Day Of The Week", false, "monday",
+        "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday");
+    return builder.toSchema().getSyntax("3.3.3");
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GeneralizedTimeSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GeneralizedTimeSyntaxTest.java
new file mode 100644
index 0000000..b11b2cd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GeneralizedTimeSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_GENERALIZED_TIME_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Generalized time syntax tests.
+ */
+public class GeneralizedTimeSyntaxTest extends SyntaxTestCase
+{
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "2006090613Z", true },
+        { "20060906135030+01", true }, { "200609061350Z", true },
+        { "20060906135030Z", true }, { "20061116135030Z", true },
+        { "20061126135030Z", true }, { "20061231235959Z", true },
+        { "20060906135030+0101", true }, { "20060906135030+2359", true },
+        { "20060906135030+3359", false }, { "20060906135030+2389", false },
+        { "20060906135030+2361", false }, { "20060906135030+", false },
+        { "20060906135030+0", false }, { "20060906135030+010", false },
+        { "20061200235959Z", false }, { "2006121a235959Z", false },
+        { "2006122a235959Z", false }, { "20060031235959Z", false },
+        { "20061331235959Z", false }, { "20062231235959Z", false },
+        { "20061232235959Z", false }, { "2006123123595aZ", false },
+        { "200a1231235959Z", false }, { "2006j231235959Z", false },
+        { "200612-1235959Z", false }, { "20061231#35959Z", false },
+        { "2006", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_GENERALIZED_TIME_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GuideSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GuideSyntaxTest.java
new file mode 100644
index 0000000..066a26e
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/GuideSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_GUIDE_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Guide syntax tests.
+ */
+public class GuideSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "sn$EQ|!(sn$EQ)", true }, { "!(sn$EQ)", true },
+        { "person#sn$EQ", true }, { "(sn$EQ)", true }, { "sn$EQ", true },
+        { "sn$SUBSTR", true }, { "sn$GE", true }, { "sn$LE", true },
+        { "sn$ME", false }, { "?true", true }, { "?false", true },
+        { "true|sn$GE", false }, { "sn$APPROX", true },
+        { "sn$EQ|(sn$EQ)", true }, { "sn$EQ|(sn$EQ", false },
+        { "sn$EQ|(sn$EQ)|sn$EQ", true }, { "sn$EQ|(cn$APPROX&?false)", true },
+        { "sn$EQ|(cn$APPROX&|?false)", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_GUIDE_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/IA5StringSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/IA5StringSyntaxTest.java
new file mode 100644
index 0000000..44154d8
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/IA5StringSyntaxTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_IA5_STRING_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * IA5 string syntax tests.
+ */
+public class IA5StringSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "12345678", true }, { "12345678\u2163", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_IA5_STRING_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/LDAPSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/LDAPSyntaxTest.java
new file mode 100644
index 0000000..b78b12f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/LDAPSyntaxTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_LDAP_SYNTAX_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * LDAP syntax tests.
+ */
+public class LDAPSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] {
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-9EN ('this' 'is' 'a' 'test'))", false },
+        { "( 2.5.4.3 DESC 'full syntax description' " + "(X-name 'this", false },
+        { "( 2.5.4.3 DESC 'full syntax description' " + "(X-name 'this'", false },
+        { "( 2.5.4.3 DESC 'full syntax description' " + "Y-name 'this')", false },
+        { "( 2.5.4.3 DESC 'full syntax description' " + "X-name 'this' 'is')",
+            false },
+        { "( 2.5.4.3 DESC 'full syntax description' " + "X-name )", false },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X- ('this' 'is' 'a' 'test'))", false },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-name ('this' 'is' 'a' 'test') X-name-a 'this' X-name-b ('this')",
+            false },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-name ('this' 'is' 'a' 'test') X-name-a 'this' X-name-b ('this'",
+            false },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-name ('this' 'is' 'a' 'test') X-name-a 'this' X-name-b ('this'))))",
+            false },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-name ('this' 'is' 'a' 'test') X-name-a  X-name-b ('this'))))",
+            false },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-name ('this' 'is' 'a' 'test') X-name-a  'X-name-b' ('this'))))",
+            false },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-name ('this' 'is' 'a' 'test') X-name-a 'this' X-name-b ('this'))",
+            true },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-a-_eN_- ('this' 'is' 'a' 'test'))", true },
+        { "( 2.5.4.3 DESC 'full syntax description' " + "X-name ('this'))",
+            true },
+        { "( 2.5.4.3 DESC 'full syntax description' " + "X-name 'this')", true },
+        {
+            "( 2.5.4.3 DESC 'full syntax description' "
+                + "X-name 'this' X-name-a 'test')", true },
+        { "( 2.5.4.3 DESC 'full syntax description' )", true },
+        { "   (    2.5.4.3    DESC  ' syntax description'    )", true },
+        { "( 2.5.4.3 DESC syntax description )", false },
+        { "($%^*&!@ DESC 'syntax description' )", false },
+        { "(temp-oid DESC 'syntax description' )", true },
+        { "2.5.4.3 DESC 'syntax description' )", false },
+        { "(2.5.4.3 DESC 'syntax description' ", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_LDAP_SYNTAX_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleSyntaxTest.java
new file mode 100644
index 0000000..bed7f0d
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_MATCHING_RULE_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Matching rule syntax tests.
+ */
+public class MatchingRuleSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] {
+        {
+            "( 1.2.3.4 NAME 'full matching rule' "
+                + " DESC 'description of matching rule' OBSOLETE "
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 "
+                + " X-name ( 'this is an extension' ) )", true },
+        {
+            "( 1.2.3.4 NAME 'missing closing parenthesis' "
+                + " DESC 'description of matching rule' "
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 "
+                + " X-name ( 'this is an extension' ) ", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_MATCHING_RULE_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleTest.java
new file mode 100644
index 0000000..4255e6a
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleTest.java
@@ -0,0 +1,136 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.testng.Assert.assertEquals;
+
+import org.opends.sdk.Assertion;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.DecodeException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Test The equality matching rules and the equality matching rule api.
+ */
+public abstract class MatchingRuleTest extends SchemaTestCase
+{
+  /**
+   * Generate invalid assertion values for the Matching Rule test.
+   *
+   * @return the data for the EqualityMatchingRulesInvalidValuestest.
+   */
+  @DataProvider(name = "matchingRuleInvalidAssertionValues")
+  public Object[][] createMatchingRuleInvalidAssertionValues()
+  {
+    return createMatchingRuleInvalidAttributeValues();
+  }
+
+
+
+  /**
+   * Generate invalid attribute values for the Matching Rule test.
+   *
+   * @return the data for the EqualityMatchingRulesInvalidValuestest.
+   */
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public abstract Object[][] createMatchingRuleInvalidAttributeValues();
+
+
+
+  /**
+   * Generate data for the Matching Rule test.
+   *
+   * @return the data for the equality matching rule test.
+   */
+  @DataProvider(name = "matchingrules")
+  public abstract Object[][] createMatchingRuleTest();
+
+
+
+  /**
+   * Test the normalization and the comparison of valid values.
+   */
+  @Test(dataProvider = "matchingrules")
+  public void matchingRules(final String value1, final String value2,
+      final ConditionResult result) throws Exception
+  {
+    final MatchingRule rule = getRule();
+
+    // normalize the 2 provided values and check that they are equals
+    final ByteString normalizedValue1 = rule.normalizeAttributeValue(ByteString
+        .valueOf(value1));
+    final Assertion assertion = rule.getAssertion(ByteString.valueOf(value2));
+
+    final ConditionResult liveResult = assertion.matches(normalizedValue1);
+    assertEquals(result, liveResult);
+  }
+
+
+
+  /**
+   * Test that invalid values are rejected.
+   */
+  @Test(expectedExceptions = DecodeException.class, dataProvider = "matchingRuleInvalidAssertionValues")
+  public void matchingRulesInvalidAssertionValues(final String value)
+      throws Exception
+  {
+    // Get the instance of the rule to be tested.
+    final MatchingRule rule = getRule();
+
+    rule.getAssertion(ByteString.valueOf(value));
+  }
+
+
+
+  /**
+   * Test that invalid values are rejected.
+   */
+  @Test(expectedExceptions = DecodeException.class, dataProvider = "matchingRuleInvalidAttributeValues")
+  public void matchingRulesInvalidAttributeValues(final String value)
+      throws Exception
+  {
+    // Get the instance of the rule to be tested.
+    final MatchingRule rule = getRule();
+
+    rule.normalizeAttributeValue(ByteString.valueOf(value));
+  }
+
+
+
+  /**
+   * Get an instance of the matching rule.
+   *
+   * @return An instance of the matching rule to test.
+   */
+  protected abstract MatchingRule getRule();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleUseSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleUseSyntaxTest.java
new file mode 100644
index 0000000..28038ed
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/MatchingRuleUseSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_MATCHING_RULE_USE_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Matching rule use syntax tests.
+ */
+public class MatchingRuleUseSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] {
+        {
+            "( 2.5.13.10 NAME 'full matching rule' "
+                + " DESC 'description of matching rule' OBSOLETE "
+                + " APPLIES 2.5.4.3 " + " X-name 'this is an extension' )",
+            true },
+        {
+            "( 2.5.13.10 NAME 'missing closing parenthesis' "
+                + " DESC 'description of matching rule' " + " SYNTAX 2.5.4.3 "
+                + " X-name ( 'this is an extension' ) ", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_MATCHING_RULE_USE_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OrderingMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OrderingMatchingRuleTest.java
new file mode 100644
index 0000000..cd8eba9
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OrderingMatchingRuleTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.Assertion;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.DecodeException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Ordering matching rule tests.
+ */
+public abstract class OrderingMatchingRuleTest extends SchemaTestCase
+{
+  /**
+   * Create data for the OrderingMatchingRulesInvalidValues test.
+   *
+   * @return The data for the OrderingMatchingRulesInvalidValues test.
+   */
+  @DataProvider(name = "OrderingMatchingRuleInvalidValues")
+  public abstract Object[][] createOrderingMatchingRuleInvalidValues();
+
+
+
+  /**
+   * Create data for the OrderingMatchingRules test.
+   *
+   * @return The data for the OrderingMatchingRules test.
+   */
+  @DataProvider(name = "Orderingmatchingrules")
+  public abstract Object[][] createOrderingMatchingRuleTestData();
+
+
+
+  /**
+   * Test the comparison of valid values.
+   */
+  @Test(dataProvider = "Orderingmatchingrules")
+  public void orderingMatchingRules(final String value1, final String value2,
+      final int result) throws Exception
+  {
+    // Make sure that the specified class can be instantiated as a task.
+    final MatchingRule ruleInstance = getRule();
+
+    final ByteString normalizedValue1 = ruleInstance
+        .normalizeAttributeValue(ByteString.valueOf(value1));
+    final ByteString normalizedValue2 = ruleInstance
+        .normalizeAttributeValue(ByteString.valueOf(value2));
+
+    // Test the comparator
+    final int comp = ruleInstance.comparator().compare(normalizedValue1,
+        normalizedValue2);
+    if (comp == 0)
+    {
+      Assert.assertEquals(comp, result);
+    }
+    else if (comp > 0)
+    {
+      Assert.assertTrue(result > 0);
+    }
+    else if (comp < 0)
+    {
+      Assert.assertTrue(result < 0);
+    }
+
+    Assertion a = ruleInstance.getGreaterOrEqualAssertion(ByteString
+        .valueOf(value2));
+    Assert.assertEquals(a.matches(normalizedValue1),
+        result >= 0 ? ConditionResult.TRUE : ConditionResult.FALSE);
+
+    a = ruleInstance.getLessOrEqualAssertion(ByteString.valueOf(value2));
+    Assert.assertEquals(a.matches(normalizedValue1),
+        result <= 0 ? ConditionResult.TRUE : ConditionResult.FALSE);
+
+    a = ruleInstance.getAssertion(ByteString.valueOf(value2));
+    Assert.assertEquals(a.matches(normalizedValue1),
+        result < 0 ? ConditionResult.TRUE : ConditionResult.FALSE);
+  }
+
+
+
+  /**
+   * Test that invalid values are rejected.
+   */
+  @Test(expectedExceptions = DecodeException.class, dataProvider = "OrderingMatchingRuleInvalidValues")
+  public void orderingMatchingRulesInvalidValues(final String value)
+      throws Exception
+  {
+    // Make sure that the specified class can be instantiated as a task.
+    final MatchingRule ruleInstance = getRule();
+
+    // normalize the 2 provided values
+    ruleInstance.normalizeAttributeValue(ByteString.valueOf(value));
+  }
+
+
+
+  /**
+   * Get the Ordering matching Rules that is to be tested.
+   *
+   * @return The Ordering matching Rules that is to be tested.
+   */
+  protected abstract MatchingRule getRule();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OtherMailboxSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OtherMailboxSyntaxTest.java
new file mode 100644
index 0000000..243536f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/OtherMailboxSyntaxTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_OTHER_MAILBOX_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Other mailbox syntax tests.
+ */
+public class OtherMailboxSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "MyMail$Mymailbox", true },
+        { "MyMailMymailbox", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_OTHER_MAILBOX_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/RegexSyntaxTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/RegexSyntaxTestCase.java
new file mode 100644
index 0000000..8b9cb15
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/RegexSyntaxTestCase.java
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import java.util.regex.Pattern;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Regex syntax tests.
+ */
+public class RegexSyntaxTestCase extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "invalid regex", false }, { "host:0.0.0", true }, };
+  }
+
+
+
+  @Test
+  public void testDecode()
+  {
+    // This should fail due to invalid pattern.
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax(
+        "( 1.1.1 DESC 'Host and Port in the format of HOST:PORT' "
+            + " X-PATTERN '^[a-z-A-Z]+:[0-9.]+\\d$' )", true);
+    builder.toSchema();
+  }
+
+
+
+  @Test
+  public void testInvalidPattern()
+  {
+    // This should fail due to invalid pattern.
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax(
+        "( 1.1.1 DESC 'Host and Port in the format of HOST:PORT' "
+            + " X-PATTERN '^[a-z-A-Z+:[0-@.]+\\d$' )", true);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addPatternSyntax("1.1.1",
+        "Host and Port in the format of HOST:PORT", Pattern
+            .compile("^[a-z-A-Z]+:[0-9.]+\\d$"), false);
+    return builder.toSchema().getSyntax("1.1.1");
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaTestCase.java
new file mode 100644
index 0000000..e1346bd
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaTestCase.java
@@ -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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.OpenDSTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all schema unit test should extend.
+ */
+@Test(groups = { "precommit", "schema", "sdk" }, sequential = true)
+public abstract class SchemaTestCase extends OpenDSTestCase
+{
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaUtilsTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaUtilsTest.java
new file mode 100644
index 0000000..318c098
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SchemaUtilsTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import org.opends.sdk.DecodeException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.sun.opends.sdk.util.SubstringReader;
+
+
+
+/**
+ * Test schema utilities.
+ */
+public class SchemaUtilsTest extends SchemaTestCase
+{
+
+  @DataProvider(name = "invalidOIDs")
+  public Object[][] createInvalidOIDs()
+  {
+    return new Object[][] { { "" }, { ".0" }, { "0." }, { "100." }, { ".999" },
+        { "1one" }, { "one+two+three" },
+        // AD puts quotes around OIDs - test mismatched quotes.
+        { "'0" }, { "'10" }, { "999'" }, { "0.0'" }, };
+  }
+
+
+
+  @DataProvider(name = "validOIDs")
+  public Object[][] createValidOIDs()
+  {
+    return new Object[][] {
+        // Compliant NOIDs
+        { "0.0" }, { "1.0" }, { "2.0" }, { "3.0" }, { "4.0" }, { "5.0" },
+        { "6.0" }, { "7.0" }, { "8.0" }, { "9.0" }, { "0.1" }, { "0.2" },
+        { "0.3" }, { "0.4" }, { "0.5" }, { "0.6" }, { "0.7" }, { "0.8" },
+        { "0.9" }, { "10.0" }, { "100.0" }, { "999.0" },
+        { "0.100" },
+        { "0.999" },
+        { "100.100" },
+        { "999.999" },
+        { "111.22.333.44.55555.66.777.88.999" },
+        { "a" },
+        { "a2" },
+        { "a-" },
+        { "one" },
+        { "one1" },
+        { "one-two" },
+        { "one1-two2-three3" },
+        // AD puts quotes around OIDs - not compliant but we need to
+        // handle them.
+        { "'0.0'" }, { "'10.0'" }, { "'999.0'" },
+        { "'111.22.333.44.55555.66.777.88.999'" }, { "'a'" }, { "'a2'" },
+        { "'a-'" }, { "'one'" }, { "'one1'" },
+        { "'one-two'" },
+        { "'one1-two2-three3'" },
+        // Not strictly legal, but we'll be lenient with what we accept.
+        { "0" }, { "1" }, { "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" },
+        { "8" }, { "9" }, { "00" }, { "01" }, { "01.0" }, { "0.01" },
+        { "one.two.three" }, };
+  }
+
+
+
+  @Test(dataProvider = "invalidOIDs", expectedExceptions = DecodeException.class)
+  public void testReadOIDInvalid(final String oid) throws DecodeException
+  {
+    final SubstringReader reader = new SubstringReader(oid);
+    SchemaUtils.readOID(reader);
+  }
+
+
+
+  @Test(dataProvider = "validOIDs")
+  public void testReadOIDValid(final String oid) throws DecodeException
+  {
+    String expected = oid;
+    if (oid.startsWith("'"))
+    {
+      expected = oid.substring(1, oid.length() - 1);
+    }
+
+    final SubstringReader reader = new SubstringReader(oid);
+    Assert.assertEquals(SchemaUtils.readOID(reader), expected);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstitutionSyntaxTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstitutionSyntaxTestCase.java
new file mode 100644
index 0000000..d6c3238
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstitutionSyntaxTestCase.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_IA5_STRING_OID;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Substitution syntax tests.
+ */
+public class SubstitutionSyntaxTestCase extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "12345678", true }, { "12345678\u2163", false }, };
+  }
+
+
+
+  @Test
+  public void testSelfSubstitute1()
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax("( 1.3.6.1.4.1.1466.115.121.1.15 "
+        + " DESC 'Replacing DirectorySyntax'  "
+        + " X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' )", true);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  @Test
+  public void testSelfSubstitute2()
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSubstitutionSyntax("1.3.6.1.4.1.1466.115.121.1.15",
+        "Replacing DirectorySyntax", "1.3.6.1.4.1.1466.115.121.1.15", true);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  @Test(expectedExceptions = ConflictingSchemaElementException.class)
+  public void testSubstituteCore1() throws ConflictingSchemaElementException
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax("( 1.3.6.1.4.1.1466.115.121.1.26 "
+        + " DESC 'Replacing DirectorySyntax'  " + " X-SUBST '9.9.9' )", false);
+  }
+
+
+
+  @Test
+  public void testSubstituteCore1Override()
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax("( 1.3.6.1.4.1.1466.115.121.1.26 "
+        + " DESC 'Replacing DirectorySyntax'  " + " X-SUBST '9.9.9' )", true);
+  }
+
+
+
+  @Test(expectedExceptions = ConflictingSchemaElementException.class)
+  public void testSubstituteCore2() throws ConflictingSchemaElementException
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSubstitutionSyntax("1.3.6.1.4.1.1466.115.121.1.26",
+        "Replacing DirectorySyntax", "9.9.9", false);
+  }
+
+
+
+  @Test
+  public void testSubstituteCore2Override()
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSubstitutionSyntax("1.3.6.1.4.1.1466.115.121.1.26",
+        "Replacing DirectorySyntax", "9.9.9", true);
+  }
+
+
+
+  @Test
+  public void testUndefinedSubstitute1()
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSyntax("( 1.3.6.1.4.1.1466.115.121.1.15 "
+        + " DESC 'Replacing DirectorySyntax'  " + " X-SUBST '1.1.1' )", true);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  @Test
+  public void testUndefinedSubstitute2()
+  {
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSubstitutionSyntax("1.3.6.1.4.1.1466.115.121.1.15",
+        "Replacing DirectorySyntax", "1.1.1", true);
+    Assert.assertFalse(builder.toSchema().getWarnings().isEmpty());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    // Use IA5String syntax as our substitute.
+    final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+    builder.addSubstitutionSyntax("9.9.9", "Unimplemented Syntax",
+        SYNTAX_IA5_STRING_OID, false);
+    return builder.toSchema().getSyntax("9.9.9");
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstringMatchingRuleTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstringMatchingRuleTest.java
new file mode 100644
index 0000000..f0ab7e2
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SubstringMatchingRuleTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.testng.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opends.sdk.ByteSequence;
+import org.opends.sdk.ByteString;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.DecodeException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Abstract class for building test for the substring matching rules. This class
+ * is intended to be extended by one class for each substring matching rules.
+ */
+public abstract class SubstringMatchingRuleTest extends SchemaTestCase
+{
+  /**
+   * Generate invalid assertion values for the Matching Rule test.
+   *
+   * @return the data for the EqualityMatchingRulesInvalidValuestest.
+   */
+  @DataProvider(name = "substringInvalidAssertionValues")
+  public abstract Object[][] createMatchingRuleInvalidAssertionValues();
+
+
+
+  /**
+   * Generate invalid attribute values for the Matching Rule test.
+   *
+   * @return the data for the EqualityMatchingRulesInvalidValuestest.
+   */
+  @DataProvider(name = "substringInvalidAttributeValues")
+  public abstract Object[][] createMatchingRuleInvalidAttributeValues();
+
+
+
+  /**
+   * Generate data for the test of the final string match.
+   *
+   * @return the data for the test of the final string match.
+   */
+  @DataProvider(name = "substringInitialMatchData")
+  public abstract Object[][] createSubstringFinalMatchData();
+
+
+
+  /**
+   * Generate data for the test of the initial string match.
+   *
+   * @return the data for the test of the initial string match.
+   */
+  @DataProvider(name = "substringInitialMatchData")
+  public abstract Object[][] createSubstringInitialMatchData();
+
+
+
+  /**
+   * Generate data for the test of the middle string match.
+   *
+   * @return the data for the test of the middle string match.
+   */
+  @DataProvider(name = "substringMiddleMatchData")
+  public abstract Object[][] createSubstringMiddleMatchData();
+
+
+
+  /**
+   * Test the normalization and the final substring match.
+   */
+  @Test(dataProvider = "substringFinalMatchData")
+  public void finalMatchingRules(final String value, final String finalValue,
+      final ConditionResult result) throws Exception
+  {
+    final MatchingRule rule = getRule();
+
+    // normalize the 2 provided values and check that they are equals
+    final ByteString normalizedValue = rule.normalizeAttributeValue(ByteString
+        .valueOf(value));
+
+    if (rule.getAssertion(null, null, ByteString.valueOf(finalValue)).matches(
+        normalizedValue) != result
+        || rule.getAssertion(ByteString.valueOf("*" + finalValue)).matches(
+            normalizedValue) != result)
+    {
+      fail("final substring matching rule " + rule
+          + " does not give expected result (" + result + ") for values : "
+          + value + " and " + finalValue);
+    }
+  }
+
+
+
+  /**
+   * Test the normalization and the initial substring match.
+   */
+  @Test(dataProvider = "substringInitialMatchData")
+  public void initialMatchingRules(final String value, final String initial,
+      final ConditionResult result) throws Exception
+  {
+    final MatchingRule rule = getRule();
+
+    // normalize the 2 provided values and check that they are equals
+    final ByteString normalizedValue = rule.normalizeAttributeValue(ByteString
+        .valueOf(value));
+
+    if (rule.getAssertion(ByteString.valueOf(initial), null, null).matches(
+        normalizedValue) != result
+        || rule.getAssertion(ByteString.valueOf(initial + "*")).matches(
+            normalizedValue) != result)
+    {
+      fail("initial substring matching rule " + rule
+          + " does not give expected result (" + result + ") for values : "
+          + value + " and " + initial);
+    }
+  }
+
+
+
+  /**
+   * Test that invalid values are rejected.
+   */
+  @Test(expectedExceptions = DecodeException.class, dataProvider = "substringInvalidAssertionValues")
+  public void matchingRulesInvalidAssertionValues(final String subInitial,
+      final String[] anys, final String subFinal) throws Exception
+  {
+    // Get the instance of the rule to be tested.
+    final MatchingRule rule = getRule();
+
+    final List<ByteSequence> anyList = new ArrayList<ByteSequence>(anys.length);
+    for (final String middleSub : anys)
+    {
+      anyList.add(ByteString.valueOf(middleSub));
+    }
+    rule.getAssertion(subInitial == null ? null : ByteString
+        .valueOf(subInitial), anyList, subFinal == null ? null : ByteString
+        .valueOf(subFinal));
+  }
+
+
+
+  /**
+   * Test that invalid values are rejected.
+   */
+  @Test(expectedExceptions = DecodeException.class, dataProvider = "substringInvalidAssertionValues")
+  public void matchingRulesInvalidAssertionValuesString(
+      final String subInitial, final String[] anys, final String subFinal)
+      throws Exception
+  {
+    // Get the instance of the rule to be tested.
+    final MatchingRule rule = getRule();
+
+    final StringBuilder assertionString = new StringBuilder();
+    if (subInitial != null)
+    {
+      assertionString.append(subInitial);
+    }
+    assertionString.append("*");
+    for (final String middleSub : anys)
+    {
+      assertionString.append(middleSub);
+      assertionString.append("*");
+    }
+    if (subFinal != null)
+    {
+      assertionString.append(subFinal);
+    }
+    rule.getAssertion(ByteString.valueOf(assertionString.toString()));
+  }
+
+
+
+  /**
+   * Test the normalization and the middle substring match.
+   */
+  @Test(dataProvider = "substringMiddleMatchData")
+  public void middleMatchingRules(final String value,
+      final String[] middleSubs, final ConditionResult result) throws Exception
+  {
+    final MatchingRule rule = getRule();
+
+    // normalize the 2 provided values and check that they are equals
+    final ByteString normalizedValue = rule.normalizeAttributeValue(ByteString
+        .valueOf(value));
+
+    final StringBuilder printableMiddleSubs = new StringBuilder();
+    final List<ByteSequence> middleList = new ArrayList<ByteSequence>(
+        middleSubs.length);
+    printableMiddleSubs.append("*");
+    for (final String middleSub : middleSubs)
+    {
+      printableMiddleSubs.append(middleSub);
+      printableMiddleSubs.append("*");
+      middleList.add(ByteString.valueOf(middleSub));
+    }
+
+    if (rule.getAssertion(null, middleList, null).matches(normalizedValue) != result
+        || rule.getAssertion(ByteString.valueOf(printableMiddleSubs)).matches(
+            normalizedValue) != result)
+    {
+      fail("middle substring matching rule " + rule
+          + " does not give expected result (" + result + ") for values : "
+          + value + " and " + printableMiddleSubs);
+    }
+  }
+
+
+
+  /**
+   * Test that invalid values are rejected.
+   */
+  @Test(expectedExceptions = DecodeException.class, dataProvider = "substringInvalidAttributeValues")
+  public void substringInvalidAttributeValues(final String value)
+      throws Exception
+  {
+    // Get the instance of the rule to be tested.
+    final MatchingRule rule = getRule();
+
+    rule.normalizeAttributeValue(ByteString.valueOf(value));
+  }
+
+
+
+  /**
+   * Get an instance of the matching rule.
+   *
+   * @return An instance of the matching rule to test.
+   */
+  protected abstract MatchingRule getRule();
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SyntaxTestCase.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SyntaxTestCase.java
new file mode 100644
index 0000000..a71120c
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/SyntaxTestCase.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.testng.Assert.fail;
+
+import org.opends.sdk.ByteString;
+import org.opends.sdk.DecodeException;
+import org.opends.sdk.LocalizableMessageBuilder;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Syntax tests.
+ */
+public abstract class SyntaxTestCase extends SchemaTestCase
+{
+  /**
+   * Create data for the testAcceptableValues test. This should be a table of
+   * tables with 2 elements. The first one should be the value to test, the
+   * second the expected result of the test.
+   *
+   * @return a table containing data for the testAcceptableValues Test.
+   */
+  @DataProvider(name = "acceptableValues")
+  public abstract Object[][] createAcceptableValues();
+
+
+
+  /**
+   * Test the normalization and the approximate comparison.
+   */
+  @Test(dataProvider = "acceptableValues")
+  public void testAcceptableValues(final String value, final Boolean result)
+      throws Exception
+  {
+    // Make sure that the specified class can be instantiated as a task.
+    final Syntax syntax = getRule();
+
+    final LocalizableMessageBuilder reason = new LocalizableMessageBuilder();
+    // test the valueIsAcceptable method
+    final Boolean liveResult = syntax.valueIsAcceptable(ByteString
+        .valueOf(value), reason);
+
+    if (!liveResult.equals(result))
+    {
+      fail(syntax + ".valueIsAcceptable gave bad result for " + value
+          + "reason : " + reason);
+    }
+
+    // call the getters
+    syntax.getApproximateMatchingRule();
+    syntax.getDescription();
+    syntax.getEqualityMatchingRule();
+    syntax.getOID();
+    syntax.getOrderingMatchingRule();
+    syntax.getSubstringMatchingRule();
+    syntax.hashCode();
+    syntax.isHumanReadable();
+    syntax.toString();
+  }
+
+
+
+  /**
+   * Get an instance of the attribute syntax that muste be tested.
+   *
+   * @return An instance of the attribute syntax that muste be tested.
+   */
+  protected abstract Syntax getRule() throws SchemaException, DecodeException;
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/TelexSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/TelexSyntaxTest.java
new file mode 100644
index 0000000..d86d3ba
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/TelexSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_TELEX_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * Telex syntax tests.
+ */
+public class TelexSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "123$france$456", true },
+        { "abcdefghijk$lmnopqr$stuvwxyz", true },
+        { "12345$67890$()+,-./:? ", true }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_TELEX_OID);
+  }
+
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UTCTimeSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UTCTimeSyntaxTest.java
new file mode 100644
index 0000000..d816be6
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UTCTimeSyntaxTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_UTC_TIME_OID;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Date;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * UTC time syntax tests.
+ */
+public class UTCTimeSyntaxTest extends SyntaxTestCase
+{
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] {
+        // tests for the UTC time syntax.
+        { "060906135030+01", true }, { "0609061350Z", true },
+        { "060906135030Z", true }, { "061116135030Z", true },
+        { "061126135030Z", true }, { "061231235959Z", true },
+        { "060906135030+0101", true }, { "060906135030+2359", true },
+        { "060906135060+0101", true }, { "060906135061+0101", false },
+        { "060906135030+3359", false }, { "060906135030+2389", false },
+        { "062231235959Z", false }, { "061232235959Z", false },
+        { "06123123595aZ", false }, { "0a1231235959Z", false },
+        { "06j231235959Z", false }, { "0612-1235959Z", false },
+        { "061231#35959Z", false }, { "2006", false },
+        { "062106135030+0101", false }, { "060A06135030+0101", false },
+        { "061A06135030+0101", false }, { "060936135030+0101", false },
+        { "06090A135030+0101", false }, { "06091A135030+0101", false },
+        { "060900135030+0101", false }, { "060906335030+0101", false },
+        { "0609061A5030+0101", false }, { "0609062A5030+0101", false },
+        { "060906137030+0101", false }, { "060906135A30+0101", false },
+        { "060906135", false }, { "0609061350", false },
+        { "060906135070+0101", false }, { "06090613503A+0101", false },
+        { "06090613503", false }, { "0609061350Z0", false },
+        { "0609061350+0", false }, { "0609061350+000A", false },
+        { "0609061350+A00A", false }, { "060906135030Z0", false },
+        { "060906135030+010", false }, { "060906135030+010A", false },
+        { "060906135030+0A01", false }, { "060906135030+2501", false },
+        { "060906135030+0170", false }, { "060906135030+010A", false },
+        { "060906135030+A00A", false }, { "060906135030Q", false },
+        { "060906135030+", false }, };
+  }
+
+
+
+  /**
+   * Tests the {@code createUTCTimeValue} and {@code decodeUTCTimeValue}
+   * methods.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurs.
+   */
+  @Test()
+  public void testCreateAndDecodeUTCTimeValue() throws Exception
+  {
+    final Date d = new Date();
+    final String timeValue = UTCTimeSyntaxImpl.createUTCTimeValue(d);
+    final Date decodedDate = UTCTimeSyntaxImpl.decodeUTCTimeValue(timeValue);
+
+    // UTCTime does not have support for sub-second values, so we need
+    // to make
+    // sure that the decoded value is within 1000 milliseconds.
+    assertTrue(Math.abs(d.getTime() - decodedDate.getTime()) < 1000);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_UTC_TIME_OID);
+  }
+}
diff --git a/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UUIDSyntaxTest.java b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UUIDSyntaxTest.java
new file mode 100644
index 0000000..d2d228f
--- /dev/null
+++ b/opendj3/opendj-modules/opendj-sdk/src/test/java/org/opends/sdk/schema/UUIDSyntaxTest.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
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.sdk.schema;
+
+
+
+import static org.opends.sdk.schema.SchemaConstants.SYNTAX_UUID_OID;
+
+import org.testng.annotations.DataProvider;
+
+
+
+/**
+ * UUID syntax tests.
+ */
+public class UUIDSyntaxTest extends SyntaxTestCase
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @DataProvider(name = "acceptableValues")
+  public Object[][] createAcceptableValues()
+  {
+    return new Object[][] { { "12345678-9ABC-DEF0-1234-1234567890ab", true },
+        { "12345678-9abc-def0-1234-1234567890ab", true },
+        { "12345678-9abc-def0-1234-1234567890ab", true },
+        { "12345678-9abc-def0-1234-1234567890ab", true },
+        { "02345678-9abc-def0-1234-1234567890ab", true },
+        { "12345678-9abc-def0-1234-1234567890ab", true },
+        { "12345678-9abc-def0-1234-1234567890ab", true },
+        { "02345678-9abc-def0-1234-1234567890ab", true },
+        { "G2345678-9abc-def0-1234-1234567890ab", false },
+        { "g2345678-9abc-def0-1234-1234567890ab", false },
+        { "12345678/9abc/def0/1234/1234567890ab", false },
+        { "12345678-9abc-def0-1234-1234567890a", false }, };
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Syntax getRule()
+  {
+    return Schema.getCoreSchema().getSyntax(SYNTAX_UUID_OID);
+  }
+}

--
Gitblit v1.10.0